2008-04-11 04:59:23 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
TiMidity -- Experimental MIDI to WAVE converter
|
|
|
|
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
instrum_dls.c
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include "timidity.h"
|
|
|
|
#include "doomdef.h"
|
|
|
|
#include "m_swap.h"
|
|
|
|
|
|
|
|
#define __Sound_SetError(x)
|
|
|
|
|
|
|
|
namespace Timidity
|
|
|
|
{
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
struct RIFF_Chunk
|
|
|
|
{
|
|
|
|
RIFF_Chunk()
|
|
|
|
{
|
|
|
|
memset(this, 0, sizeof(*this));
|
|
|
|
}
|
|
|
|
~RIFF_Chunk()
|
|
|
|
{
|
|
|
|
// data is not freed here because it may be owned by a parent chunk
|
|
|
|
if (child != NULL)
|
|
|
|
{
|
|
|
|
delete child;
|
|
|
|
}
|
|
|
|
if (next != NULL)
|
|
|
|
{
|
|
|
|
delete next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD magic;
|
|
|
|
DWORD length;
|
|
|
|
DWORD subtype;
|
|
|
|
BYTE *data;
|
|
|
|
RIFF_Chunk *child;
|
|
|
|
RIFF_Chunk *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
RIFF_Chunk *LoadRIFF(FILE *src);
|
|
|
|
void FreeRIFF(RIFF_Chunk *chunk);
|
|
|
|
void PrintRIFF(RIFF_Chunk *chunk, int level);
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
#define RIFF MAKE_ID('R','I','F','F')
|
|
|
|
#define LIST MAKE_ID('L','I','S','T')
|
|
|
|
|
|
|
|
static bool ChunkHasSubType(DWORD magic)
|
|
|
|
{
|
|
|
|
return (magic == RIFF || magic == LIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ChunkHasSubChunks(DWORD magic)
|
|
|
|
{
|
|
|
|
return (magic == RIFF || magic == LIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void LoadSubChunks(RIFF_Chunk *chunk, BYTE *data, DWORD left)
|
|
|
|
{
|
|
|
|
BYTE *subchunkData;
|
|
|
|
DWORD subchunkDataLen;
|
|
|
|
|
|
|
|
while ( left > 8 ) {
|
|
|
|
RIFF_Chunk *child = new RIFF_Chunk;
|
|
|
|
RIFF_Chunk *next, *prev = NULL;
|
|
|
|
for ( next = chunk->child; next; next = next->next ) {
|
|
|
|
prev = next;
|
|
|
|
}
|
|
|
|
if ( prev ) {
|
|
|
|
prev->next = child;
|
|
|
|
} else {
|
|
|
|
chunk->child = child;
|
|
|
|
}
|
|
|
|
|
|
|
|
child->magic = *(DWORD *)data;
|
|
|
|
data += 4;
|
|
|
|
left -= 4;
|
|
|
|
child->length = LittleLong(*(DWORD *)data);
|
|
|
|
data += 4;
|
|
|
|
left -= 4;
|
|
|
|
child->data = data;
|
|
|
|
|
|
|
|
if ( child->length > left ) {
|
|
|
|
child->length = left;
|
|
|
|
}
|
|
|
|
|
|
|
|
subchunkData = child->data;
|
|
|
|
subchunkDataLen = child->length;
|
|
|
|
if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) {
|
|
|
|
child->subtype = *(DWORD *)subchunkData;
|
|
|
|
subchunkData += 4;
|
|
|
|
subchunkDataLen -= 4;
|
|
|
|
}
|
|
|
|
if ( ChunkHasSubChunks(child->magic) ) {
|
|
|
|
LoadSubChunks(child, subchunkData, subchunkDataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
data += child->length + (child->length & 1);
|
|
|
|
left -= child->length + (child->length & 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RIFF_Chunk *LoadRIFF(FILE *src)
|
|
|
|
{
|
|
|
|
RIFF_Chunk *chunk;
|
|
|
|
BYTE *subchunkData;
|
|
|
|
DWORD subchunkDataLen;
|
|
|
|
|
|
|
|
/* Allocate the chunk structure */
|
|
|
|
chunk = new RIFF_Chunk;
|
|
|
|
|
|
|
|
/* Make sure the file is in RIFF format */
|
|
|
|
fread(&chunk->magic, 4, 1, src);
|
|
|
|
fread(&chunk->length, 4, 1, src);
|
|
|
|
chunk->length = LittleLong(chunk->length);
|
|
|
|
if ( chunk->magic != RIFF ) {
|
|
|
|
__Sound_SetError("Not a RIFF file");
|
|
|
|
delete chunk;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
chunk->data = (BYTE *)malloc(chunk->length);
|
|
|
|
if ( chunk->data == NULL ) {
|
|
|
|
__Sound_SetError(ERR_OUT_OF_MEMORY);
|
|
|
|
delete chunk;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ( fread(chunk->data, chunk->length, 1, src) != 1 ) {
|
|
|
|
__Sound_SetError(ERR_IO_ERROR);
|
|
|
|
FreeRIFF(chunk);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
subchunkData = chunk->data;
|
|
|
|
subchunkDataLen = chunk->length;
|
|
|
|
if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) {
|
|
|
|
chunk->subtype = *(DWORD *)subchunkData;
|
|
|
|
subchunkData += 4;
|
|
|
|
subchunkDataLen -= 4;
|
|
|
|
}
|
|
|
|
if ( ChunkHasSubChunks(chunk->magic) ) {
|
|
|
|
LoadSubChunks(chunk, subchunkData, subchunkDataLen);
|
|
|
|
}
|
|
|
|
return chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeRIFF(RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
free(chunk->data);
|
|
|
|
delete chunk;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrintRIFF(RIFF_Chunk *chunk, int level)
|
|
|
|
{
|
|
|
|
static char prefix[128];
|
|
|
|
|
|
|
|
if ( level == sizeof(prefix)-1 ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( level > 0 ) {
|
|
|
|
prefix[(level-1)*2] = ' ';
|
|
|
|
prefix[(level-1)*2+1] = ' ';
|
|
|
|
}
|
|
|
|
prefix[level*2] = '\0';
|
|
|
|
printf("%sChunk: %c%c%c%c (%d bytes)", prefix,
|
|
|
|
((chunk->magic >> 0) & 0xFF),
|
|
|
|
((chunk->magic >> 8) & 0xFF),
|
|
|
|
((chunk->magic >> 16) & 0xFF),
|
|
|
|
((chunk->magic >> 24) & 0xFF), chunk->length);
|
|
|
|
if ( chunk->subtype ) {
|
|
|
|
printf(" subtype: %c%c%c%c",
|
|
|
|
((chunk->subtype >> 0) & 0xFF),
|
|
|
|
((chunk->subtype >> 8) & 0xFF),
|
|
|
|
((chunk->subtype >> 16) & 0xFF),
|
|
|
|
((chunk->subtype >> 24) & 0xFF));
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
if ( chunk->child ) {
|
|
|
|
printf("%s{\n", prefix);
|
|
|
|
PrintRIFF(chunk->child, level + 1);
|
|
|
|
printf("%s}\n", prefix);
|
|
|
|
}
|
|
|
|
if ( chunk->next ) {
|
|
|
|
PrintRIFF(chunk->next, level);
|
|
|
|
}
|
|
|
|
if ( level > 0 ) {
|
|
|
|
prefix[(level-1)*2] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TEST_MAIN_RIFF
|
|
|
|
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for ( i = 1; i < argc; ++i ) {
|
|
|
|
RIFF_Chunk *chunk;
|
|
|
|
SDL_RWops *src = SDL_RWFromFile(argv[i], "rb");
|
|
|
|
if ( !src ) {
|
|
|
|
fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
chunk = LoadRIFF(src);
|
|
|
|
if ( chunk ) {
|
|
|
|
PrintRIFF(chunk, 0);
|
|
|
|
FreeRIFF(chunk);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError());
|
|
|
|
}
|
|
|
|
SDL_RWclose(src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TEST_MAIN
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* This code is based on the DLS spec version 1.1, available at:
|
|
|
|
http://www.midi.org/about-midi/dls/dlsspec.shtml
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Some typedefs so the public dls headers don't need to be modified */
|
|
|
|
#define FAR
|
|
|
|
typedef SWORD SHORT;
|
|
|
|
typedef WORD USHORT;
|
|
|
|
typedef SDWORD LONG;
|
|
|
|
typedef DWORD ULONG;
|
|
|
|
#define mmioFOURCC MAKE_ID
|
|
|
|
#define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M)
|
|
|
|
|
|
|
|
#include "dls1.h"
|
|
|
|
#include "dls2.h"
|
|
|
|
|
|
|
|
struct WaveFMT
|
|
|
|
{
|
|
|
|
WORD wFormatTag;
|
|
|
|
WORD wChannels;
|
|
|
|
DWORD dwSamplesPerSec;
|
|
|
|
DWORD dwAvgBytesPerSec;
|
|
|
|
WORD wBlockAlign;
|
|
|
|
WORD wBitsPerSample;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLS_Wave
|
|
|
|
{
|
|
|
|
WaveFMT *format;
|
|
|
|
BYTE *data;
|
|
|
|
DWORD length;
|
|
|
|
WSMPL *wsmp;
|
|
|
|
WLOOP *wsmp_loop;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLS_Region
|
|
|
|
{
|
|
|
|
RGNHEADER *header;
|
|
|
|
WAVELINK *wlnk;
|
|
|
|
WSMPL *wsmp;
|
|
|
|
WLOOP *wsmp_loop;
|
|
|
|
CONNECTIONLIST *art;
|
|
|
|
CONNECTION *artList;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLS_Instrument
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
INSTHEADER *header;
|
|
|
|
DLS_Region *regions;
|
|
|
|
CONNECTIONLIST *art;
|
|
|
|
CONNECTION *artList;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DLS_Data
|
|
|
|
{
|
|
|
|
RIFF_Chunk *chunk;
|
|
|
|
|
|
|
|
DWORD cInstruments;
|
|
|
|
DLS_Instrument *instruments;
|
|
|
|
|
|
|
|
POOLTABLE *ptbl;
|
|
|
|
POOLCUE *ptblList;
|
|
|
|
DLS_Wave *waveList;
|
|
|
|
|
|
|
|
const char *name;
|
|
|
|
const char *artist;
|
|
|
|
const char *copyright;
|
|
|
|
const char *comments;
|
|
|
|
};
|
|
|
|
|
|
|
|
DLS_Data *LoadDLS(FILE *src);
|
|
|
|
void FreeDLS(DLS_Data *chunk);
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#define FOURCC_LIST mmioFOURCC('L','I','S','T')
|
|
|
|
#define FOURCC_FMT mmioFOURCC('f','m','t',' ')
|
|
|
|
#define FOURCC_DATA mmioFOURCC('d','a','t','a')
|
|
|
|
#define FOURCC_INFO mmioFOURCC('I','N','F','O')
|
|
|
|
#define FOURCC_IARL mmioFOURCC('I','A','R','L')
|
|
|
|
#define FOURCC_IART mmioFOURCC('I','A','R','T')
|
|
|
|
#define FOURCC_ICMS mmioFOURCC('I','C','M','S')
|
|
|
|
#define FOURCC_ICMT mmioFOURCC('I','C','M','T')
|
|
|
|
#define FOURCC_ICOP mmioFOURCC('I','C','O','P')
|
|
|
|
#define FOURCC_ICRD mmioFOURCC('I','C','R','D')
|
|
|
|
#define FOURCC_IENG mmioFOURCC('I','E','N','G')
|
|
|
|
#define FOURCC_IGNR mmioFOURCC('I','G','N','R')
|
|
|
|
#define FOURCC_IKEY mmioFOURCC('I','K','E','Y')
|
|
|
|
#define FOURCC_IMED mmioFOURCC('I','M','E','D')
|
|
|
|
#define FOURCC_INAM mmioFOURCC('I','N','A','M')
|
|
|
|
#define FOURCC_IPRD mmioFOURCC('I','P','R','D')
|
|
|
|
#define FOURCC_ISBJ mmioFOURCC('I','S','B','J')
|
|
|
|
#define FOURCC_ISFT mmioFOURCC('I','S','F','T')
|
|
|
|
#define FOURCC_ISRC mmioFOURCC('I','S','R','C')
|
|
|
|
#define FOURCC_ISRF mmioFOURCC('I','S','R','F')
|
|
|
|
#define FOURCC_ITCH mmioFOURCC('I','T','C','H')
|
|
|
|
|
|
|
|
|
|
|
|
static void FreeRegions(DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
if ( instrument->regions ) {
|
|
|
|
free(instrument->regions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AllocRegions(DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
int datalen = (instrument->header->cRegions * sizeof(DLS_Region));
|
|
|
|
FreeRegions(instrument);
|
|
|
|
instrument->regions = (DLS_Region *)malloc(datalen);
|
|
|
|
if ( instrument->regions ) {
|
|
|
|
memset(instrument->regions, 0, datalen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FreeInstruments(DLS_Data *data)
|
|
|
|
{
|
|
|
|
if ( data->instruments ) {
|
|
|
|
DWORD i;
|
|
|
|
for ( i = 0; i < data->cInstruments; ++i ) {
|
|
|
|
FreeRegions(&data->instruments[i]);
|
|
|
|
}
|
|
|
|
free(data->instruments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AllocInstruments(DLS_Data *data)
|
|
|
|
{
|
|
|
|
int datalen = (data->cInstruments * sizeof(DLS_Instrument));
|
|
|
|
FreeInstruments(data);
|
|
|
|
data->instruments = (DLS_Instrument *)malloc(datalen);
|
|
|
|
if ( data->instruments ) {
|
|
|
|
memset(data->instruments, 0, datalen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FreeWaveList(DLS_Data *data)
|
|
|
|
{
|
|
|
|
if ( data->waveList ) {
|
|
|
|
free(data->waveList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void AllocWaveList(DLS_Data *data)
|
|
|
|
{
|
|
|
|
int datalen = (data->ptbl->cCues * sizeof(DLS_Wave));
|
|
|
|
FreeWaveList(data);
|
|
|
|
data->waveList = (DLS_Wave *)malloc(datalen);
|
|
|
|
if ( data->waveList ) {
|
|
|
|
memset(data->waveList, 0, datalen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
data->cInstruments = LittleLong(*(DWORD *)chunk->data);
|
|
|
|
AllocInstruments(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
INSTHEADER *header = (INSTHEADER *)chunk->data;
|
|
|
|
header->cRegions = LittleLong(header->cRegions);
|
|
|
|
header->Locale.ulBank = LittleLong(header->Locale.ulBank);
|
|
|
|
header->Locale.ulInstrument = LittleLong(header->Locale.ulInstrument);
|
|
|
|
instrument->header = header;
|
|
|
|
AllocRegions(instrument);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
|
|
|
|
{
|
|
|
|
RGNHEADER *header = (RGNHEADER *)chunk->data;
|
|
|
|
header->RangeKey.usLow = LittleShort(header->RangeKey.usLow);
|
|
|
|
header->RangeKey.usHigh = LittleShort(header->RangeKey.usHigh);
|
|
|
|
header->RangeVelocity.usLow = LittleShort(header->RangeVelocity.usLow);
|
|
|
|
header->RangeVelocity.usHigh = LittleShort(header->RangeVelocity.usHigh);
|
|
|
|
header->fusOptions = LittleShort(header->fusOptions);
|
|
|
|
header->usKeyGroup = LittleShort(header->usKeyGroup);
|
|
|
|
region->header = header;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
|
|
|
|
{
|
|
|
|
WAVELINK *wlnk = (WAVELINK *)chunk->data;
|
|
|
|
wlnk->fusOptions = LittleShort(wlnk->fusOptions);
|
|
|
|
wlnk->usPhaseGroup = LittleShort(wlnk->usPhaseGroup);
|
|
|
|
wlnk->ulChannel = LittleShort(wlnk->ulChannel);
|
|
|
|
wlnk->ulTableIndex = LittleShort(wlnk->ulTableIndex);
|
|
|
|
region->wlnk = wlnk;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr)
|
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
WSMPL *wsmp = (WSMPL *)chunk->data;
|
|
|
|
WLOOP *loop;
|
|
|
|
wsmp->cbSize = LittleLong(wsmp->cbSize);
|
|
|
|
wsmp->usUnityNote = LittleShort(wsmp->usUnityNote);
|
|
|
|
wsmp->sFineTune = LittleShort(wsmp->sFineTune);
|
|
|
|
wsmp->lAttenuation = LittleLong(wsmp->lAttenuation);
|
|
|
|
wsmp->fulOptions = LittleLong(wsmp->fulOptions);
|
|
|
|
wsmp->cSampleLoops = LittleLong(wsmp->cSampleLoops);
|
|
|
|
loop = (WLOOP *)((BYTE *)chunk->data + wsmp->cbSize);
|
|
|
|
*wsmp_ptr = wsmp;
|
|
|
|
*wsmp_loop_ptr = loop;
|
|
|
|
for ( i = 0; i < wsmp->cSampleLoops; ++i ) {
|
|
|
|
loop->cbSize = LittleLong(loop->cbSize);
|
|
|
|
loop->ulType = LittleLong(loop->ulType);
|
|
|
|
loop->ulStart = LittleLong(loop->ulStart);
|
|
|
|
loop->ulLength = LittleLong(loop->ulLength);
|
|
|
|
++loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr)
|
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data;
|
|
|
|
CONNECTION *artList;
|
|
|
|
art->cbSize = LittleLong(art->cbSize);
|
|
|
|
art->cConnections = LittleLong(art->cConnections);
|
|
|
|
artList = (CONNECTION *)((BYTE *)chunk->data + art->cbSize);
|
|
|
|
*art_ptr = art;
|
|
|
|
*artList_ptr = artList;
|
|
|
|
for ( i = 0; i < art->cConnections; ++i ) {
|
|
|
|
artList->usSource = LittleShort(artList->usSource);
|
|
|
|
artList->usControl = LittleShort(artList->usControl);
|
|
|
|
artList->usDestination = LittleShort(artList->usDestination);
|
|
|
|
artList->usTransform = LittleShort(artList->usTransform);
|
|
|
|
artList->lScale = LittleLong(artList->lScale);
|
|
|
|
++artList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr)
|
|
|
|
{
|
|
|
|
/* FIXME: This only supports one set of connections */
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_ART1:
|
|
|
|
case FOURCC_ART2:
|
|
|
|
Parse_art(data, chunk, conn_ptr, connList_ptr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region)
|
|
|
|
{
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_RGNH:
|
|
|
|
Parse_rgnh(data, chunk, region);
|
|
|
|
break;
|
|
|
|
case FOURCC_WLNK:
|
|
|
|
Parse_wlnk(data, chunk, region);
|
|
|
|
break;
|
|
|
|
case FOURCC_WSMP:
|
|
|
|
Parse_wsmp(data, chunk, ®ion->wsmp, ®ion->wsmp_loop);
|
|
|
|
break;
|
|
|
|
case FOURCC_LART:
|
|
|
|
case FOURCC_LAR2:
|
|
|
|
Parse_lart(data, chunk, ®ion->art, ®ion->artList);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
DWORD region = 0;
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_RGN:
|
|
|
|
case FOURCC_RGN2:
|
|
|
|
if ( region < instrument->header->cRegions ) {
|
|
|
|
Parse_rgn(data, chunk, &instrument->regions[region++]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_INAM: /* Name */
|
|
|
|
instrument->name = (const char *)chunk->data;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument)
|
|
|
|
{
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_INSH:
|
|
|
|
Parse_insh(data, chunk, instrument);
|
|
|
|
break;
|
|
|
|
case FOURCC_LRGN:
|
|
|
|
Parse_lrgn(data, chunk, instrument);
|
|
|
|
break;
|
|
|
|
case FOURCC_LART:
|
|
|
|
case FOURCC_LAR2:
|
|
|
|
Parse_lart(data, chunk, &instrument->art, &instrument->artList);
|
|
|
|
break;
|
|
|
|
case FOURCC_INFO:
|
|
|
|
Parse_INFO_INS(data, chunk, instrument);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
DWORD instrument = 0;
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_INS:
|
|
|
|
if ( instrument < data->cInstruments ) {
|
|
|
|
Parse_ins(data, chunk, &data->instruments[instrument++]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
POOLTABLE *ptbl = (POOLTABLE *)chunk->data;
|
|
|
|
ptbl->cbSize = LittleLong(ptbl->cbSize);
|
|
|
|
ptbl->cCues = LittleLong(ptbl->cCues);
|
|
|
|
data->ptbl = ptbl;
|
|
|
|
data->ptblList = (POOLCUE *)((BYTE *)chunk->data + ptbl->cbSize);
|
|
|
|
for ( i = 0; i < ptbl->cCues; ++i ) {
|
|
|
|
data->ptblList[i].ulOffset = LittleLong(data->ptblList[i].ulOffset);
|
|
|
|
}
|
|
|
|
AllocWaveList(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
|
|
|
|
{
|
|
|
|
WaveFMT *fmt = (WaveFMT *)chunk->data;
|
|
|
|
fmt->wFormatTag = LittleShort(fmt->wFormatTag);
|
|
|
|
fmt->wChannels = LittleShort(fmt->wChannels);
|
|
|
|
fmt->dwSamplesPerSec = LittleLong(fmt->dwSamplesPerSec);
|
|
|
|
fmt->dwAvgBytesPerSec = LittleLong(fmt->dwAvgBytesPerSec);
|
|
|
|
fmt->wBlockAlign = LittleShort(fmt->wBlockAlign);
|
|
|
|
fmt->wBitsPerSample = LittleShort(fmt->wBitsPerSample);
|
|
|
|
wave->format = fmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
|
|
|
|
{
|
|
|
|
wave->data = chunk->data;
|
|
|
|
wave->length = chunk->length;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave)
|
|
|
|
{
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_FMT:
|
|
|
|
Parse_fmt(data, chunk, wave);
|
|
|
|
break;
|
|
|
|
case FOURCC_DATA:
|
|
|
|
Parse_data(data, chunk, wave);
|
|
|
|
break;
|
|
|
|
case FOURCC_WSMP:
|
|
|
|
Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
DWORD wave = 0;
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_wave:
|
|
|
|
if ( wave < data->ptbl->cCues ) {
|
|
|
|
Parse_wave(data, chunk, &data->waveList[wave++]);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk)
|
|
|
|
{
|
|
|
|
for ( chunk = chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_IARL: /* Archival Location */
|
|
|
|
break;
|
|
|
|
case FOURCC_IART: /* Artist */
|
|
|
|
data->artist = (const char *)chunk->data;
|
|
|
|
break;
|
|
|
|
case FOURCC_ICMS: /* Commisioned */
|
|
|
|
break;
|
|
|
|
case FOURCC_ICMT: /* Comments */
|
|
|
|
data->comments = (const char *)chunk->data;
|
|
|
|
break;
|
|
|
|
case FOURCC_ICOP: /* Copyright */
|
|
|
|
data->copyright = (const char *)chunk->data;
|
|
|
|
break;
|
|
|
|
case FOURCC_ICRD: /* Creation Date */
|
|
|
|
break;
|
|
|
|
case FOURCC_IENG: /* Engineer */
|
|
|
|
break;
|
|
|
|
case FOURCC_IGNR: /* Genre */
|
|
|
|
break;
|
|
|
|
case FOURCC_IKEY: /* Keywords */
|
|
|
|
break;
|
|
|
|
case FOURCC_IMED: /* Medium */
|
|
|
|
break;
|
|
|
|
case FOURCC_INAM: /* Name */
|
|
|
|
data->name = (const char *)chunk->data;
|
|
|
|
break;
|
|
|
|
case FOURCC_IPRD: /* Product */
|
|
|
|
break;
|
|
|
|
case FOURCC_ISBJ: /* Subject */
|
|
|
|
break;
|
|
|
|
case FOURCC_ISFT: /* Software */
|
|
|
|
break;
|
|
|
|
case FOURCC_ISRC: /* Source */
|
|
|
|
break;
|
|
|
|
case FOURCC_ISRF: /* Source Form */
|
|
|
|
break;
|
|
|
|
case FOURCC_ITCH: /* Technician */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DLS_Data *LoadDLS(FILE *src)
|
|
|
|
{
|
|
|
|
RIFF_Chunk *chunk;
|
|
|
|
DLS_Data *data = (DLS_Data *)malloc(sizeof(*data));
|
|
|
|
if ( !data ) {
|
|
|
|
__Sound_SetError(ERR_OUT_OF_MEMORY);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(data, 0, sizeof(*data));
|
|
|
|
|
|
|
|
data->chunk = LoadRIFF(src);
|
|
|
|
if ( !data->chunk ) {
|
|
|
|
FreeDLS(data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) {
|
|
|
|
DWORD magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic;
|
|
|
|
switch(magic) {
|
|
|
|
case FOURCC_COLH:
|
|
|
|
Parse_colh(data, chunk);
|
|
|
|
break;
|
|
|
|
case FOURCC_LINS:
|
|
|
|
Parse_lins(data, chunk);
|
|
|
|
break;
|
|
|
|
case FOURCC_PTBL:
|
|
|
|
Parse_ptbl(data, chunk);
|
|
|
|
break;
|
|
|
|
case FOURCC_WVPL:
|
|
|
|
Parse_wvpl(data, chunk);
|
|
|
|
break;
|
|
|
|
case FOURCC_INFO:
|
|
|
|
Parse_INFO_DLS(data, chunk);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeDLS(DLS_Data *data)
|
|
|
|
{
|
|
|
|
if ( data->chunk ) {
|
|
|
|
FreeRIFF(data->chunk);
|
|
|
|
}
|
|
|
|
FreeInstruments(data);
|
|
|
|
FreeWaveList(data);
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *SourceToString(USHORT usSource)
|
|
|
|
{
|
|
|
|
static char unknown[32];
|
|
|
|
switch(usSource) {
|
|
|
|
case CONN_SRC_NONE:
|
|
|
|
return "NONE";
|
|
|
|
case CONN_SRC_LFO:
|
|
|
|
return "LFO";
|
|
|
|
case CONN_SRC_KEYONVELOCITY:
|
|
|
|
return "KEYONVELOCITY";
|
|
|
|
case CONN_SRC_KEYNUMBER:
|
|
|
|
return "KEYNUMBER";
|
|
|
|
case CONN_SRC_EG1:
|
|
|
|
return "EG1";
|
|
|
|
case CONN_SRC_EG2:
|
|
|
|
return "EG2";
|
|
|
|
case CONN_SRC_PITCHWHEEL:
|
|
|
|
return "PITCHWHEEL";
|
|
|
|
case CONN_SRC_CC1:
|
|
|
|
return "CC1";
|
|
|
|
case CONN_SRC_CC7:
|
|
|
|
return "CC7";
|
|
|
|
case CONN_SRC_CC10:
|
|
|
|
return "CC10";
|
|
|
|
case CONN_SRC_CC11:
|
|
|
|
return "CC11";
|
|
|
|
case CONN_SRC_POLYPRESSURE:
|
|
|
|
return "POLYPRESSURE";
|
|
|
|
case CONN_SRC_CHANNELPRESSURE:
|
|
|
|
return "CHANNELPRESSURE";
|
|
|
|
case CONN_SRC_VIBRATO:
|
|
|
|
return "VIBRATO";
|
|
|
|
case CONN_SRC_MONOPRESSURE:
|
|
|
|
return "MONOPRESSURE";
|
|
|
|
case CONN_SRC_CC91:
|
|
|
|
return "CC91";
|
|
|
|
case CONN_SRC_CC93:
|
|
|
|
return "CC93";
|
|
|
|
default:
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf(unknown, countof(unknown), "UNKNOWN (0x%04x)", usSource);
|
2008-04-11 04:59:23 +00:00
|
|
|
return unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *TransformToString(USHORT usTransform)
|
|
|
|
{
|
|
|
|
static char unknown[32];
|
|
|
|
switch (usTransform) {
|
|
|
|
case CONN_TRN_NONE:
|
|
|
|
return "NONE";
|
|
|
|
case CONN_TRN_CONCAVE:
|
|
|
|
return "CONCAVE";
|
|
|
|
case CONN_TRN_CONVEX:
|
|
|
|
return "CONVEX";
|
|
|
|
case CONN_TRN_SWITCH:
|
|
|
|
return "SWITCH";
|
|
|
|
default:
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf(unknown, countof(unknown), "UNKNOWN (0x%04x)", usTransform);
|
2008-04-11 04:59:23 +00:00
|
|
|
return unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *DestinationToString(USHORT usDestination)
|
|
|
|
{
|
|
|
|
static char unknown[32];
|
|
|
|
switch (usDestination) {
|
|
|
|
case CONN_DST_NONE:
|
|
|
|
return "NONE";
|
|
|
|
case CONN_DST_ATTENUATION:
|
|
|
|
return "ATTENUATION";
|
|
|
|
case CONN_DST_PITCH:
|
|
|
|
return "PITCH";
|
|
|
|
case CONN_DST_PAN:
|
|
|
|
return "PAN";
|
|
|
|
case CONN_DST_LFO_FREQUENCY:
|
|
|
|
return "LFO_FREQUENCY";
|
|
|
|
case CONN_DST_LFO_STARTDELAY:
|
|
|
|
return "LFO_STARTDELAY";
|
|
|
|
case CONN_DST_EG1_ATTACKTIME:
|
|
|
|
return "EG1_ATTACKTIME";
|
|
|
|
case CONN_DST_EG1_DECAYTIME:
|
|
|
|
return "EG1_DECAYTIME";
|
|
|
|
case CONN_DST_EG1_RELEASETIME:
|
|
|
|
return "EG1_RELEASETIME";
|
|
|
|
case CONN_DST_EG1_SUSTAINLEVEL:
|
|
|
|
return "EG1_SUSTAINLEVEL";
|
|
|
|
case CONN_DST_EG2_ATTACKTIME:
|
|
|
|
return "EG2_ATTACKTIME";
|
|
|
|
case CONN_DST_EG2_DECAYTIME:
|
|
|
|
return "EG2_DECAYTIME";
|
|
|
|
case CONN_DST_EG2_RELEASETIME:
|
|
|
|
return "EG2_RELEASETIME";
|
|
|
|
case CONN_DST_EG2_SUSTAINLEVEL:
|
|
|
|
return "EG2_SUSTAINLEVEL";
|
|
|
|
case CONN_DST_KEYNUMBER:
|
|
|
|
return "KEYNUMBER";
|
|
|
|
case CONN_DST_LEFT:
|
|
|
|
return "LEFT";
|
|
|
|
case CONN_DST_RIGHT:
|
|
|
|
return "RIGHT";
|
|
|
|
case CONN_DST_CENTER:
|
|
|
|
return "CENTER";
|
|
|
|
case CONN_DST_LEFTREAR:
|
|
|
|
return "LEFTREAR";
|
|
|
|
case CONN_DST_RIGHTREAR:
|
|
|
|
return "RIGHTREAR";
|
|
|
|
case CONN_DST_LFE_CHANNEL:
|
|
|
|
return "LFE_CHANNEL";
|
|
|
|
case CONN_DST_CHORUS:
|
|
|
|
return "CHORUS";
|
|
|
|
case CONN_DST_REVERB:
|
|
|
|
return "REVERB";
|
|
|
|
case CONN_DST_VIB_FREQUENCY:
|
|
|
|
return "VIB_FREQUENCY";
|
|
|
|
case CONN_DST_VIB_STARTDELAY:
|
|
|
|
return "VIB_STARTDELAY";
|
|
|
|
case CONN_DST_EG1_DELAYTIME:
|
|
|
|
return "EG1_DELAYTIME";
|
|
|
|
case CONN_DST_EG1_HOLDTIME:
|
|
|
|
return "EG1_HOLDTIME";
|
|
|
|
case CONN_DST_EG1_SHUTDOWNTIME:
|
|
|
|
return "EG1_SHUTDOWNTIME";
|
|
|
|
case CONN_DST_EG2_DELAYTIME:
|
|
|
|
return "EG2_DELAYTIME";
|
|
|
|
case CONN_DST_EG2_HOLDTIME:
|
|
|
|
return "EG2_HOLDTIME";
|
|
|
|
case CONN_DST_FILTER_CUTOFF:
|
|
|
|
return "FILTER_CUTOFF";
|
|
|
|
case CONN_DST_FILTER_Q:
|
|
|
|
return "FILTER_Q";
|
|
|
|
default:
|
About a week's worth of changes here. As a heads-up, I wouldn't be
surprised if this doesn't build in Linux right now. The CMakeLists.txt
were checked with MinGW and NMake, but how they fair under Linux is an
unknown to me at this time.
- Converted most sprintf (and all wsprintf) calls to either mysnprintf or
FStrings, depending on the situation.
- Changed the strings in the wbstartstruct to be FStrings.
- Changed myvsnprintf() to output nothing if count is greater than INT_MAX.
This is so that I can use a series of mysnprintf() calls and advance the
pointer for each one. Once the pointer goes beyond the end of the buffer,
the count will go negative, but since it's an unsigned type it will be
seen as excessively huge instead. This should not be a problem, as there's
no reason for ZDoom to be using text buffers larger than 2 GB anywhere.
- Ripped out the disabled bit from FGameConfigFile::MigrateOldConfig().
- Changed CalcMapName() to return an FString instead of a pointer to a static
buffer.
- Changed startmap in d_main.cpp into an FString.
- Changed CheckWarpTransMap() to take an FString& as the first argument.
- Changed d_mapname in g_level.cpp into an FString.
- Changed DoSubstitution() in ct_chat.cpp to place the substitutions in an
FString.
- Fixed: The MAPINFO parser wrote into the string buffer to construct a map
name when given a Hexen map number. This was fine with the old scanner
code, but only a happy coincidence prevents it from crashing with the new
code
- Added the 'B' conversion specifier to StringFormat::VWorker() for printing
binary numbers.
- Added CMake support for building with MinGW, MSYS, and NMake. Linux support
is probably broken until I get around to booting into Linux again. Niceties
provided over the existing Makefiles they're replacing:
* All command-line builds can use the same build system, rather than having
a separate one for MinGW and another for Linux.
* Microsoft's NMake tool is supported as a target.
* Progress meters.
* Parallel makes work from a fresh checkout without needing to be primed
first with a single-threaded make.
* Porting to other architectures should be simplified, whenever that day
comes.
- Replaced the makewad tool with zipdir. This handles the dependency tracking
itself instead of generating an external makefile to do it, since I couldn't
figure out how to generate a makefile with an external tool and include it
with a CMake-generated makefile. Where makewad used a master list of files
to generate the package file, zipdir just zips the entire contents of one or
more directories.
- Added the gdtoa package from netlib's fp library so that ZDoom's printf-style
formatting can be entirely independant of the CRT.
SVN r1082 (trunk)
2008-07-23 04:57:26 +00:00
|
|
|
mysnprintf(unknown, countof(unknown), "UNKNOWN (0x%04x)", usDestination);
|
2008-04-11 04:59:23 +00:00
|
|
|
return unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList)
|
|
|
|
{
|
|
|
|
DWORD i;
|
|
|
|
printf("%s Connections:\n", type);
|
|
|
|
for ( i = 0; i < art->cConnections; ++i ) {
|
|
|
|
printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n",
|
|
|
|
SourceToString(artList[i].usSource),
|
|
|
|
SourceToString(artList[i].usControl),
|
|
|
|
DestinationToString(artList[i].usDestination),
|
|
|
|
TransformToString(artList[i].usTransform),
|
|
|
|
artList[i].lScale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintWave(DLS_Wave *wave, DWORD index)
|
|
|
|
{
|
|
|
|
WaveFMT *format = wave->format;
|
|
|
|
if ( format ) {
|
|
|
|
printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length);
|
|
|
|
}
|
|
|
|
if ( wave->wsmp ) {
|
|
|
|
DWORD i;
|
|
|
|
printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote);
|
|
|
|
printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune);
|
|
|
|
printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation);
|
|
|
|
printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions);
|
|
|
|
printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops);
|
|
|
|
for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) {
|
|
|
|
WLOOP *loop = &wave->wsmp_loop[i];
|
|
|
|
printf(" Loop %u:\n", i);
|
|
|
|
printf(" ulStart = %u\n", loop->ulStart);
|
|
|
|
printf(" ulLength = %u\n", loop->ulLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintRegion(DLS_Region *region, DWORD index)
|
|
|
|
{
|
|
|
|
printf(" Region %u:\n", index);
|
|
|
|
if ( region->header ) {
|
|
|
|
printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh);
|
|
|
|
printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh);
|
|
|
|
printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions);
|
|
|
|
printf(" usKeyGroup = %hu\n", region->header->usKeyGroup);
|
|
|
|
}
|
|
|
|
if ( region->wlnk ) {
|
|
|
|
printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions);
|
|
|
|
printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup);
|
|
|
|
printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel);
|
|
|
|
printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex);
|
|
|
|
}
|
|
|
|
if ( region->wsmp ) {
|
|
|
|
DWORD i;
|
|
|
|
printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote);
|
|
|
|
printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune);
|
|
|
|
printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation);
|
|
|
|
printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions);
|
|
|
|
printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops);
|
|
|
|
for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) {
|
|
|
|
WLOOP *loop = ®ion->wsmp_loop[i];
|
|
|
|
printf(" Loop %u:\n", i);
|
|
|
|
printf(" ulStart = %u\n", loop->ulStart);
|
|
|
|
printf(" ulLength = %u\n", loop->ulLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( region->art && region->art->cConnections > 0 ) {
|
|
|
|
PrintArt("Region", region->art, region->artList);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PrintInstrument(DLS_Instrument *instrument, DWORD index)
|
|
|
|
{
|
|
|
|
printf("Instrument %u:\n", index);
|
|
|
|
if ( instrument->name ) {
|
|
|
|
printf(" Name: %s\n", instrument->name);
|
|
|
|
}
|
|
|
|
if ( instrument->header ) {
|
|
|
|
DWORD i;
|
|
|
|
printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank);
|
|
|
|
printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument);
|
|
|
|
printf(" Regions: %u\n", instrument->header->cRegions);
|
|
|
|
for ( i = 0; i < instrument->header->cRegions; ++i ) {
|
|
|
|
PrintRegion(&instrument->regions[i], i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( instrument->art && instrument->art->cConnections > 0 ) {
|
|
|
|
PrintArt("Instrument", instrument->art, instrument->artList);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void PrintDLS(DLS_Data *data)
|
|
|
|
{
|
|
|
|
printf("DLS Data:\n");
|
|
|
|
printf("cInstruments = %u\n", data->cInstruments);
|
|
|
|
if ( data->instruments ) {
|
|
|
|
DWORD i;
|
|
|
|
for ( i = 0; i < data->cInstruments; ++i ) {
|
|
|
|
PrintInstrument(&data->instruments[i], i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( data->ptbl && data->ptbl->cCues > 0 ) {
|
|
|
|
DWORD i;
|
|
|
|
printf("Cues: ");
|
|
|
|
for ( i = 0; i < data->ptbl->cCues; ++i ) {
|
|
|
|
if ( i > 0 ) {
|
|
|
|
printf(", ");
|
|
|
|
}
|
|
|
|
printf("%u", data->ptblList[i].ulOffset);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
if ( data->waveList ) {
|
|
|
|
DWORD i;
|
|
|
|
printf("Waves:\n");
|
|
|
|
for ( i = 0; i < data->ptbl->cCues; ++i ) {
|
|
|
|
PrintWave(&data->waveList[i], i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( data->name ) {
|
|
|
|
printf("Name: %s\n", data->name);
|
|
|
|
}
|
|
|
|
if ( data->artist ) {
|
|
|
|
printf("Artist: %s\n", data->artist);
|
|
|
|
}
|
|
|
|
if ( data->copyright ) {
|
|
|
|
printf("Copyright: %s\n", data->copyright);
|
|
|
|
}
|
|
|
|
if ( data->comments ) {
|
|
|
|
printf("Comments: %s\n", data->comments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TEST_MAIN_DLS
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for ( i = 1; i < argc; ++i ) {
|
|
|
|
Timidity::DLS_Data *data;
|
|
|
|
FILE *src = fopen(argv[i], "rb");
|
|
|
|
if ( !src ) {
|
|
|
|
fprintf(stderr, "Couldn't open %s: %s", argv[i], strerror(errno));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
data = Timidity::LoadDLS(src);
|
|
|
|
if ( data ) {
|
|
|
|
Timidity::PrintRIFF(data->chunk, 0);
|
|
|
|
Timidity::PrintDLS(data);
|
|
|
|
Timidity::FreeDLS(data);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Couldn't load %s: %s\n", argv[i], strerror(errno));
|
|
|
|
}
|
|
|
|
fclose(src);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Timidity
|
|
|
|
{
|
|
|
|
#endif // TEST_MAIN
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
#ifndef TEST_MAIN_DLS
|
|
|
|
|
|
|
|
DLS_Data *Timidity_LoadDLS(FILE *src)
|
|
|
|
{
|
|
|
|
return LoadDLS(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Timidity_FreeDLS(DLS_Data *patches)
|
|
|
|
{
|
|
|
|
FreeDLS(patches);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert timecents to sec */
|
|
|
|
static double to_msec(int timecent)
|
|
|
|
{
|
2008-04-12 05:33:20 +00:00
|
|
|
if (timecent == INT_MIN || timecent == 0)
|
2008-04-11 04:59:23 +00:00
|
|
|
return 0.0;
|
|
|
|
return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert decipercent to {0..1} */
|
|
|
|
static double to_normalized_percent(int decipercent)
|
|
|
|
{
|
|
|
|
return ((double)(decipercent / 65536)) / 1000.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* convert from 8bit value to fractional offset (15.15) */
|
|
|
|
static SDWORD to_offset(int offset)
|
|
|
|
{
|
|
|
|
return (SDWORD)offset << (7+15);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate ramp rate in fractional unit;
|
|
|
|
* diff = 8bit, time = msec
|
|
|
|
*/
|
|
|
|
static SDWORD calc_rate(Renderer *song, int diff, int sample_rate, double msec)
|
|
|
|
{
|
|
|
|
double rate;
|
|
|
|
|
|
|
|
if(msec < 6)
|
|
|
|
msec = 6;
|
|
|
|
if(diff == 0)
|
|
|
|
diff = 255;
|
|
|
|
diff <<= (7+15);
|
|
|
|
rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec;
|
|
|
|
return (SDWORD)rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
int value = 0;
|
|
|
|
for (i = 0; i < cConnections; ++i) {
|
|
|
|
CONNECTION *conn = &artList[i];
|
|
|
|
if(conn->usDestination == destination) {
|
|
|
|
// The formula for the destination is:
|
|
|
|
// usDestination = usDestination + usTransform(usSource * (usControl * lScale))
|
|
|
|
// Since we are only handling source/control of NONE and identity
|
|
|
|
// transform, this simplifies to: usDestination = usDestination + lScale
|
|
|
|
if (conn->usSource == CONN_SRC_NONE &&
|
|
|
|
conn->usControl == CONN_SRC_NONE &&
|
|
|
|
conn->usTransform == CONN_TRN_NONE)
|
|
|
|
value += conn->lScale;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins, DWORD index)
|
|
|
|
{
|
|
|
|
DLS_Region *rgn = &ins->regions[index];
|
|
|
|
DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex];
|
|
|
|
|
2008-05-09 03:54:06 +00:00
|
|
|
sample->type = INST_DLS;
|
2008-04-16 05:41:03 +00:00
|
|
|
sample->self_nonexclusive = !!(rgn->header->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE);
|
|
|
|
sample->key_group = (SBYTE)rgn->header->usKeyGroup;
|
2008-05-09 03:54:06 +00:00
|
|
|
sample->low_freq = note_to_freq(rgn->header->RangeKey.usLow);
|
|
|
|
sample->high_freq = note_to_freq(rgn->header->RangeKey.usHigh);
|
|
|
|
sample->root_freq = note_to_freq(rgn->wsmp->usUnityNote);
|
|
|
|
sample->low_vel = (BYTE)rgn->header->RangeVelocity.usLow;
|
|
|
|
sample->high_vel = (BYTE)rgn->header->RangeVelocity.usHigh;
|
2008-04-11 04:59:23 +00:00
|
|
|
|
2008-04-16 05:41:03 +00:00
|
|
|
sample->modes = wave->format->wBitsPerSample == 8 ? PATCH_UNSIGNED : PATCH_16;
|
2008-04-11 04:59:23 +00:00
|
|
|
sample->sample_rate = wave->format->dwSamplesPerSec;
|
|
|
|
sample->data = NULL;
|
|
|
|
sample->data_length = wave->length;
|
|
|
|
convert_sample_data(sample, wave->data);
|
2008-04-16 05:41:03 +00:00
|
|
|
if (rgn->wsmp->cSampleLoops)
|
|
|
|
{
|
|
|
|
sample->modes |= (PATCH_LOOPEN | PATCH_SUSTAIN);
|
2008-04-11 04:59:23 +00:00
|
|
|
sample->loop_start = rgn->wsmp_loop->ulStart / 2;
|
|
|
|
sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
|
|
|
|
}
|
|
|
|
sample->volume = 1.0f;
|
|
|
|
|
2008-04-16 05:41:03 +00:00
|
|
|
if (sample->modes & PATCH_SUSTAIN)
|
|
|
|
{
|
2008-04-11 04:59:23 +00:00
|
|
|
int value;
|
|
|
|
double attack, hold, decay, release; int sustain;
|
|
|
|
CONNECTIONLIST *art = NULL;
|
|
|
|
CONNECTION *artList = NULL;
|
|
|
|
|
|
|
|
if (ins->art && ins->art->cConnections > 0 && ins->artList) {
|
|
|
|
art = ins->art;
|
|
|
|
artList = ins->artList;
|
|
|
|
} else {
|
|
|
|
art = rgn->art;
|
|
|
|
artList = rgn->artList;
|
|
|
|
}
|
|
|
|
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME);
|
|
|
|
attack = to_msec(value);
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME);
|
|
|
|
hold = to_msec(value);
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME);
|
|
|
|
decay = to_msec(value);
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME);
|
|
|
|
release = to_msec(value);
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL);
|
|
|
|
sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0);
|
|
|
|
value = load_connection(art->cConnections, artList, CONN_DST_PAN);
|
|
|
|
sample->panning = (int)((0.5 + to_normalized_percent(value)) * 16383.f);
|
|
|
|
|
|
|
|
/*
|
|
|
|
printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release);
|
|
|
|
*/
|
|
|
|
|
2008-05-09 03:54:06 +00:00
|
|
|
sample->envelope.sf2.decay_vol = 0;
|
|
|
|
sample->envelope.sf2.attack_vol = (short)attack;
|
|
|
|
sample->envelope.sf2.hold_vol = (short)hold;
|
|
|
|
sample->envelope.sf2.decay_vol = (short)decay;
|
|
|
|
sample->envelope.sf2.release_vol = (short)release;
|
|
|
|
sample->envelope.sf2.sustain_vol = (short)sustain;
|
2008-04-11 04:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sample->data_length <<= FRACTION_BITS;
|
|
|
|
sample->loop_start <<= FRACTION_BITS;
|
|
|
|
sample->loop_end <<= FRACTION_BITS;
|
|
|
|
}
|
|
|
|
|
2008-04-16 05:41:03 +00:00
|
|
|
Instrument *load_instrument_dls(Renderer *song, int drum, int bank, int instrument)
|
2008-04-11 04:59:23 +00:00
|
|
|
{
|
2008-04-16 05:41:03 +00:00
|
|
|
Instrument *inst;
|
2008-04-11 04:59:23 +00:00
|
|
|
DWORD i;
|
2008-04-12 05:33:20 +00:00
|
|
|
DLS_Instrument *dls_ins = NULL;
|
2008-04-11 04:59:23 +00:00
|
|
|
|
|
|
|
if (song->patches == NULL)
|
2008-04-16 05:41:03 +00:00
|
|
|
{
|
2008-04-11 04:59:23 +00:00
|
|
|
return NULL;
|
2008-04-16 05:41:03 +00:00
|
|
|
}
|
2008-04-11 04:59:23 +00:00
|
|
|
drum = drum ? 0x80000000 : 0;
|
2008-04-16 05:41:03 +00:00
|
|
|
for (i = 0; i < song->patches->cInstruments; ++i)
|
|
|
|
{
|
2008-04-11 04:59:23 +00:00
|
|
|
dls_ins = &song->patches->instruments[i];
|
2008-04-12 05:33:20 +00:00
|
|
|
if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum &&
|
|
|
|
((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == (ULONG)bank &&
|
|
|
|
dls_ins->header->Locale.ulInstrument == (ULONG)instrument)
|
2008-04-11 04:59:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-04-16 05:41:03 +00:00
|
|
|
if (i == song->patches->cInstruments && bank == 0)
|
|
|
|
{
|
|
|
|
for (i = 0; i < song->patches->cInstruments; ++i)
|
|
|
|
{
|
2008-04-11 04:59:23 +00:00
|
|
|
dls_ins = &song->patches->instruments[i];
|
2008-04-12 05:33:20 +00:00
|
|
|
if ((dls_ins->header->Locale.ulBank & 0x80000000) == (ULONG)drum &&
|
|
|
|
dls_ins->header->Locale.ulInstrument == (ULONG)instrument)
|
2008-04-11 04:59:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-04-16 05:41:03 +00:00
|
|
|
if (i == song->patches->cInstruments)
|
|
|
|
{
|
2008-04-11 04:59:23 +00:00
|
|
|
// SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-04-16 05:41:03 +00:00
|
|
|
inst = (Instrument *)safe_malloc(sizeof(Instrument));
|
|
|
|
inst->samples = dls_ins->header->cRegions;
|
|
|
|
inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(Sample));
|
|
|
|
memset(inst->sample, 0, inst->samples * sizeof(Sample));
|
2008-04-11 04:59:23 +00:00
|
|
|
/*
|
|
|
|
printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples);
|
|
|
|
*/
|
2008-04-16 05:41:03 +00:00
|
|
|
for (i = 0; i < dls_ins->header->cRegions; ++i)
|
|
|
|
{
|
|
|
|
load_region_dls(song, &inst->sample[i], dls_ins, i);
|
2008-04-11 04:59:23 +00:00
|
|
|
}
|
2008-04-16 05:41:03 +00:00
|
|
|
return inst;
|
2008-04-11 04:59:23 +00:00
|
|
|
}
|
|
|
|
#endif /* !TEST_MAIN_DLS */
|
|
|
|
|
|
|
|
}
|