diff --git a/papers/format.md b/papers/format.md index 6281293ab..080914c1e 100644 --- a/papers/format.md +++ b/papers/format.md @@ -816,7 +816,47 @@ size | description 4?? | wavetable data ``` -# sample +# sample (>=102) + +this is the new sample storage format used in Furnace dev102 and higher. + +``` +size | description +-----|------------------------------------ + 4 | "SMP2" block ID + 4 | size of this block + STR | sample name + 4 | length + 4 | compatibility rate + 4 | C-4 rate + 1 | depth + | - 0: ZX Spectrum overlay drum (1-bit) + | - 1: 1-bit NES DPCM (1-bit) + | - 3: YMZ ADPCM + | - 4: QSound ADPCM + | - 5: ADPCM-A + | - 6: ADPCM-B + | - 8: 8-bit PCM + | - 9: BRR (SNES) + | - 10: VOX + | - 16: 16-bit PCM + 3 | reserved + 4 | loop start + | - -1 means no loop + 4 | loop end + | - -1 means no loop + 16 | sample presence bitfields + | - for future use. + | - indicates whether the sample should be present in the memory of a system. + | - read 4 32-bit numbers (for 4 memory banks per system, e.g. YM2610 + | does ADPCM-A and ADPCM-B on separate memory banks). + ??? | sample data + | - size is length +``` + +# old sample (<102) + +this format is present when saving using previous Furnace versions. ``` size | description @@ -825,7 +865,7 @@ size | description 4 | size of this block STR | sample name 4 | length - 4 | rate + 4 | compatibility rate 2 | volume (<58) or reserved 2 | pitch (<58) or reserved 1 | depth diff --git a/src/engine/engine.h b/src/engine/engine.h index 896c083a2..21fde0a70 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "0.6pre1 (dev101)" -#define DIV_ENGINE_VERSION 101 +#define DIV_VERSION "0.6pre1 (dev102)" +#define DIV_ENGINE_VERSION 102 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 40932a378..110259050 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1619,51 +1619,67 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } reader.read(magic,4); - if (strcmp(magic,"SMPL")!=0) { + if (strcmp(magic,"SMPL")!=0 && strcmp(magic,"SMP2")!=0) { logE("%d: invalid sample header!",i); lastError="invalid sample header!"; ds.unload(); delete[] file; return false; } + bool isNewSample=(strcmp(magic,"SMP2")==0); reader.readI(); DivSample* sample=new DivSample; logD("reading sample %d at %x...",i,samplePtr[i]); + if (!isNewSample) logV("(old sample)"); sample->name=reader.readString(); - sample->samples=sample->loopEnd=reader.readI(); + sample->samples=reader.readI(); + if (!isNewSample) { + sample->loopEnd=sample->samples; + } sample->rate=reader.readI(); - if (ds.version<58) { - vol=reader.readS(); - pitch=reader.readS(); - } else { - reader.readI(); - } - sample->depth=(DivSampleDepth)reader.readC(); - // reserved - reader.readC(); + if (isNewSample) { + sample->centerRate=reader.readI(); + sample->depth=(DivSampleDepth)reader.readC(); - // while version 32 stored this value, it was unused. - if (ds.version>=38) { - sample->centerRate=(unsigned short) reader.readS(); - } else { - reader.readS(); - } + // reserved + reader.readC(); + reader.readC(); + reader.readC(); - if (ds.version>=19) { sample->loopStart=reader.readI(); + sample->loopEnd=reader.readI(); + + for (int i=0; i<4; i++) { + reader.readI(); + } } else { - reader.readI(); + if (ds.version<58) { + vol=reader.readS(); + pitch=reader.readS(); + } else { + reader.readI(); + } + sample->depth=(DivSampleDepth)reader.readC(); + + // reserved + reader.readC(); + + // while version 32 stored this value, it was unused. + if (ds.version>=38) { + sample->centerRate=(unsigned short)reader.readS(); + } else { + reader.readS(); + } + + if (ds.version>=19) { + sample->loopStart=reader.readI(); + } else { + reader.readI(); + } } -/* - if (ds.version>=100) { - sample->loopEnd=reader.readI(); - } else { - reader.readI(); - } -*/ if (ds.version>=58) { // modern sample sample->init(sample->samples); reader.read(sample->getCurBuf(),sample->getCurBufLen()); @@ -3038,19 +3054,24 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { for (int i=0; itell()); - w->write("SMPL",4); + w->write("SMP2",4); blockStartSeek=w->tell(); w->writeI(0); w->writeString(sample->name,false); w->writeI(sample->samples); w->writeI(sample->rate); - w->writeI(0); // reserved (for now) + w->writeI(sample->centerRate); w->writeC(sample->depth); + w->writeC(0); // reserved + w->writeC(0); w->writeC(0); - w->writeS(sample->centerRate); w->writeI(sample->loopStart); - //w->writeI(sample->loopEnd); + w->writeI(sample->loopEnd); + + for (int i=0; i<4; i++) { + w->writeI(0xffffffff); + } w->write(sample->getCurBuf(),sample->getCurBufLen());