diff --git a/papers/newIns.md b/papers/newIns.md index 7b6512f0f..6a4a94198 100644 --- a/papers/newIns.md +++ b/papers/newIns.md @@ -151,8 +151,10 @@ the following feature codes are recognized: - `N1`: Namco 163 ins data - `FD`: FDS/Virtual Boy ins data - `WS`: wavetable synth data -- `SL`: list of samples -- `WL`: list of wavetables +- `SL`: list of samples (<233) +- `WL`: list of wavetables (<233) +- `LS`: list of samples (>=233) +- `LW`: list of wavetables (>=233) - `MP`: MultiPCM ins data - `SU`: Sound Unit ins data - `ES`: ES5506 ins data @@ -555,7 +557,7 @@ size | description 1 | parameter 4 ``` -# list of samples (SL) +# old list of samples (SL) (<233) ``` size | description @@ -566,7 +568,7 @@ size | description | - these use the Furnace sample format. ``` -# list of wavetables (WL) +# old list of wavetables (WL) (<233) ``` size | description @@ -577,6 +579,28 @@ size | description | - these use the Furnace wavetable format. ``` +# new list of samples (LS) (>=233) + +``` +size | description +-----|------------------------------------ + 2 | number of samples + 2?? | sample indexes... + 4?? | pointers to samples... + | - these use the Furnace sample format. +``` + +# new list of wavetables (LW) (>=233) + +``` +size | description +-----|------------------------------------ + 2 | number of wavetables + 2?? | wavetable indexes... + 4?? | pointers to wavetables... + | - these use the Furnace wavetable format. +``` + # MultiPCM data (MP) ``` diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 9aa669974..315f77c4b 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -932,11 +932,13 @@ void DivEngine::delUnusedWaves() { } void DivEngine::delUnusedSamples() { + if (song.sample.empty()) return; + BUSY_BEGIN; saveLock.lock(); - bool isUsed[256]; - memset(isUsed,0,256*sizeof(bool)); + bool* isUsed=new bool[song.sample.size()]; + memset(isUsed,0,song.sample.size()*sizeof(bool)); // scan in instruments for (DivInstrument* i: song.ins) { @@ -1029,6 +1031,8 @@ void DivEngine::delUnusedSamples() { // render renderSamples(); + delete[] isUsed; + saveLock.unlock(); BUSY_END; } @@ -2707,7 +2711,7 @@ void DivEngine::delInstrument(int index) { } int DivEngine::addWave() { - if (song.wave.size()>=256) { + if (song.wave.size()>=32768) { lastError=_("too many wavetables!"); return -1; } @@ -2724,7 +2728,7 @@ int DivEngine::addWave() { } int DivEngine::addWavePtr(DivWavetable* which) { - if (song.wave.size()>=256) { + if (song.wave.size()>=32768) { lastError=_("too many wavetables!"); delete which; return -1; diff --git a/src/engine/engine.h b/src/engine/engine.h index 5594ad359..74b8064f5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -54,8 +54,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "dev232" -#define DIV_ENGINE_VERSION 232 +#define DIV_VERSION "dev233" +#define DIV_ENGINE_VERSION 233 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps/ftm.cpp b/src/engine/fileOps/ftm.cpp index f1ee0eb15..b471959d6 100644 --- a/src/engine/fileOps/ftm.cpp +++ b/src/engine/fileOps/ftm.cpp @@ -1089,7 +1089,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si ins->fds.modSpeed = reader.readI(); ins->fds.modDepth = reader.readI(); reader.readI(); // this is delay. currently ignored. TODO. - if (ds.wave.size()>=256) { + if (ds.wave.size()>=32768) { logW("too many waves! ignoring..."); delete wave; } else { @@ -1210,7 +1210,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si wave->data[jj] = val; } - if (ds.wave.size()<256) { + if (ds.wave.size()<32768) { ds.wave.push_back(wave); } else { logW("too many waves..."); diff --git a/src/engine/fileOps/fur.cpp b/src/engine/fileOps/fur.cpp index 2193c0510..e67360108 100644 --- a/src/engine/fileOps/fur.cpp +++ b/src/engine/fileOps/fur.cpp @@ -692,9 +692,9 @@ void DivEngine::convertOldFlags(unsigned int oldFlags, DivConfig& newFlags, DivS } bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { - unsigned int insPtr[256]; - unsigned int wavePtr[256]; - unsigned int samplePtr[256]; + std::vector insPtr; + std::vector wavePtr; + std::vector samplePtr; unsigned int subSongPtr[256]; unsigned int sysFlagsPtr[DIV_MAX_CHIPS]; unsigned int assetDirPtr[3]; @@ -934,13 +934,13 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { delete[] file; return false; } - if (ds.waveLen<0 || ds.waveLen>256) { + if (ds.waveLen<0 || ds.waveLen>32768) { logE("invalid wavetable count!"); lastError="invalid wavetable count!"; delete[] file; return false; } - if (ds.sampleLen<0 || ds.sampleLen>256) { + if (ds.sampleLen<0 || ds.sampleLen>32768) { logE("invalid sample count!"); lastError="invalid sample count!"; delete[] file; @@ -1142,14 +1142,17 @@ bool DivEngine::loadFur(unsigned char* file, size_t len, int variantID) { } // pointers + insPtr.reserve(ds.insLen); for (int i=0; i256) { - logE("maximum number of wavetables is 256!"); - lastError="maximum number of wavetables is 256"; + if (song.wave.size()>32768) { + logE("maximum number of wavetables is 32768!"); + lastError="maximum number of wavetables is 32768"; saveLock.unlock(); return NULL; } - if (song.sample.size()>256) { - logE("maximum number of samples is 256!"); - lastError="maximum number of samples is 256"; + if (song.sample.size()>32768) { + logE("maximum number of samples is 32768!"); + lastError="maximum number of samples is 32768"; saveLock.unlock(); return NULL; } diff --git a/src/engine/fileOps/xm.cpp b/src/engine/fileOps/xm.cpp index 7579c04b5..0a798d090 100644 --- a/src/engine/fileOps/xm.cpp +++ b/src/engine/fileOps/xm.cpp @@ -1334,7 +1334,7 @@ bool DivEngine::loadXM(unsigned char* file, size_t len) { } ds.sampleLen=ds.sample.size(); - if (ds.sampleLen>256) { + if (ds.sampleLen>32768) { logE("too many samples!"); lastError="too many samples"; ds.unload(); diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index bdb16391c..d76f21997 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -858,9 +858,11 @@ void DivInstrument::writeFeatureWS(SafeWriter* w) { FEATURE_END; } -size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, const DivSong* song) { - bool sampleUsed[256]; - memset(sampleUsed,0,256*sizeof(bool)); +size_t DivInstrument::writeFeatureLS(SafeWriter* w, std::vector& list, const DivSong* song) { + if (song==NULL) return 0; + + bool* sampleUsed=new bool[song->sample.size()]; + memset(sampleUsed,0,song->sample.size()*sizeof(bool)); if (amiga.initSample>=0 && amiga.initSample<(int)song->sample.size()) { sampleUsed[amiga.initSample]=true; @@ -880,14 +882,16 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, cons } } + delete[] sampleUsed; + if (list.empty()) return 0; FEATURE_BEGIN("SL"); - w->writeC(list.size()); + w->writeS(list.size()); for (int i: list) { - w->writeC(i); + w->writeS(i); } size_t ret=w->tell(); @@ -902,9 +906,11 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, cons return ret; } -size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector& list, const DivSong* song) { - bool waveUsed[256]; - memset(waveUsed,0,256*sizeof(bool)); +size_t DivInstrument::writeFeatureLW(SafeWriter* w, std::vector& list, const DivSong* song) { + if (song==NULL) return 0; + + bool* waveUsed=new bool[song->wave.size()]; + memset(waveUsed,0,song->wave.size()*sizeof(bool)); for (int i=0; i=0 && std.waveMacro.val[i]<(int)song->wave.size()) { @@ -931,10 +937,10 @@ size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector& list, cons FEATURE_BEGIN("WL"); - w->writeC(list.size()); + w->writeS(list.size()); for (int i: list) { - w->writeC(i); + w->writeS(i); } size_t ret=w->tell(); @@ -1621,10 +1627,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo writeFeatureWS(w); } if (featureSL) { - slSeek=writeFeatureSL(w,sampleList,song); + slSeek=writeFeatureLS(w,sampleList,song); } if (featureWL) { - wlSeek=writeFeatureWL(w,waveList,song); + wlSeek=writeFeatureLW(w,waveList,song); } if (featureMP) { writeFeatureMP(w); @@ -2275,17 +2281,17 @@ void DivInstrument::readFeatureWS(SafeReader& reader, short version) { void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short version) { READ_FEAT_BEGIN; - unsigned int samplePtr[256]; - unsigned char sampleIndex[256]; - unsigned char sampleRemap[256]; - memset(samplePtr,0,256*sizeof(unsigned int)); - memset(sampleIndex,0,256); - memset(sampleRemap,0,256); + unsigned int* samplePtr=new unsigned int[32768]; + unsigned short* sampleIndex=new unsigned short[65536]; + unsigned short* sampleRemap=new unsigned short[65536]; + memset(samplePtr,0,32768*sizeof(unsigned int)); + memset(sampleIndex,0,65536*sizeof(unsigned short)); + memset(sampleRemap,0,65536*sizeof(unsigned short)); unsigned char sampleCount=reader.readC(); for (int i=0; isample.size()>=256) { + if (song->sample.size()>=32768) { break; } DivSample* sample=new DivSample; @@ -2316,35 +2322,39 @@ void DivInstrument::readFeatureSL(SafeReader& reader, DivSong* song, short versi reader.seek(lastSeek,SEEK_SET); // re-map samples - if (amiga.initSample>=0 && amiga.initSample<256) { + if (amiga.initSample>=0) { amiga.initSample=sampleRemap[amiga.initSample]; } if (amiga.useNoteMap) { for (int i=0; i<120; i++) { - if (amiga.noteMap[i].map>=0 && amiga.noteMap[i].map<256) { + if (amiga.noteMap[i].map>=0) { amiga.noteMap[i].map=sampleRemap[amiga.noteMap[i].map]; } } } + delete[] samplePtr; + delete[] sampleIndex; + delete[] sampleRemap; + READ_FEAT_END; } void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short version) { READ_FEAT_BEGIN; - unsigned int wavePtr[256]; - unsigned char waveIndex[256]; - unsigned char waveRemap[256]; - memset(wavePtr,0,256*sizeof(unsigned int)); - memset(waveIndex,0,256); - memset(waveRemap,0,256); + unsigned int* wavePtr=new unsigned int[32768]; + unsigned short* waveIndex=new unsigned short[65536]; + unsigned short* waveRemap=new unsigned short[65536]; + memset(wavePtr,0,32768*sizeof(unsigned int)); + memset(waveIndex,0,65536*sizeof(unsigned short)); + memset(waveRemap,0,65536*sizeof(unsigned short)); unsigned char waveCount=reader.readC(); for (int i=0; iwave.size()>=256) { + if (song->wave.size()>=32768) { break; } DivWavetable* wave=new DivWavetable; @@ -2376,16 +2386,164 @@ void DivInstrument::readFeatureWL(SafeReader& reader, DivSong* song, short versi // re-map wavetables if (ws.enabled) { - if (ws.wave1>=0 && ws.wave1<256) ws.wave1=waveRemap[ws.wave1]; + if (ws.wave1>=0 && ws.wave1<32768) ws.wave1=waveRemap[ws.wave1]; if (ws.effect&0x80) { - if (ws.wave2>=0 && ws.wave2<256) ws.wave2=waveRemap[ws.wave2]; + if (ws.wave2>=0 && ws.wave2<32768) ws.wave2=waveRemap[ws.wave2]; } } - if (n163.wave>=0 && n163.wave<256) n163.wave=waveRemap[n163.wave]; + if (n163.wave>=0 && n163.wave<32768) n163.wave=waveRemap[n163.wave]; for (int i=0; i=0 && std.waveMacro.val[i]<256) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]]; + if (std.waveMacro.val[i]>=0 && std.waveMacro.val[i]<32768) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]]; } + delete[] wavePtr; + delete[] waveIndex; + delete[] waveRemap; + + READ_FEAT_END; +} + +// new versions +void DivInstrument::readFeatureLS(SafeReader& reader, DivSong* song, short version) { + READ_FEAT_BEGIN; + + unsigned int* samplePtr=new unsigned int[32768]; + unsigned short* sampleIndex=new unsigned short[65536]; + unsigned short* sampleRemap=new unsigned short[65536]; + memset(samplePtr,0,32768*sizeof(unsigned int)); + memset(sampleIndex,0,65536*sizeof(unsigned short)); + memset(sampleRemap,0,65536*sizeof(unsigned short)); + + unsigned short sampleCount=reader.readS(); + + if (sampleCount>32768) { + logW("invalid sample count!"); + delete[] samplePtr; + delete[] sampleIndex; + delete[] sampleRemap; + READ_FEAT_END; + return; + } + + for (int i=0; isample.size()>=32768) { + break; + } + DivSample* sample=new DivSample; + int sampleCount=(int)song->sample.size(); + + DivDataErrors result=sample->readSampleData(reader,version); + if (result==DIV_DATA_SUCCESS) { + song->sample.push_back(sample); + song->sampleLen=sampleCount+1; + sampleRemap[sampleIndex[i]]=sampleCount; + } else { + delete sample; + sampleRemap[sampleIndex[i]]=0; + } + } + + reader.seek(lastSeek,SEEK_SET); + + // re-map samples + if (amiga.initSample>=0) { + amiga.initSample=sampleRemap[amiga.initSample]; + } + + if (amiga.useNoteMap) { + for (int i=0; i<120; i++) { + if (amiga.noteMap[i].map>=0) { + amiga.noteMap[i].map=sampleRemap[amiga.noteMap[i].map]; + } + } + } + + delete[] samplePtr; + delete[] sampleIndex; + delete[] sampleRemap; + + READ_FEAT_END; +} + +void DivInstrument::readFeatureLW(SafeReader& reader, DivSong* song, short version) { + READ_FEAT_BEGIN; + + unsigned int* wavePtr=new unsigned int[32768]; + unsigned short* waveIndex=new unsigned short[65536]; + unsigned short* waveRemap=new unsigned short[65536]; + memset(wavePtr,0,32768*sizeof(unsigned int)); + memset(waveIndex,0,65536*sizeof(unsigned short)); + memset(waveRemap,0,65536*sizeof(unsigned short)); + + unsigned short waveCount=reader.readS(); + + if (waveCount>32768) { + logW("invalid wave count!"); + delete[] wavePtr; + delete[] waveIndex; + delete[] waveRemap; + READ_FEAT_END; + return; + } + + for (int i=0; iwave.size()>=32768) { + break; + } + DivWavetable* wave=new DivWavetable; + int waveCount=(int)song->wave.size(); + + DivDataErrors result=wave->readWaveData(reader,version); + if (result==DIV_DATA_SUCCESS) { + song->wave.push_back(wave); + song->waveLen=waveCount+1; + waveRemap[waveIndex[i]]=waveCount; + } else { + delete wave; + waveRemap[waveIndex[i]]=0; + } + } + + reader.seek(lastSeek,SEEK_SET); + + // re-map wavetables + if (ws.enabled) { + if (ws.wave1>=0 && ws.wave1<32768) ws.wave1=waveRemap[ws.wave1]; + if (ws.effect&0x80) { + if (ws.wave2>=0 && ws.wave2<32768) ws.wave2=waveRemap[ws.wave2]; + } + } + if (n163.wave>=0 && n163.wave<32768) n163.wave=waveRemap[n163.wave]; + for (int i=0; i=0 && std.waveMacro.val[i]<32768) std.waveMacro.val[i]=waveRemap[std.waveMacro.val[i]]; + } + + delete[] wavePtr; + delete[] waveIndex; + delete[] waveRemap; + READ_FEAT_END; } @@ -2647,10 +2805,14 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b readFeatureFD(reader,version); } else if (memcmp(featCode,"WS",2)==0) { // WaveSynth readFeatureWS(reader,version); - } else if (memcmp(featCode,"SL",2)==0 && fui && song!=NULL) { // sample list + } else if (memcmp(featCode,"SL",2)==0 && fui && song!=NULL) { // sample list (old) readFeatureSL(reader,song,version); - } else if (memcmp(featCode,"WL",2)==0 && fui && song!=NULL) { // wave list + } else if (memcmp(featCode,"WL",2)==0 && fui && song!=NULL) { // wave list (old) readFeatureWL(reader,song,version); + } else if (memcmp(featCode,"LS",2)==0 && fui && song!=NULL) { // sample list (new) + readFeatureLS(reader,song,version); + } else if (memcmp(featCode,"LW",2)==0 && fui && song!=NULL) { // wave list (new) + readFeatureLW(reader,song,version); } else if (memcmp(featCode,"MP",2)==0) { // MultiPCM readFeatureMP(reader,version); } else if (memcmp(featCode,"SU",2)==0) { // Sound Unit diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 2c7d91be7..dfabfeaef 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -1097,8 +1097,8 @@ struct DivInstrument : DivInstrumentPOD { void writeFeatureN1(SafeWriter* w); void writeFeatureFD(SafeWriter* w); void writeFeatureWS(SafeWriter* w); - size_t writeFeatureSL(SafeWriter* w, std::vector& list, const DivSong* song); - size_t writeFeatureWL(SafeWriter* w, std::vector& list, const DivSong* song); + size_t writeFeatureLS(SafeWriter* w, std::vector& list, const DivSong* song); + size_t writeFeatureLW(SafeWriter* w, std::vector& list, const DivSong* song); void writeFeatureMP(SafeWriter* w); void writeFeatureSU(SafeWriter* w); void writeFeatureES(SafeWriter* w); @@ -1123,6 +1123,8 @@ struct DivInstrument : DivInstrumentPOD { void readFeatureWS(SafeReader& reader, short version); void readFeatureSL(SafeReader& reader, DivSong* song, short version); void readFeatureWL(SafeReader& reader, DivSong* song, short version); + void readFeatureLS(SafeReader& reader, DivSong* song, short version); + void readFeatureLW(SafeReader& reader, DivSong* song, short version); void readFeatureMP(SafeReader& reader, short version); void readFeatureSU(SafeReader& reader, short version); void readFeatureES(SafeReader& reader, short version); diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 3ed2a888b..7081a8e1f 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -764,8 +764,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write pendingFreq[streamID]=write.val; } else { DivSample* sample=song.sample[write.val]; - int pos=sampleOff8[write.val&0xff]+setPos[streamID]; - int len=(int)sampleLen8[write.val&0xff]-setPos[streamID]; + int pos=sampleOff8[write.val&0x7fff]+setPos[streamID]; + int len=(int)sampleLen8[write.val&0x7fff]-setPos[streamID]; if (len<0) len=0; @@ -807,8 +807,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write loopFreq[streamID]=realFreq; if (pendingFreq[streamID]!=-1) { DivSample* sample=song.sample[pendingFreq[streamID]]; - int pos=sampleOff8[pendingFreq[streamID]&0xff]+setPos[streamID]; - int len=(int)sampleLen8[pendingFreq[streamID]&0xff]-setPos[streamID]; + int pos=sampleOff8[pendingFreq[streamID]&0x7fff]+setPos[streamID]; + int len=(int)sampleLen8[pendingFreq[streamID]&0x7fff]-setPos[streamID]; if (len<0) len=0; @@ -859,8 +859,8 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write if (playingSample[streamID]!=-1 && pendingFreq[streamID]==-1) { // play the sample again DivSample* sample=song.sample[playingSample[streamID]]; - int pos=sampleOff8[playingSample[streamID]&0xff]+setPos[streamID]; - int len=(int)sampleLen8[playingSample[streamID]&0xff]-setPos[streamID]; + int pos=sampleOff8[playingSample[streamID]&0x7fff]+setPos[streamID]; + int len=(int)sampleLen8[playingSample[streamID]&0x7fff]-setPos[streamID]; if (len<0) len=0; @@ -1329,9 +1329,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p int loopTickSong=-1; int songTick=0; - unsigned int sampleOff8[256]; - unsigned int sampleLen8[256]; - unsigned int sampleOffSegaPCM[256]; + unsigned int* sampleOff8=new unsigned int[32768]; + unsigned int* sampleLen8=new unsigned int[32768]; + unsigned int* sampleOffSegaPCM=new unsigned int[32768]; SafeWriter* w=new SafeWriter; w->init(); @@ -2202,9 +2202,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p unsigned int songOff=w->tell(); // initialize sample offsets - memset(sampleOff8,0,256*sizeof(unsigned int)); - memset(sampleLen8,0,256*sizeof(unsigned int)); - memset(sampleOffSegaPCM,0,256*sizeof(unsigned int)); + memset(sampleOff8,0,32768*sizeof(unsigned int)); + memset(sampleLen8,0,32768*sizeof(unsigned int)); + memset(sampleOffSegaPCM,0,32768*sizeof(unsigned int)); // write samples unsigned int sampleSeek=0; @@ -2968,6 +2968,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p logI("%d register writes total.",writeCount); + delete[] sampleOff8; + delete[] sampleLen8; + delete[] sampleOffSegaPCM; + BUSY_END; return w; }