/*---------------------------------------------------------------------------* Project: DLS converter for SYN File: dls.c Copyright (C)2001-2006 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: dls.c,v $ Revision 1.5 2006/06/09 07:55:31 aka Removed temporary workaround for SDK1.0. Revision 1.4 2006/03/16 00:27:19 aka Added temporary workaround for SDK1.0. Revision 1.3 2006/02/08 06:21:14 aka Changed copyright. Revision 1.2 2005/11/04 07:16:48 aka Changed audio frame length from 5ms to 3ms. *---------------------------------------------------------------------------*/ #include #include #include #include #include "types.h" #include "dls.h" #include "wt.h" #include "string.h" #include "dspadpcm.h" /*--------------------------------------------------------------------------*/ static FILE *dlsFile; static FILE *wtFile; static FILE *pcmFile; /*--------------------------------------------------------------------------*/ static int currentProgram; static int percussive; static WTINST melodicInst[128]; static WTINST percussiveInst[128]; static u16 artIndex; static WTART art[0xFFFF]; static WTART artTemp; static u16 regionIndex; static WTREGION region[0xFFFF]; static int waveOffset; static int waveIndex; static WTSAMPLE waveSample[0xFFFF]; static u16 adpcmIndex; static WTADPCM adpcm[0xFFFF]; static int loopStart; static int loopLength; static int encodeAdpcm; static int convertTo16Bit; static int compression; static int returnFlag; #define USER_MODE_USEFLAG 0 // use option flag (default) #define USER_MODE_ADPCM 1 // compress all to ADPCM #define USER_MODE_RAW 2 // all raw PCM #define F_WSMP_NO_COMPRESSION 0x0002 /*--------------------------------------------------------------------------*/ #define reverse_endian_16(a)( \ ((a & 0xFF00) >> 8) | \ ((a & 0x00FF) << 8)) #define reverse_endian_32(a)( \ ((a & 0xFF000000) >> 24) | \ ((a & 0x00FF0000) >> 8) | \ ((a & 0x0000FF00) << 8) | \ ((a & 0x000000FF) << 24)) /*--------------------------------------------------------------------------*/ void dls_skip_chunk(void) { u32 count; fread(&count, 1, 4, dlsFile); // fix alignment if (count % sizeof(u16)) count += 1; fseek(dlsFile, count, SEEK_CUR); // printf("Skipping %d bytes\n", count); } /*--------------------------------------------------------------------------*/ void dls_string(void) { u32 count; fread(&count, 1, 4, dlsFile); // fix alignment if (count % sizeof(u16)) count += 1; while (count) { char ch; fread(&ch, 1, 1, dlsFile); // printf("%c", ch); count--; } // printf("\n"); } /*--------------------------------------------------------------------------*/ void dls_riff(void) { u32 count; fread(&count, 1, 4, dlsFile); printf("%d bytes\n", count); } /*--------------------------------------------------------------------------*/ void dls_colh(void) { u32 count, length; fread(&length, 1, 4, dlsFile); fread(&count, 1, 4, dlsFile); // check to see if we have advanced the read position by specified length length -= 4; if (length) fseek(dlsFile, length, SEEK_CUR); printf("%d instruments\n", count); } /*--------------------------------------------------------------------------*/ void dls_vers(void) { u32 ms, ls, length; fread(&length, 1, 4, dlsFile); fread(&ms, 1, 4, dlsFile); fread(&ls, 1, 4, dlsFile); // check to see if we have advanced the read position by specified length length -= 8; if (length) fseek(dlsFile, length, SEEK_CUR); printf( "VERSION %d,%d,%d,%d\n", ms >> 16, ms & 0xFFFF, ls >> 16, ls & 0xFFFF ); } /*--------------------------------------------------------------------------*/ void dls_list(void) { u32 list, length; fread(&length, 1, 4, dlsFile); fread(&list, 1, 4, dlsFile); /* printf( "<%c%c%c%c>\n", (list & 0xFF), ((list >> 8) & 0xFF), ((list >> 16) & 0xFF), ((list >> 24) & 0xFF) ); */ switch (list) { case COLH: case VERS: case LINS: case INS: case INSH: case LRGN: case RGN: case RGNH: case WSMP: case WLNK: case LART: case LAR2: // another Direct Music Producer hack!!! does it ever end? // if we don't do this we lose the articulations case ART1: case DATA: case PTBL: case DLID: case WVPL: case WAVE: case WAVU: case FMT: case SMPL: case INFO: break; default: printf( "\n%cWarning: LIST \"%c%c%c%c\" not defined by DLS 1.0 spec. skipping chunk!\n", 7, (list & 0xFF), ((list >> 8) & 0xFF), ((list >> 16) & 0xFF), ((list >> 24) & 0xFF) ); fseek(dlsFile, length - 4, SEEK_CUR); } } /*--------------------------------------------------------------------------*/ void dls_insh(void) { u32 regions; u32 bank; u32 program; u32 length; fread(&length, 1, 4, dlsFile); fread(®ions, 1, 4, dlsFile); fread(&bank, 1, 4, dlsFile); fread(&program, 1, 4, dlsFile); // check to see if we have advanced the read position by specified length length -= 12; if (length) fseek(dlsFile, length, SEEK_CUR); // printf("%d regions, bank: %d, program: %d\n", regions, bank, program); if (bank & 0x80000000) // percussive instrument percussive = 1; else percussive = 0; // this wt format does not support banks so if the instrument is not on // bank 0 do not make any instrument reference to it if (bank & 0x0000FFFF) currentProgram = 0xFFFFFFFF; else currentProgram = program; } /*--------------------------------------------------------------------------*/ void dls_rgnh(void) { u16 loKey; u16 hiKey; u16 loVel; u16 hiVel; u16 options; u16 keyGroup; WTREGION *thisRegion; u32 length; fread(&length, 1, 4, dlsFile); fread(&loKey, 1, 2, dlsFile); fread(&hiKey, 1, 2, dlsFile); fread(&loVel, 1, 2, dlsFile); fread(&hiVel, 1, 2, dlsFile); fread(&options, 1, 2, dlsFile); fread(&keyGroup, 1, 2, dlsFile); /* printf("loKey: %d, hiKey: %d\n", loKey, hiKey); printf("loVel: %d, hiVel: %d\n", loVel, hiVel); printf("Options: 0x%.4x\n", options); printf("KeyGroup: %d\n", keyGroup); */ // check to see if we have advanced the read position by specified length length -= 12; if (length) fseek(dlsFile, length, SEEK_CUR); thisRegion = ®ion[regionIndex]; // thisRegion->loKey = (u8)loKey; // thisRegion->hiKey = (u8)hiKey; // thisRegion->loVel = (u8)loVel; // thisRegion->hiVel = (u8)hiVel; thisRegion->keyGroup = (u8)keyGroup; // mark the current instrument's keys for this region if (currentProgram != 0xFFFFFFFF) { if (percussive) { int i; for (i = loKey; i <= hiKey; i++) { if (percussiveInst[currentProgram].keyRegion[i] == 0xFFFF) percussiveInst[currentProgram].keyRegion[i] = reverse_endian_16(regionIndex); } } else { int i; for (i = loKey; i <= hiKey; i++) { if (melodicInst[currentProgram].keyRegion[i] == 0xFFFF) melodicInst[currentProgram].keyRegion[i] = reverse_endian_16(regionIndex); } } } } /*--------------------------------------------------------------------------*/ void dls_wsmp(void) { u32 structSize; u16 unityNote; s16 fineTune; s32 attenuation; u32 options; u32 loops; u32 size; u32 type; u32 start; u32 length; WTREGION *thisRegion; fseek(dlsFile, 4, SEEK_CUR); fread(&structSize, 1, 4, dlsFile); fread(&unityNote, 1, 2, dlsFile); fread(&fineTune, 1, 2, dlsFile); fread(&attenuation, 1, 4, dlsFile); fread(&options, 1, 4, dlsFile); fread(&loops, 1, 4, dlsFile); /* printf("Struct size: %d\n", structSize); printf("unityNote: %d\n", unityNote); printf("fineTune: 0x%.4x\n", fineTune); printf("Attenuation: 0x%.8x\n", attenuation); printf("Options: 0x%.8x\n", options); printf("Loops: %d\n", loops); */ thisRegion = ®ion[regionIndex]; thisRegion->unityNote = (u8)unityNote; thisRegion->fineTune = reverse_endian_16(fineTune); thisRegion->attn = reverse_endian_32(attenuation); if (loops) { fread(&size, 1, 4, dlsFile); fread(&type, 1, 4, dlsFile); fread(&start, 1, 4, dlsFile); fread(&length, 1, 4, dlsFile); /* printf("\n"); printf("region: %d\n", regionIndex); printf("size: %d\n", size); printf("type: 0x%.8x\n", type); printf("start: %d\n", start); printf("length: %d\n", length); */ thisRegion->loopStart = reverse_endian_32(start); thisRegion->loopLength = reverse_endian_32(length); loopStart = start; loopLength = length; } else { thisRegion->loopStart = 0; thisRegion->loopLength = 0; loopStart = 0; loopLength = 0; } switch (compression) { case MODE_USE_FLAG: // use F_WSMP_NO_COMPRESSION flag if (options & F_WSMP_NO_COMPRESSION) encodeAdpcm = 0; else encodeAdpcm = 1; break; case MODE_COMPRESS_ALL: encodeAdpcm = 1; break; case MODE_COMPRESS_NONE: encodeAdpcm = 0; break; } } /*--------------------------------------------------------------------------*/ void dls_wlnk(void) { u16 options; u16 phaseGroup; u32 channel; u32 tableIndex; WTREGION *thisRegion; fseek(dlsFile, 4, SEEK_CUR); fread(&options, 1, 2, dlsFile); fread(&phaseGroup, 1, 2, dlsFile); fread(&channel, 1, 4, dlsFile); fread(&tableIndex, 1, 4, dlsFile); /* printf("Options: 0x%.4x\n", options); printf("PhaseGroup: 0x%.4x\n", phaseGroup); printf("Channel: %d\n", channel); printf("TableIndex: %d\n", tableIndex); */ thisRegion = ®ion[regionIndex]; thisRegion->sampleIndex = reverse_endian_32(tableIndex); thisRegion->articulationIndex = reverse_endian_32(artIndex); regionIndex++; } /*--------------------------------------------------------------------------*/ void dls_art_default(void) { WTART *a = &artTemp; a->lfoFreq = 0xFCACAE9C; // 5Hz a->lfoDelay = 0xE0DB6022; // 0.01 sec a->lfoAtten = 0x00000000; // 0dB a->lfoPitch = 0x00000000; // 0 cents a->lfoMod2Atten = 0x00000000; // 0dB a->lfoMod2Pitch = 0x00000000; // 0 cents a->eg1Attack = 0x80000000; // 0 seconds a->eg1Decay = 0x80000000; // 0 seconds a->eg1Sustain = 0x03E80000; // 100% a->eg1Release = 0x80000000; // 0 seconds a->eg1Vel2Attack = 0x80000000; // 0 seconds a->eg1Key2Decay = 0x80000000; // 0 seconds a->eg2Attack = 0x80000000; // 0 seconds a->eg2Decay = 0x80000000; // 0 seconds a->eg2Sustain = 0x03E80000; // 100% a->eg2Release = 0x80000000; // 0 seconds a->eg2Vel2Attack = 0x80000000; // 0 seconds a->eg2Key2Decay = 0x80000000; // 0 seconds a->eg2Pitch = 0x00000000; // 0 cents a->pan = 0x00000000; // center } /*---------------------------------------------------------------------------*/ void dls_connection (u16 source, u16 control, u16 destination, s32 scale) { WTART *a = &artTemp; switch (source) { case CONN_SRC_NONE: switch (destination) { case CONN_DST_LFO_FREQUENCY: a->lfoFreq = scale; break; case CONN_DST_LFO_STARTDELAY: a->lfoDelay = scale; break; case CONN_DST_EG1_ATTACKTIME: a->eg1Attack = scale; break; case CONN_DST_EG1_DECAYTIME: a->eg1Decay = scale; break; case CONN_DST_EG1_SUSTAINLEVEL: a->eg1Sustain = scale; break; case CONN_DST_EG1_RELEASETIME: a->eg1Release = scale; break; case CONN_DST_EG2_ATTACKTIME: a->eg2Attack = scale; break; case CONN_DST_EG2_DECAYTIME: a->eg2Decay = scale; break; case CONN_DST_EG2_SUSTAINLEVEL: a->eg2Sustain = scale; break; case CONN_DST_EG2_RELEASETIME: a->eg2Release = scale; break; case CONN_DST_EG1_RESERVED: break; case CONN_DST_EG2_RESERVED: break; case CONN_DST_PAN: a->pan = scale; break; } break; case CONN_SRC_LFO: switch (destination) { case CONN_DST_ATTENUATION: switch (control) { case CONN_SRC_NONE: a->lfoAtten = scale; break; case CONN_SRC_CC1: a->lfoMod2Atten = scale; break; } break; case CONN_DST_PITCH: switch (control) { case CONN_SRC_NONE: a->lfoPitch = scale; break; case CONN_SRC_CC1: a->lfoMod2Pitch = scale; break; } break; } break; case CONN_SRC_KEYONVELOCITY: switch (destination) { case CONN_DST_EG1_ATTACKTIME: a->eg1Vel2Attack = scale; break; case CONN_DST_EG2_ATTACKTIME: a->eg2Vel2Attack = scale; break; } break; case CONN_SRC_KEYNUMBER: switch (destination) { case CONN_DST_EG1_DECAYTIME: a->eg1Key2Decay = scale; break; case CONN_DST_EG2_DECAYTIME: a->eg2Key2Decay = scale; break; } break; case CONN_SRC_EG2: switch (destination) { case CONN_DST_PITCH: a->eg2Pitch = scale; break; } break; } } /*---------------------------------------------------------------------------*/ u32 dls_tc2ms(s32 scale) // time cents to milliseconds { if (scale == 0x80000000) return 0; return (u32)(pow(2, (double)scale / (1200 * 65536)) * 1000); } /*--------------------------------------------------------------------------*/ s32 dls_get_eg1Sustain(s32 scale) { f32 percent = (float)scale / 0x03E80000; return (s32)(0x03C00000 * percent) + 0xFC400000; /* double dB; if (scale == 0x00000000) dB = -96.0; else dB = -20.0 * log10(1000.0 / (scale / 0x00010000)); return(s32)(dB * 10 * 0x00010000); */ } /*--------------------------------------------------------------------------*/ s32 dls_get_eg1Release(s32 scale) { s32 frames; frames = dls_tc2ms(scale) / 3; // 3 ms per audio frame if (frames) return (s32)((-960 * 0x00010000) / frames); else return (s32)(-960 * 0x00010000); } /*--------------------------------------------------------------------------*/ s32 dls_get_eg2Sustain(s32 scale, s32 cents) { if (scale == 0x00000000) return 0; else return (s32)(cents * ((double)scale / (1000 * 65536))); } /*--------------------------------------------------------------------------*/ s32 dls_get_eg2Release(s32 scale, s32 cents) { u32 frames; frames = dls_tc2ms(scale) / 3; // 3 ms per audio frame if (frames) return (s32)((cents * -1) / frames); else return cents * -1; } /*--------------------------------------------------------------------------*/ s32 dls_get_lfoFreq(s32 scale) { f32 f; f = (float)pow(2, ((double)scale / 65536 - 6900) / 1200) * 440; return (s32)(((1000.0f / f) / (3 * 64)) * 0x00010000); // 3ms frames * 64 steps in LFO } /*--------------------------------------------------------------------------*/ s32 dls_get_lfoDelay(s32 scale) { return dls_tc2ms(scale) / 65536; } /*--------------------------------------------------------------------------*/ s32 dls_get_pan(s32 scale) { if (scale == 0) return 64; return (s32)(127 * ((float)(scale + (500 * 0x00010000)) / (1000 * 0x00010000))) ; } /*--------------------------------------------------------------------------*/ void dls_set_art(void) { WTART *a = &art[artIndex]; // print LFO a->lfoFreq = reverse_endian_32(dls_get_lfoFreq(artTemp.lfoFreq)); a->lfoDelay = reverse_endian_32(dls_get_lfoDelay(artTemp.lfoDelay)); a->lfoAtten = reverse_endian_32(artTemp.lfoAtten); a->lfoPitch = reverse_endian_32(artTemp.lfoPitch); a->lfoMod2Atten = reverse_endian_32(artTemp.lfoMod2Atten); a->lfoMod2Pitch = reverse_endian_32(artTemp.lfoMod2Pitch); // print (eg1) volume envelope a->eg1Attack = reverse_endian_32(artTemp.eg1Attack); a->eg1Decay = reverse_endian_32(artTemp.eg1Decay); a->eg1Sustain = reverse_endian_32(dls_get_eg1Sustain(artTemp.eg1Sustain)); a->eg1Release = reverse_endian_32(dls_get_eg1Release(artTemp.eg1Release)); a->eg1Vel2Attack = reverse_endian_32(artTemp.eg1Vel2Attack); a->eg1Key2Decay = reverse_endian_32(artTemp.eg1Key2Decay); // print (eg2) pitch envelope a->eg2Pitch = reverse_endian_32(artTemp.eg2Pitch); a->eg2Attack = reverse_endian_32(artTemp.eg2Attack); a->eg2Decay = reverse_endian_32(artTemp.eg2Decay); a->eg2Sustain = reverse_endian_32(dls_get_eg2Sustain(artTemp.eg2Sustain, artTemp.eg2Pitch)); a->eg2Release = reverse_endian_32(dls_get_eg2Release(artTemp.eg2Release, artTemp.eg2Pitch)); a->eg2Vel2Attack = reverse_endian_32(artTemp.eg2Vel2Attack); a->eg2Key2Decay = reverse_endian_32(artTemp.eg2Key2Decay); // print pan a->pan = reverse_endian_32(dls_get_pan(artTemp.pan)); } /*--------------------------------------------------------------------------*/ void dls_art1(void) { u32 structSize; u32 connectionBlocks; u16 source; u16 control; u16 destination; u16 transform; s32 scale; fseek(dlsFile, 4, SEEK_CUR); fread(&structSize, 1, 4, dlsFile); fread(&connectionBlocks, 1, 4, dlsFile); /* printf("StructSize: %d\n", structSize); printf("ConnectionBlocks: %d", connectionBlocks); */ dls_art_default(); while (connectionBlocks) { fread(&source, 1, 2, dlsFile); fread(&control, 1, 2, dlsFile); fread(&destination, 1, 2, dlsFile); fread(&transform, 1, 2, dlsFile); fread(&scale, 1, 4, dlsFile); /* printf("\n"); printf("Source: 0x%.4x\n", source); printf("Control: 0x%.4x\n", control); printf("Destination: 0x%.4x\n", destination); printf("Transform: 0x%.4x\n", transform); printf("Scale: 0x%.8x\n", scale); */ dls_connection(source, control, destination, scale); connectionBlocks--; } dls_set_art(); artIndex++; } /*--------------------------------------------------------------------------*/ void dls_fmt(void) { u16 formatTag; u16 channels; u32 samplesPerSec; u32 averageBytesPerSec; u16 blockAlign; u16 bitsPerSample; u16 samplesPerSec16; u16 format; fseek(dlsFile, 4, SEEK_CUR); fread(&formatTag, 1, 2, dlsFile); fread(&channels, 1, 2, dlsFile); fread(&samplesPerSec, 1, 4, dlsFile); fread(&averageBytesPerSec, 1, 4, dlsFile); fread(&blockAlign, 1, 2, dlsFile); fread(&bitsPerSample, 1, 2, dlsFile); fseek(dlsFile, 2, SEEK_CUR); /* printf("FormatTag: 0x%.4x\n", formatTag); printf("Channels: %d\n", channels); printf("SamplesPerSec: %d\n", samplesPerSec); printf("AverageBytesPerSec: %d\n", averageBytesPerSec); printf("BlockAlign: %d\n", blockAlign); printf("BitsPerSample: %d\n", bitsPerSample); */ // give warning if format tag is not PCM if (formatTag != 0x0001) printf( "Warning: sample %d is not in PCM format!%c\n", waveIndex, 7 ); switch (bitsPerSample) { case 16: if (encodeAdpcm) { format = WT_FORMAT_ADPCM; convertTo16Bit = 0; } else { format = WT_FORMAT_PCM16; } break; case 8: if (encodeAdpcm) { format = WT_FORMAT_ADPCM; convertTo16Bit = 1; } else { format = WT_FORMAT_PCM8; } break; default: printf( "Warning: sample %d is not 16 or 8 bits per sample!%c\n", waveIndex, 7 ); } samplesPerSec16 = (u16)samplesPerSec; waveSample[waveIndex].format = reverse_endian_16(format); waveSample[waveIndex].sampleRate = reverse_endian_16(samplesPerSec16); } /*--------------------------------------------------------------------------*/ typedef u32 (*lpFunc1)(u32); typedef u32 (*lpFunc2)(void); typedef void (*lpFunc3)(s16*, u8*, ADPCMINFO*, u32); typedef void (*lpFunc4)(u8*, s16*, ADPCMINFO*, u32); typedef void (*lpFunc5)(u8*, ADPCMINFO*, u32); extern lpFunc1 getBytesForAdpcmBuffer; extern lpFunc1 getBytesForAdpcmSamples; extern lpFunc1 getBytesForPcmBuffer; extern lpFunc1 getNibbleAddress; extern lpFunc2 getBytesForAdpcmInfo; extern lpFunc3 encode; extern lpFunc4 decode; extern lpFunc5 getLoopContext; void dls_data(void) { u32 count; fread(&count, 1, 4, dlsFile); switch (reverse_endian_16(waveSample[waveIndex].format)) { case WT_FORMAT_ADPCM: { u8 bytes; // ADPCM has to start on a frame boundary (8 bytes) bytes = waveOffset % 8; if (bytes) { bytes = 8 - bytes; while (bytes) { u8 ch = 0; fwrite(&ch, 1, 1, pcmFile); waveOffset++; bytes--; } } // see if the sample needs to be converted to 16 bit first if (convertTo16Bit) { // allocate buffer for storage u8 *adpcmBuffer; void *pcm16Buffer; u32 nBytesForAdpcmBuffer; u32 nBytesForPcm16Buffer; u32 nBytesForAdpcmSamples; u32 temp; nBytesForAdpcmBuffer = getBytesForAdpcmBuffer(count); nBytesForPcm16Buffer = getBytesForPcmBuffer(count); nBytesForAdpcmSamples = getBytesForAdpcmSamples(count); pcm16Buffer = malloc(nBytesForPcm16Buffer); adpcmBuffer = malloc(nBytesForAdpcmBuffer); waveSample[waveIndex].length = reverse_endian_32(nBytesForAdpcmSamples); waveSample[waveIndex].offset = reverse_endian_32(waveOffset * 2); waveOffset += nBytesForAdpcmSamples; if (pcm16Buffer && adpcmBuffer) { u16 *p; u32 samples; ADPCMINFO adpcminfo; p = (s16*)pcm16Buffer; samples = count; temp = samples; while (samples) { u8 sample; fread(&sample, 1, 1, dlsFile); *p++ = (s16)((sample + 0x80) << 8); samples--; } samples = temp; encode( pcm16Buffer, adpcmBuffer, &adpcminfo, samples ); if (loopStart + loopLength) getLoopContext( adpcmBuffer, &adpcminfo, loopStart ); memcpy(&adpcm[adpcmIndex], &adpcminfo, sizeof(WTADPCM)); { u16 *p; p = (u16*)&adpcm[adpcmIndex]; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); } fwrite(adpcmBuffer, nBytesForAdpcmSamples, 1, pcmFile); } else { printf( "Warning: could not allocate buffer for PCM conversion!\n%c", 7 ); } if (pcm16Buffer) free(pcm16Buffer); if (adpcmBuffer) free(adpcmBuffer); } else { u8 *adpcmBuffer; s16 *pcmBuffer; u32 samples; u32 nBytesForBuffer, nBytesForSamples; samples = count / 2; nBytesForBuffer = getBytesForAdpcmBuffer(samples); nBytesForSamples = getBytesForAdpcmSamples(samples); adpcmBuffer = malloc(nBytesForBuffer); pcmBuffer = malloc(count); waveSample[waveIndex].length = reverse_endian_32(samples); waveSample[waveIndex].offset = reverse_endian_32(waveOffset * 2); waveOffset += nBytesForSamples; if (adpcmBuffer && pcmBuffer) { ADPCMINFO adpcminfo; fread(pcmBuffer, count, 1, dlsFile); encode( pcmBuffer, adpcmBuffer, &adpcminfo, samples ); if (loopStart + loopLength) getLoopContext( adpcmBuffer, &adpcminfo, loopStart ); memcpy(&adpcm[adpcmIndex], &adpcminfo, sizeof(WTADPCM)); { u16 *p; p = (u16*)&adpcm[adpcmIndex]; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); p++; *p = reverse_endian_16(*p); } fwrite(adpcmBuffer, nBytesForSamples, 1, pcmFile); } else { printf( "Warning: could not allocate buffer for ADPCM encode!\n%c", 7 ); } if (adpcmBuffer) free(adpcmBuffer); if (pcmBuffer) free(pcmBuffer); } } waveSample[waveIndex].adpcmIndex = reverse_endian_16(adpcmIndex); adpcmIndex++; break; case WT_FORMAT_PCM16: waveSample[waveIndex].length = reverse_endian_32(count / 2); waveSample[waveIndex].offset = reverse_endian_32(waveOffset / 2); waveOffset += count; while (count) { u16 sample; fread(&sample, 1, 2, dlsFile); sample = reverse_endian_16(sample); fwrite(&sample, 1, 2, pcmFile); count -= 2; } break; case WT_FORMAT_PCM8: waveSample[waveIndex].length = reverse_endian_32(count); waveSample[waveIndex].offset = reverse_endian_32(waveOffset); waveOffset += count; while (count) { u8 sample; fread(&sample, 1, 1, dlsFile); sample += 0x80; fwrite(&sample, 1, 1, pcmFile); count--; } break; } waveIndex++; printf("."); } /*--------------------------------------------------------------------------*/ void dls_read_file(FILE *dlsFile_, FILE *wtFile_, FILE *pcmFile_, int mode) { WTFILEHEADER fileHeader; int filePosition; int i, j; // initialize file pointers dlsFile = dlsFile_; wtFile = wtFile_; pcmFile = pcmFile_; artIndex = 0; regionIndex = 0; waveIndex = 0; waveOffset = 0; adpcmIndex = 0; compression = mode; // mark all instrument regions invalid for (i = 0; i < 128; i++) for (j = 0; j < 128; j++) percussiveInst[i].keyRegion[j] = 0xFFFF; for (i = 0; i < 128; i++) for (j = 0; j < 128; j++) melodicInst[i].keyRegion[j] = 0xFFFF; while (1) { u32 chunk; if (fread(&chunk, 1, 4, dlsFile) == 0) { printf("\nEnd of DLS file reached\n"); break; } /* printf( "<%c%c%c%c>\n", (chunk & 0xFF), ((chunk >> 8) & 0xFF), ((chunk >> 16) & 0xFF), ((chunk >> 24) & 0xFF) ); */ switch (chunk) { case RIFF: dls_riff(); break; case COLH: dls_colh(); break; case VERS: dls_vers(); break; case LIST: dls_list(); break; case INSH: dls_insh(); break; case RGNH: dls_rgnh(); break; case WSMP: dls_wsmp(); break; case WLNK: dls_wlnk(); break; case ART1: dls_art1(); break; case FMT: dls_fmt(); break; case DATA: dls_data(); break; case DLS: break; case IARL: case IART: case ICMS: case ICMT: case ICOP: case ICRD: case IENG: case IGNR: case IKEY: case IMED: case INAM: case IPRD: case ISBJ: case ISFT: case ISRC: case ISRF: case ITCH: dls_string(); break; case PTBL: default: dls_skip_chunk(); break; } } // write wt file fwrite(&fileHeader, sizeof(WTFILEHEADER), 1, wtFile); filePosition = sizeof(WTFILEHEADER); fileHeader.offsetPercussiveInst = reverse_endian_32(filePosition); fwrite(percussiveInst, sizeof(WTINST), 128, wtFile); filePosition += sizeof(WTINST) * 128; fileHeader.offsetMelodicInst = reverse_endian_32(filePosition); fwrite(melodicInst, sizeof(WTINST), 128, wtFile); filePosition += sizeof(WTINST) * 128; fileHeader.offsetRegions = reverse_endian_32(filePosition); fwrite(region, sizeof(WTREGION), regionIndex, wtFile); filePosition += sizeof(WTREGION) * regionIndex; fileHeader.offsetArticulations = reverse_endian_32(filePosition); fwrite(art, sizeof(WTART), artIndex, wtFile); filePosition += sizeof(WTART) * artIndex; fileHeader.offsetSamples = reverse_endian_32(filePosition); fwrite(waveSample, sizeof(WTSAMPLE), waveIndex, wtFile); filePosition += sizeof(WTSAMPLE) * waveIndex; fileHeader.offsetAdpcmContext = reverse_endian_32(filePosition); fwrite(adpcm, sizeof(WTADPCM), adpcmIndex, wtFile); // write the real header again fseek(wtFile, 0, SEEK_SET); fwrite(&fileHeader, sizeof(WTFILEHEADER), 1, wtFile); }