#include "fmod_settings.h" #ifdef FMOD_SUPPORT_DLS #include "fmod.h" #include "fmod_codec_dls.h" #include "fmod_codec_wav.h" #include "fmod_soundi.h" #include namespace FMOD { FMOD_CODEC_DESCRIPTION_EX dlscodec; #ifdef PLUGIN_EXPORTS #ifdef __cplusplus extern "C" { #endif /* FMODGetCodecDescription is mandatory for every fmod plugin. This is the symbol the registerplugin function searches for. Must be declared with F_API to make it export as stdcall. */ F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx() { return CodecDLS::getDescriptionEx(); } #ifdef __cplusplus } #endif #endif /* PLUGIN_EXPORTS */ /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_CODEC_DESCRIPTION_EX *CodecDLS::getDescriptionEx() { FMOD_memset(&dlscodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX)); dlscodec.name = "FMOD DLS Codec"; dlscodec.version = 0x00010100; dlscodec.timeunits = FMOD_TIMEUNIT_PCM; dlscodec.open = &CodecDLS::openCallback; dlscodec.close = &CodecDLS::closeCallback; dlscodec.read = &CodecDLS::readCallback; dlscodec.setposition = &CodecDLS::setPositionCallback; dlscodec.mType = FMOD_SOUND_TYPE_DLS; dlscodec.mSize = sizeof(CodecDLS); return &dlscodec; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT CodecDLS::parseChunk(char *parentchunk, unsigned int chunksize) { unsigned int offset, fileoffset; FMOD_RESULT result; bool done = false; result = mFile->tell(&fileoffset); if (result != FMOD_OK) { return result; } offset = 4; fileoffset -= sizeof(WAVE_CHUNK); /* Decode chunks */ do { WAVE_CHUNK chunk; result = mFile->seek(fileoffset + sizeof(WAVE_CHUNK), SEEK_SET); if (result != FMOD_OK) { return result; } result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size); #endif //FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::parseRIFF","chunk : id %c%c%c%c size %d\n", chunk.id[0],chunk.id[1],chunk.id[2],chunk.id[3], chunk.size)); /* CHUNKS WE DONT CARE ABOUT */ if (!FMOD_strncmp((const char *)chunk.id, "vers", 4) || !FMOD_strncmp((const char *)chunk.id, "msyn", 4) || !FMOD_strncmp((const char *)chunk.id, "dlid", 4)) { } /* NUMBER OF INSTRUMENTS CHUNK */ else if (!FMOD_strncmp((const char *)chunk.id, "colh", 4)) { result = mFile->read(&mNumInstruments, 4, 1, 0); if (result != FMOD_OK) { return result; } mInstrument = (CodecDLSInstrument *)FMOD_Memory_Calloc(mNumInstruments * sizeof(CodecDLSInstrument)); if (!mInstrument) { return FMOD_ERR_MEMORY; } } /* POOL TABLE CHUNK */ else if (!FMOD_strncmp((const char *)chunk.id, "ptbl", 4)) { unsigned int size; result = mFile->read(&size, 4, 1, 0); if (result != FMOD_OK) { return result; } result = mFile->read(&mNumSamples, 4, 1, 0); if (result != FMOD_OK) { return result; } /* Fill out base class members, also pointing to or allocating storage for them. */ waveformat = (FMOD_CODEC_WAVEFORMAT *)FMOD_Memory_Calloc(sizeof(FMOD_CODEC_WAVEFORMAT) * mNumSamples); if (!waveformat) { return FMOD_ERR_MEMORY; } mSample = (CodecDLSSample *)FMOD_Memory_Calloc(mNumSamples *sizeof(CodecDLSSample)); if (!mSample) { return FMOD_ERR_MEMORY; } } /* LIST CHUNK */ else if (!FMOD_strncmp((const char *)chunk.id, "LIST", 4)) { char listid[4]; result = mFile->read(listid, 1, 4, 0); if (result != FMOD_OK) { return result; } result = parseChunk(listid, chunk.size); if (result != FMOD_OK) { return result; } if (!FMOD_strncmp((const char *)listid, "wave", 4)) { mSampleID++; } else if (!FMOD_strncmp((const char *)listid, "ins ", 4)) { mInstrumentID++; if (mInstrumentID >= mNumInstruments) { mInstrumentID = mInstrumentID; } } else if (!FMOD_strncmp((const char *)listid, "rgn ", 4)) { mRegionID++; } } else if (!FMOD_strncmp((const char *)chunk.id, "dlid", 4)) { FMOD_GUID dlsid; result = mFile->read(&dlsid, 1, sizeof(FMOD_GUID), 0); if (result != FMOD_OK) { return result; } } else if (!FMOD_strncmp((const char *)chunk.id, "insh", 4)) { result = mFile->read(&mInstrument[mInstrumentID].mHeader, 1, sizeof(DLS_INSTRUMENTHEADER), 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG mInstrument[mInstrumentID].mHeader.cRegions = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.cRegions); mInstrument[mInstrumentID].mHeader.Locale.ulBank = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.Locale.ulBank); mInstrument[mInstrumentID].mHeader.Locale.ulInstrument = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.Locale.ulInstrument); #endif mInstrument[mInstrumentID].mRegion = (CodecDLSRegion *)FMOD_Memory_Calloc(sizeof(CodecDLSRegion) * mInstrument[mInstrumentID].mHeader.cRegions); if (!mInstrument[mInstrumentID].mRegion) { return FMOD_ERR_MEMORY; } mRegionID = 0; } else if (!FMOD_strncmp((const char *)chunk.id, "rgnh", 4)) { result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader, 1, sizeof(DLS_REGIONHEADER), 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usLow = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usLow); mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usHigh = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usHigh); mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usLow = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usLow); mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usHigh = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usHigh); mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.fusOptions = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.fusOptions); mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.usKeyGroup = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.usKeyGroup); #endif } else if (!FMOD_strncmp((const char *)chunk.id, "wsmp", 4)) { unsigned int size = sizeof(DLS_WAVESAMPLE); if (chunk.size < size) { size = chunk.size; } if (!FMOD_strncmp(parentchunk, "wave", 4)) { result = mFile->read(&mSample[mSampleID].mWaveSample, 1, size, 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG mSample[mSampleID].mWaveSample.cbSize = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.cbSize); mSample[mSampleID].mWaveSample.usUnityNote = FMOD_SWAPENDIAN_WORD(mSample[mSampleID].mWaveSample.usUnityNote); mSample[mSampleID].mWaveSample.sFineTune = FMOD_SWAPENDIAN_WORD(mSample[mSampleID].mWaveSample.sFineTune); mSample[mSampleID].mWaveSample.lAttenuation = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.lAttenuation); mSample[mSampleID].mWaveSample.fulOptions = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.fulOptions); #endif if (mSample[mSampleID].mWaveSample.cSampleLoops) { #ifdef PLATFORM_ENDIAN_BIG mSample[mSampleID].mWaveSample.loop[0].cbSize = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].cbSize); mSample[mSampleID].mWaveSample.loop[0].ulLoopType = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopType); mSample[mSampleID].mWaveSample.loop[0].ulLoopStart = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopStart); mSample[mSampleID].mWaveSample.loop[0].ulLoopLength = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopLength); #endif waveformat[mSampleID].mode = FMOD_LOOP_NORMAL; waveformat[mSampleID].loopstart = mSample[mSampleID].mWaveSample.loop[0].ulLoopStart; waveformat[mSampleID].loopend = mSample[mSampleID].mWaveSample.loop[0].ulLoopStart + mSample[mSampleID].mWaveSample.loop[0].ulLoopLength - 1; } } else if (!FMOD_strncmp(parentchunk, "rgn ", 4)) { result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample, 1, size, 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cbSize = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cbSize); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.usUnityNote = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.usUnityNote); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.sFineTune = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.sFineTune); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.lAttenuation = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.lAttenuation); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.fulOptions = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.fulOptions); if (mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cSampleLoops) { mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].cbSize = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].cbSize); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopType = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopType); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopStart = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopStart); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopLength = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopLength); } #endif } } else if (!FMOD_strncmp((const char *)chunk.id, "wlnk", 4)) { result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink, 1, sizeof(DLS_WAVELINK), 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.fusOptions = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.fusOptions); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.usPhaseGroup = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.usPhaseGroup); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulChannel = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulChannel); mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulTableIndex = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulTableIndex); #endif } else if (!FMOD_strncmp((const char *)chunk.id, "art1", 4)) { struct { unsigned int cbSize; unsigned int cConnectionBlocks; } articulator; result = mFile->read(&articulator, 1, sizeof(articulator), 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG articulator.cbSize = FMOD_SWAPENDIAN_DWORD(articulator.cbSize); articulator.cConnectionBlocks = FMOD_SWAPENDIAN_DWORD(articulator.cConnectionBlocks); #endif if (articulator.cbSize > sizeof(articulator)) { mFile->seek(articulator.cbSize - sizeof(articulator), SEEK_CUR); } if (mRegionID < mInstrument[mInstrumentID].mHeader.cRegions) { mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock = (DLS_CONNECTIONBLOCK *)FMOD_Memory_Calloc(sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks); if (!mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock) { return FMOD_ERR_MEMORY; } mInstrument[mInstrumentID].mRegion[mRegionID].mNumConnectionBlocks = articulator.cConnectionBlocks; result = mFile->read(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock, 1, sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks, 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG { unsigned int count; for (count = 0; count < articulator.cConnectionBlocks; count++) { mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usSource = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usSource); mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usControl = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usControl); mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usDestination = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usDestination); mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usTransform = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usTransform); mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].lScale = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].lScale); } } #endif } else { mInstrument[mInstrumentID].mConnectionBlock = (DLS_CONNECTIONBLOCK *)FMOD_Memory_Calloc(sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks); if (!mInstrument[mInstrumentID].mConnectionBlock) { return FMOD_ERR_MEMORY; } mInstrument[mInstrumentID].mNumConnectionBlocks = articulator.cConnectionBlocks; result = mFile->read(mInstrument[mInstrumentID].mConnectionBlock, 1, sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks, 0); if (result != FMOD_OK) { return result; } #ifdef PLATFORM_ENDIAN_BIG unsigned int count; for (count = 0; count < articulator.cConnectionBlocks; count++) { mInstrument[mInstrumentID].mConnectionBlock[count].usSource = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usSource); mInstrument[mInstrumentID].mConnectionBlock[count].usControl = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usControl); mInstrument[mInstrumentID].mConnectionBlock[count].usDestination = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usDestination); mInstrument[mInstrumentID].mConnectionBlock[count].usTransform = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usTransform); mInstrument[mInstrumentID].mConnectionBlock[count].lScale = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mConnectionBlock[count].lScale); } #endif } } /* FORMAT CHUNK */ else if (!FMOD_strncmp((const char *)chunk.id, "fmt ", 4)) { WAVE_FORMATEXTENSIBLE srcformat; unsigned int size = chunk.size; /* Reduced allocs here and used a local instance of waveformatextensible instead */ if (size > sizeof(WAVE_FORMATEXTENSIBLE)) { size = sizeof(WAVE_FORMATEXTENSIBLE); } FMOD_memset(&srcformat, 0, sizeof(WAVE_FORMATEXTENSIBLE)); result = mFile->read(&srcformat, 1, size, 0); if (result != FMOD_OK) { return result; } if (chunk.size > sizeof(WAVE_FORMATEXTENSIBLE)) { result = mFile->seek(chunk.size - sizeof(WAVE_FORMATEXTENSIBLE), SEEK_CUR); if (result != FMOD_OK) { return result; } } #ifdef PLATFORM_ENDIAN_BIG srcformat.Format.wFormatTag = FMOD_SWAPENDIAN_WORD (srcformat.Format.wFormatTag); srcformat.Format.nChannels = FMOD_SWAPENDIAN_WORD (srcformat.Format.nChannels); srcformat.Format.nSamplesPerSec = FMOD_SWAPENDIAN_DWORD(srcformat.Format.nSamplesPerSec); srcformat.Format.nAvgBytesPerSec = FMOD_SWAPENDIAN_DWORD(srcformat.Format.nAvgBytesPerSec); srcformat.Format.nBlockAlign = FMOD_SWAPENDIAN_WORD (srcformat.Format.nBlockAlign); srcformat.Format.wBitsPerSample = FMOD_SWAPENDIAN_WORD (srcformat.Format.wBitsPerSample); srcformat.Format.cbSize = FMOD_SWAPENDIAN_WORD (srcformat.Format.cbSize); srcformat.Samples.wValidBitsPerSample = FMOD_SWAPENDIAN_WORD (srcformat.Samples.wValidBitsPerSample); srcformat.dwChannelMask = FMOD_SWAPENDIAN_DWORD(srcformat.dwChannelMask); #endif switch (srcformat.Format.wBitsPerSample) { case 4: { if (srcformat.Format.wFormatTag == 0x6666) { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_VAG; } else if (srcformat.Format.wFormatTag == 0x7777) { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_GCADPCM; } break; } case 8: { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM8; break; } case 16: { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM16; break; } case 24: { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM24; break; } case 32: { if (srcformat.Format.wFormatTag == WAVE_FORMAT_PCM) { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM32; } else if (srcformat.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCMFLOAT; } break; } } waveformat[mSampleID].channels = srcformat.Format.nChannels; waveformat[mSampleID].frequency = srcformat.Format.nSamplesPerSec; waveformat[mSampleID].blockalign = srcformat.Format.nBlockAlign; } /* DATA CHUNK */ else if (!FMOD_strncmp((const char *)chunk.id, "data", 4)) { SoundI::getSamplesFromBytes(chunk.size, &waveformat[mSampleID].lengthpcm, waveformat[mSampleID].channels, waveformat[mSampleID].format); result = mFile->tell(&mSample[mSampleID].mDataOffset); if (result != FMOD_OK) { return result; } } else if (!FMOD_strncmp((const char *)chunk.id, "INAM", 4)) { if (mInstrumentID < mNumInstruments) { FMOD_memset(mInstrument[mInstrumentID].mName, 0, FMOD_STRING_MAXNAMELEN); result = mFile->read(mInstrument[mInstrumentID].mName, 1, chunk.size, 0); if (result != FMOD_OK) { return result; } } else if (mSampleID < mNumSamples) { FMOD_memset(mSample[mSampleID].mName, 0, FMOD_STRING_MAXNAMELEN); result = mFile->read(mSample[mSampleID].mName, 1, chunk.size, 0); if (result != FMOD_OK) { return result; } FMOD_strncpy(waveformat[mSampleID].name, mSample[mSampleID].mName, FMOD_STRING_MAXNAMELEN); } } else if (!FMOD_strncmp((const char *)chunk.id, "IARL", 4) || !FMOD_strncmp((const char *)chunk.id, "IART", 4) || !FMOD_strncmp((const char *)chunk.id, "ICMS", 4) || !FMOD_strncmp((const char *)chunk.id, "ICMT", 4) || !FMOD_strncmp((const char *)chunk.id, "ICOP", 4) || !FMOD_strncmp((const char *)chunk.id, "ICRD", 4) || !FMOD_strncmp((const char *)chunk.id, "IENG", 4) || !FMOD_strncmp((const char *)chunk.id, "IGNR", 4) || !FMOD_strncmp((const char *)chunk.id, "IKEY", 4) || !FMOD_strncmp((const char *)chunk.id, "IMED", 4) || !FMOD_strncmp((const char *)chunk.id, "IPRD", 4) || !FMOD_strncmp((const char *)chunk.id, "ISBJ", 4) || !FMOD_strncmp((const char *)chunk.id, "ISFT", 4) || !FMOD_strncmp((const char *)chunk.id, "ISRC", 4) || !FMOD_strncmp((const char *)chunk.id, "ISRF", 4) || !FMOD_strncmp((const char *)chunk.id, "ITCH", 4)) { result = result; } else { mFile->seek(chunk.size, SEEK_CUR); if (result != FMOD_OK) { return result; } } offset += (chunk.size+sizeof(WAVE_CHUNK)); fileoffset += (chunk.size+sizeof(WAVE_CHUNK)); if (chunk.size & 1) { offset++; fileoffset++; } if (chunk.size < 0) { break; } //FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::parseRIFF", "offset = %d / %d\n", offset, chunksize)); } while (offset < chunksize && offset > 0 && !done); return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT CodecDLS::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo) { FMOD_RESULT result = FMOD_OK; WAVE_CHUNK chunk; char dls[4]; init(FMOD_SOUND_TYPE_DLS); FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::openInternal", "attempting to open as DLS..\n")); result = mFile->seek(0, SEEK_SET); if (result != FMOD_OK) { return result; } mSrcDataOffset = 0; mNumInstruments = 0; mNumSamples = 0; result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0); if (result != FMOD_OK) { return result; } if (FMOD_strncmp((const char *)chunk.id, "RIFF", 4)) { return FMOD_ERR_FORMAT; } result = mFile->read(dls, 1, 4, 0); if (result != FMOD_OK) { return result; } if (FMOD_strncmp(dls, "DLS ", 4)) { return FMOD_ERR_FORMAT; } #ifdef PLATFORM_ENDIAN_BIG chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size); #endif mSrcDataOffset = 0; mSampleID = 0; result = parseChunk(dls, chunk.size); if (result != FMOD_OK) { return result; } if (mNumInstruments <= 0) { return FMOD_ERR_FORMAT; } numsubsounds = mNumSamples; return result; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT CodecDLS::closeInternal() { if (waveformat) { FMOD_Memory_Free(waveformat); waveformat = 0; } if (mInstrument) { int count; for (count = 0; count < mNumInstruments; count++) { if (mInstrument[count].mRegion) { unsigned int region; /* Look for special drum articulators. */ for (region = 0; region < mInstrument[count].mHeader.cRegions; region++) { if (mInstrument[count].mRegion[region].mConnectionBlock) { FMOD_Memory_Free(mInstrument[count].mRegion[region].mConnectionBlock); } } FMOD_Memory_Free(mInstrument[count].mRegion); } if (mInstrument[count].mConnectionBlock) { FMOD_Memory_Free(mInstrument[count].mConnectionBlock); } } FMOD_Memory_Free(mInstrument); mInstrument = 0; } if (mSample) { FMOD_Memory_Free(mSample); mSample = 0; } return FMOD_OK; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT CodecDLS::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread) { FMOD_RESULT result = FMOD_OK; result = mFile->read(buffer, 1, sizebytes, bytesread); if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF) { return result; } /* PCM8 is stored in unsigned 8-bit, so convert it to signed 8-bit for FMOD */ if (waveformat[mCurrentIndex].format == FMOD_SOUND_FORMAT_PCM8) { unsigned char *wptr = (unsigned char *)buffer; for (unsigned int count = 0; count < *bytesread; count++) { *wptr++ ^= 128; } } else /* Must be PCM16 */ { #ifdef PLATFORM_ENDIAN_BIG { signed short *wptr = (signed short *)buffer; for (unsigned int count = 0; count < *bytesread >> 1; count++) { wptr[count] = FMOD_SWAPENDIAN_WORD(wptr[count]); } } #endif } return result; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT CodecDLS::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype) { FMOD_RESULT result = FMOD_OK; if (subsound < 0 || (numsubsounds && subsound >= numsubsounds)) { return FMOD_ERR_INVALID_POSITION; } if (mFile->mFlags & FMOD_FILE_SEEKABLE) { unsigned int posbytes; if (subsound != mCurrentIndex) { mCurrentIndex = subsound; } result = SoundI::getBytesFromSamples(position, &posbytes, waveformat[mCurrentIndex].channels, waveformat[mCurrentIndex].format); if (result != FMOD_OK) { return result; } posbytes += mSample[mCurrentIndex].mDataOffset; result = mFile->seek(posbytes, SEEK_SET); if (result != FMOD_OK) { return result; } } return result; } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT F_CALLBACK CodecDLS::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo) { CodecDLS *dls = (CodecDLS *)codec; return dls->openInternal(usermode, userexinfo); } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT F_CALLBACK CodecDLS::closeCallback(FMOD_CODEC_STATE *codec) { CodecDLS *dls = (CodecDLS *)codec; return dls->closeInternal(); } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT F_CALLBACK CodecDLS::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread) { CodecDLS *dls = (CodecDLS *)codec; return dls->readInternal(buffer, sizebytes, bytesread); } /* [ [DESCRIPTION] [PARAMETERS] [RETURN_VALUE] [REMARKS] [PLATFORMS] Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube [SEE_ALSO] ] */ FMOD_RESULT F_CALLBACK CodecDLS::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype) { CodecDLS *dls = (CodecDLS *)codec; return dls->setPositionInternal(subsound, position, postype); } } #endif