DragonNest/Common/FMODEngine/FMOD_static/src/fmod_codec_dls.cpp
2024-12-19 09:48:26 +08:00

971 lines
32 KiB
C++

#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 <stdio.h>
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