From d6ae735ffe5a4064ebb9ad9b4845dfd1424ee3b1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 20 Nov 2022 19:19:24 -0500 Subject: [PATCH] dev126 - new ins format --- src/engine/fileOps.cpp | 168 ++------------------------------- src/engine/instrument.cpp | 192 ++++++++++++++++++++++++++++++++------ src/engine/instrument.h | 8 +- src/engine/sample.cpp | 179 +++++++++++++++++++++++++++++++++++ src/engine/sample.h | 16 ++++ src/gui/dataList.cpp | 9 ++ src/gui/doAction.cpp | 3 + src/gui/gui.cpp | 21 ++++- src/gui/gui.h | 2 + src/gui/guiConst.cpp | 3 +- src/gui/insEdit.cpp | 3 + 11 files changed, 408 insertions(+), 196 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index a5502040b..15bb77113 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2348,142 +2348,24 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { // read samples for (int i=0; ireadSampleData(reader,ds.version)!=DIV_DATA_SUCCESS) { + lastError="invalid sample header/data!"; ds.unload(); + delete sample; 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=reader.readI(); - if (!isNewSample) { - sample->loopEnd=sample->samples; - } - sample->rate=reader.readI(); - - if (isNewSample) { - sample->centerRate=reader.readI(); - sample->depth=(DivSampleDepth)reader.readC(); - if (ds.version>=123) { - sample->loopMode=(DivSampleLoopMode)reader.readC(); - } else { - sample->loopMode=DIV_SAMPLE_LOOP_FORWARD; - reader.readC(); - } - - // reserved - reader.readC(); - reader.readC(); - - sample->loopStart=reader.readI(); - sample->loopEnd=reader.readI(); - sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); - - for (int i=0; i<4; i++) { - reader.readI(); - } - } else { - 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(); - sample->loop=(sample->loopStart>=0)&&(sample->loopEnd>=0); - } else { - reader.readI(); - } - } - - if (ds.version>=58) { // modern sample - sample->init(sample->samples); - reader.read(sample->getCurBuf(),sample->getCurBufLen()); -#ifdef TA_BIG_ENDIAN - // convert 16-bit samples to big-endian - if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); - size_t sampleBufLen=sample->getCurBufLen(); - for (size_t pos=0; possamples; - short* data=new short[length]; - reader.read(data,2*length); - -#ifdef TA_BIG_ENDIAN - // convert 16-bit samples to big-endian - for (int pos=0; pos>8)|((unsigned short)data[pos]<<8); - } -#endif - - if (pitch!=5) { - logD("%d: scaling from %d...",i,pitch); - } - - // render data - if (sample->depth!=DIV_SAMPLE_DEPTH_8BIT && sample->depth!=DIV_SAMPLE_DEPTH_16BIT) { - logW("%d: sample depth is wrong! (%d)",i,sample->depth); - sample->depth=DIV_SAMPLE_DEPTH_16BIT; - } - sample->samples=(double)sample->samples/samplePitches[pitch]; - sample->init(sample->samples); - - unsigned int k=0; - float mult=(float)(vol)/50.0f; - for (double j=0; j=sample->samples) { - break; - } - if (sample->depth==DIV_SAMPLE_DEPTH_8BIT) { - float next=(float)(data[(unsigned int)j]-0x80)*mult; - sample->data8[k++]=fmin(fmax(next,-128),127); - } else { - float next=(float)data[(unsigned int)j]*mult; - sample->data16[k++]=fmin(fmax(next,-32768),32767); - } - } - - delete[] data; - } ds.sample.push_back(sample); } @@ -4635,45 +4517,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { for (int i=0; itell()); - 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(sample->centerRate); - w->writeC(sample->depth); - w->writeC(sample->loopMode); - w->writeC(0); // reserved - w->writeC(0); - w->writeI(sample->loop?sample->loopStart:-1); - w->writeI(sample->loop?sample->loopEnd:-1); - - for (int i=0; i<4; i++) { - w->writeI(0xffffffff); - } - -#ifdef TA_BIG_ENDIAN - // store 16-bit samples as little-endian - if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); - size_t bufLen=sample->getCurBufLen(); - for (size_t i=0; iwriteC(sampleBuf[i+1]); - w->writeC(sampleBuf[i]); - } - } else { - w->write(sample->getCurBuf(),sample->getCurBufLen()); - } -#else - w->write(sample->getCurBuf(),sample->getCurBufLen()); -#endif - - blockEndSeek=w->tell(); - w->seek(blockStartSeek,SEEK_SET); - w->writeI(blockEndSeek-blockStartSeek-4); - w->seek(0,SEEK_END); + sample->putSampleData(w); } /// PATTERN diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 06fce17de..3bba85340 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -549,8 +549,6 @@ void DivInstrument::writeFeatureWS(SafeWriter* w) { } size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, const DivSong* song) { - FEATURE_BEGIN("SL"); - bool sampleUsed[256]; memset(sampleUsed,0,256*sizeof(bool)); @@ -572,6 +570,10 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, cons } } + if (list.empty()) return 0; + + FEATURE_BEGIN("SL"); + w->writeC(list.size()); for (int i: list) { @@ -591,8 +593,6 @@ size_t DivInstrument::writeFeatureSL(SafeWriter* w, std::vector& list, cons } size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector& list, const DivSong* song) { - FEATURE_BEGIN("WL"); - bool waveUsed[256]; memset(waveUsed,0,256*sizeof(bool)); @@ -617,6 +617,10 @@ size_t DivInstrument::writeFeatureWL(SafeWriter* w, std::vector& list, cons } } + if (list.empty()) return 0; + + FEATURE_BEGIN("WL"); + w->writeC(list.size()); for (int i: list) { @@ -687,9 +691,14 @@ void DivInstrument::writeFeatureX1(SafeWriter* w) { void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { size_t blockStartSeek=0; size_t blockEndSeek=0; + size_t slSeek=0; + size_t wlSeek=0; std::vector waveList; std::vector sampleList; + std::vector wavePtr; + std::vector samplePtr; + if (fui) { w->write("FINS",4); } else { @@ -747,17 +756,21 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { break; case DIV_INS_AMIGA: featureSM=true; + if (!amiga.useWave) featureSL=true; break; case DIV_INS_PCE: checkForWL=true; featureSM=true; + if (amiga.useSample) featureSL=true; if (ws.enabled) featureWS=true; break; case DIV_INS_AY: featureSM=true; + if (amiga.useSample) featureSL=true; break; case DIV_INS_AY8930: featureSM=true; + if (amiga.useSample) featureSL=true; break; case DIV_INS_TIA: break; @@ -769,6 +782,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { break; case DIV_INS_VRC6: featureSM=true; + if (amiga.useSample) featureSL=true; break; case DIV_INS_OPLL: featureFM=true; @@ -807,36 +821,44 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { case DIV_INS_SWAN: checkForWL=true; featureSM=true; + if (amiga.useSample) featureSL=true; if (ws.enabled) featureWS=true; break; case DIV_INS_MIKEY: featureSM=true; + if (amiga.useSample) featureSL=true; break; case DIV_INS_VERA: break; case DIV_INS_X1_010: checkForWL=true; featureX1=true; + featureSM=true; + if (amiga.useSample) featureSL=true; if (ws.enabled) featureWS=true; break; case DIV_INS_VRC6_SAW: break; case DIV_INS_ES5506: featureSM=true; + featureSL=true; featureES=true; break; case DIV_INS_MULTIPCM: featureSM=true; + featureSL=true; featureMP=true; break; case DIV_INS_SNES: featureSM=true; + if (!amiga.useWave) featureSL=true; featureSN=true; checkForWL=true; if (ws.enabled) featureWS=true; break; case DIV_INS_SU: featureSM=true; + if (amiga.useSample) featureSL=true; featureSU=true; break; case DIV_INS_NAMCO: @@ -854,27 +876,35 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { break; case DIV_INS_MSM6258: featureSM=true; + featureSL=true; break; case DIV_INS_MSM6295: featureSM=true; + featureSL=true; break; case DIV_INS_ADPCMA: featureSM=true; + featureSL=true; break; case DIV_INS_ADPCMB: featureSM=true; + featureSL=true; break; case DIV_INS_SEGAPCM: featureSM=true; + featureSL=true; break; case DIV_INS_QSOUND: featureSM=true; + featureSL=true; break; case DIV_INS_YMZ280B: featureSM=true; + featureSL=true; break; case DIV_INS_RF5C68: featureSM=true; + featureSL=true; break; case DIV_INS_MSM5232: break; @@ -1049,10 +1079,10 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { writeFeatureWS(w); } if (featureSL) { - writeFeatureSL(w,sampleList,song); + slSeek=writeFeatureSL(w,sampleList,song); } if (featureWL) { - writeFeatureWL(w,waveList,song); + wlSeek=writeFeatureWL(w,waveList,song); } if (featureMP) { writeFeatureMP(w); @@ -1069,7 +1099,44 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song) { if (fui && (featureSL || featureWL)) { w->write("EN",2); - // TODO: write wave/sample data here + + if (wlSeek!=0 && !waveList.empty()) { + for (int i: waveList) { + if (i<0 || i>=(int)song->wave.size()) { + wavePtr.push_back(0); + continue; + } + DivWavetable* wave=song->wave[i]; + + wavePtr.push_back(w->tell()); + wave->putWaveData(w); + } + + w->seek(wlSeek,SEEK_SET); + for (unsigned int i: wavePtr) { + w->writeI(i); + } + w->seek(0,SEEK_END); + } + + if (slSeek!=0 && !sampleList.empty()) { + for (int i: sampleList) { + if (i<0 || i>=(int)song->sample.size()) { + samplePtr.push_back(0); + continue; + } + DivSample* sample=song->sample[i]; + + samplePtr.push_back(w->tell()); + sample->putSampleData(w); + } + + w->seek(slSeek,SEEK_SET); + for (unsigned int i: samplePtr) { + w->writeI(i); + } + w->seek(0,SEEK_END); + } } blockEndSeek=w->tell(); @@ -2204,13 +2271,15 @@ void DivInstrument::readFeatureWS(SafeReader& reader) { READ_FEAT_END; } -void DivInstrument::readFeatureSL(SafeReader& reader, const DivSong* song) { +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 char sampleCount=reader.readC(); @@ -2223,20 +2292,53 @@ void DivInstrument::readFeatureSL(SafeReader& reader, const DivSong* song) { size_t lastSeek=reader.tell(); - // TODO: load samples here + // load samples + for (int i=0; isample.size()>=256) { + 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_CUR); + // re-map samples + if (amiga.initSample>=0 && amiga.initSample<256) { + 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) { + amiga.noteMap[i].map=sampleRemap[amiga.noteMap[i].map]; + } + } + } + READ_FEAT_END; } -void DivInstrument::readFeatureWL(SafeReader& reader, const DivSong* song) { +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 char waveCount=reader.readC(); @@ -2249,10 +2351,40 @@ void DivInstrument::readFeatureWL(SafeReader& reader, const DivSong* song) { size_t lastSeek=reader.tell(); - // TODO: load samples here + // load wavetables + for (int i=0; iwave.size()>=256) { + 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_CUR); + // re-map wavetables + if (ws.enabled) { + if (ws.wave1>=0 && ws.wave1<256) ws.wave1=waveRemap[ws.wave1]; + if (ws.effect&0x80) { + if (ws.wave2>=0 && ws.wave2<256) ws.wave2=waveRemap[ws.wave2]; + } + } + if (n163.wave>=0 && n163.wave<256) 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]]; + } + READ_FEAT_END; } @@ -2358,9 +2490,9 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b } else if (memcmp(featCode,"WS",2)==0) { // WaveSynth readFeatureWS(reader); } else if (memcmp(featCode,"SL",2)==0 && fui && song!=NULL) { // sample list - readFeatureSL(reader,NULL); + readFeatureSL(reader,song,version); } else if (memcmp(featCode,"WL",2)==0 && fui && song!=NULL) { // wave list - readFeatureWL(reader,NULL); + readFeatureWL(reader,song,version); } else if (memcmp(featCode,"MP",2)==0) { // MultiPCM readFeatureMP(reader); } else if (memcmp(featCode,"SU",2)==0) { // Sound Unit @@ -3118,30 +3250,32 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version, DivS return readInsDataOld(reader,version); } -bool DivInstrument::save(const char* path) { +bool DivInstrument::save(const char* path, bool oldFormat, DivSong* song) { SafeWriter* w=new SafeWriter(); w->init(); - //putInsData2(w,true); + if (oldFormat) { + // write magic + w->write("-Furnace instr.-",16); - // write magic - w->write("-Furnace instr.-",16); + // write version + w->writeS(DIV_ENGINE_VERSION); - // write version - w->writeS(DIV_ENGINE_VERSION); + // reserved + w->writeS(0); - // reserved - w->writeS(0); + // pointer to data + w->writeI(32); - // pointer to data - w->writeI(32); + // currently reserved (TODO; wavetable and sample here) + w->writeS(0); + w->writeS(0); + w->writeI(0); - // currently reserved (TODO; wavetable and sample here) - w->writeS(0); - w->writeS(0); - w->writeI(0); - - putInsData(w); + putInsData(w); + } else { + putInsData2(w,true,song); + } FILE* outFile=ps_fopen(path,"wb"); if (outFile==NULL) { diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 21ede72b1..829223f22 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -674,8 +674,8 @@ struct DivInstrument { void readFeatureN1(SafeReader& reader); void readFeatureFD(SafeReader& reader); void readFeatureWS(SafeReader& reader); - void readFeatureSL(SafeReader& reader, const DivSong* song); - void readFeatureWL(SafeReader& reader, const DivSong* song); + void readFeatureSL(SafeReader& reader, DivSong* song, short version); + void readFeatureWL(SafeReader& reader, DivSong* song, short version); void readFeatureMP(SafeReader& reader); void readFeatureSU(SafeReader& reader); void readFeatureES(SafeReader& reader); @@ -707,9 +707,11 @@ struct DivInstrument { /** * save this instrument to a file. * @param path file path. + * @param oldFormat whether to save in legacy Furnace ins format. + * @param song if new format, a DivSong to read wavetables and samples. * @return whether it was successful. */ - bool save(const char* path); + bool save(const char* path, bool oldFormat=false, DivSong* song=NULL); /** * save this instrument to a file in .dmp format. diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index f4a0d98b9..5f84aad01 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -39,6 +39,185 @@ DivSampleHistory::~DivSampleHistory() { if (data!=NULL) delete[] data; } +void DivSample::putSampleData(SafeWriter* w) { + size_t blockStartSeek, blockEndSeek; + + w->write("SMP2",4); + blockStartSeek=w->tell(); + w->writeI(0); + + w->writeString(name,false); + w->writeI(samples); + w->writeI(rate); + w->writeI(centerRate); + w->writeC(depth); + w->writeC(loopMode); + w->writeC(0); // reserved + w->writeC(0); + w->writeI(loop?loopStart:-1); + w->writeI(loop?loopEnd:-1); + + for (int i=0; i<4; i++) { + w->writeI(0xffffffff); + } + +#ifdef TA_BIG_ENDIAN + // store 16-bit samples as little-endian + if (depth==DIV_SAMPLE_DEPTH_16BIT) { + unsigned char* sampleBuf=(unsigned char*)getCurBuf(); + size_t bufLen=getCurBufLen(); + for (size_t i=0; iwriteC(sampleBuf[i+1]); + w->writeC(sampleBuf[i]); + } + } else { + w->write(getCurBuf(),getCurBufLen()); + } +#else + w->write(getCurBuf(),getCurBufLen()); +#endif + + blockEndSeek=w->tell(); + w->seek(blockStartSeek,SEEK_SET); + w->writeI(blockEndSeek-blockStartSeek-4); + w->seek(0,SEEK_END); +} + +// Delek why +static double samplePitchesSD[11]={ + 0.1666666666, 0.2, 0.25, 0.333333333, 0.5, + 1, + 2, 3, 4, 5, 6 +}; + +DivDataErrors DivSample::readSampleData(SafeReader& reader, short version) { + int vol=0; + int pitch=0; + char magic[4]; + + reader.read(magic,4); + if (strcmp(magic,"SMPL")!=0 && strcmp(magic,"SMP2")!=0) { + return DIV_DATA_INVALID_HEADER; + } + bool isNewSample=(strcmp(magic,"SMP2")==0); + reader.readI(); + if (!isNewSample) logV("(old sample)"); + + name=reader.readString(); + samples=reader.readI(); + if (!isNewSample) { + loopEnd=samples; + } + rate=reader.readI(); + + if (isNewSample) { + centerRate=reader.readI(); + depth=(DivSampleDepth)reader.readC(); + if (version>=123) { + loopMode=(DivSampleLoopMode)reader.readC(); + } else { + loopMode=DIV_SAMPLE_LOOP_FORWARD; + reader.readC(); + } + + // reserved + reader.readC(); + reader.readC(); + + loopStart=reader.readI(); + loopEnd=reader.readI(); + loop=(loopStart>=0)&&(loopEnd>=0); + + for (int i=0; i<4; i++) { + reader.readI(); + } + } else { + if (version<58) { + vol=reader.readS(); + pitch=reader.readS(); + } else { + reader.readI(); + } + depth=(DivSampleDepth)reader.readC(); + + // reserved + reader.readC(); + + // while version 32 stored this value, it was unused. + if (version>=38) { + centerRate=(unsigned short)reader.readS(); + } else { + reader.readS(); + } + + if (version>=19) { + loopStart=reader.readI(); + loop=(loopStart>=0)&&(loopEnd>=0); + } else { + reader.readI(); + } + } + + if (version>=58) { // modern sample + init(samples); + reader.read(getCurBuf(),getCurBufLen()); +#ifdef TA_BIG_ENDIAN + // convert 16-bit samples to big-endian + if (depth==DIV_SAMPLE_DEPTH_16BIT) { + unsigned char* sampleBuf=(unsigned char*)getCurBuf(); + size_t sampleBufLen=getCurBufLen(); + for (size_t pos=0; pos>8)|((unsigned short)data[pos]<<8); + } +#endif + + if (pitch!=5) { + logD("scaling from %d...",pitch); + } + + // render data + if (depth!=DIV_SAMPLE_DEPTH_8BIT && depth!=DIV_SAMPLE_DEPTH_16BIT) { + logW("sample depth is wrong! (%d)",depth); + depth=DIV_SAMPLE_DEPTH_16BIT; + } + samples=(double)samples/samplePitchesSD[pitch]; + init(samples); + + unsigned int k=0; + float mult=(float)(vol)/50.0f; + for (double j=0; j=samples) { + break; + } + if (depth==DIV_SAMPLE_DEPTH_8BIT) { + float next=(float)(data[(unsigned int)j]-0x80)*mult; + data8[k++]=fmin(fmax(next,-128),127); + } else { + float next=(float)data[(unsigned int)j]*mult; + data16[k++]=fmin(fmax(next,-32768),32767); + } + } + + delete[] data; + } + + return DIV_DATA_SUCCESS; +} + bool DivSample::isLoopable() { return loop && ((loopStart>=0 && loopStartloopStart && loopEnd<=(int)samples)); } diff --git a/src/engine/sample.h b/src/engine/sample.h index 9fa11abf3..e0d2c5d7c 100644 --- a/src/engine/sample.h +++ b/src/engine/sample.h @@ -21,6 +21,8 @@ #define _SAMPLE_H #include "../ta-utils.h" +#include "safeWriter.h" +#include "dataErrors.h" #include enum DivSampleLoopMode: unsigned char { @@ -130,6 +132,20 @@ struct DivSample { std::deque undoHist; std::deque redoHist; + /** + * put sample data. + * @param w a SafeWriter. + */ + void putSampleData(SafeWriter* w); + + /** + * read sample data. + * @param reader the reader. + * @param version the format version. + * @return a DivDataErrors. + */ + DivDataErrors readSampleData(SafeReader& reader, short version); + /** * check if sample is loopable. * @return whether it is loopable. diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 20f66dd59..face74247 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -132,6 +132,9 @@ void FurnaceGUI::drawInsList(bool asChild) { if (ImGui::MenuItem("instrument")) { doAction(GUI_ACTION_INS_LIST_SAVE); } + if (ImGui::MenuItem("instrument (legacy .fui)")) { + doAction(GUI_ACTION_INS_LIST_SAVE_OLD); + } if (ImGui::MenuItem("instrument (.dmp)")) { doAction(GUI_ACTION_INS_LIST_SAVE_DMP); } @@ -151,6 +154,9 @@ void FurnaceGUI::drawInsList(bool asChild) { } } else { if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save in legacy format...")) { + doAction(GUI_ACTION_INS_LIST_SAVE_OLD); + } if (ImGui::MenuItem("save as .dmp...")) { doAction(GUI_ACTION_INS_LIST_SAVE_DMP); } @@ -434,6 +440,9 @@ void FurnaceGUI::drawInsList(bool asChild) { if (ImGui::MenuItem("save")) { doAction(GUI_ACTION_INS_LIST_SAVE); } + if (ImGui::MenuItem("save (legacy .fui)")) { + doAction(GUI_ACTION_INS_LIST_SAVE_OLD); + } if (ImGui::MenuItem("save (.dmp)")) { doAction(GUI_ACTION_INS_LIST_SAVE_DMP); } diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 941d037c5..14fb4466a 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -599,6 +599,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_INS_LIST_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE); break; + case GUI_ACTION_INS_LIST_SAVE_OLD: + if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_OLD); + break; case GUI_ACTION_INS_LIST_SAVE_DMP: if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE_DMP); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 93c333689..54e2eedda 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1506,6 +1506,16 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_INS_SAVE_OLD: + if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); + hasOpened=fileDialog->openSave( + "Save Instrument", + {"Furnace instrument", "*.fui"}, + "Furnace instrument{.fui}", + workingDirIns, + dpiScale + ); + break; case GUI_FILE_INS_SAVE_DMP: if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); hasOpened=fileDialog->openSave( @@ -3855,6 +3865,7 @@ bool FurnaceGUI::loop() { case GUI_FILE_INS_OPEN: case GUI_FILE_INS_OPEN_REPLACE: case GUI_FILE_INS_SAVE: + case GUI_FILE_INS_SAVE_OLD: case GUI_FILE_INS_SAVE_DMP: workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR; break; @@ -3950,6 +3961,9 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_INS_SAVE) { checkExtension(".fui"); } + if (curFileDialog==GUI_FILE_INS_SAVE_OLD) { + checkExtension(".fui"); + } if (curFileDialog==GUI_FILE_INS_SAVE_DMP) { checkExtension(".dmp"); } @@ -4041,7 +4055,12 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_INS_SAVE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { - e->song.ins[curIns]->save(copyOfName.c_str()); + e->song.ins[curIns]->save(copyOfName.c_str(),false,&e->song); + } + break; + case GUI_FILE_INS_SAVE_OLD: + if (curIns>=0 && curIns<(int)e->song.ins.size()) { + e->song.ins[curIns]->save(copyOfName.c_str(),true); } break; case GUI_FILE_INS_SAVE_DMP: diff --git a/src/gui/gui.h b/src/gui/gui.h index f57e14429..8775a5f2c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -313,6 +313,7 @@ enum FurnaceGUIFileDialogs { GUI_FILE_INS_OPEN, GUI_FILE_INS_OPEN_REPLACE, GUI_FILE_INS_SAVE, + GUI_FILE_INS_SAVE_OLD, GUI_FILE_INS_SAVE_DMP, GUI_FILE_WAVE_OPEN, GUI_FILE_WAVE_OPEN_REPLACE, @@ -507,6 +508,7 @@ enum FurnaceGUIActions { GUI_ACTION_INS_LIST_OPEN, GUI_ACTION_INS_LIST_OPEN_REPLACE, GUI_ACTION_INS_LIST_SAVE, + GUI_ACTION_INS_LIST_SAVE_OLD, GUI_ACTION_INS_LIST_SAVE_DMP, GUI_ACTION_INS_LIST_MOVE_UP, GUI_ACTION_INS_LIST_MOVE_DOWN, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 5b8c5dc7d..b542b3f71 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -590,6 +590,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("INS_LIST_OPEN", "Open", 0), D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0), D("INS_LIST_SAVE", "Save", 0), + D("INS_LIST_SAVE_OLD", "Save (legacy .fui)", 0), D("INS_LIST_SAVE_DMP", "Save (.dmp)", 0), D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP), D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN), @@ -1084,4 +1085,4 @@ const char* chipCategoryNames[]={ "Special", "Sample", NULL -}; \ No newline at end of file +}; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index c2e2cb016..7dc010697 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2167,6 +2167,9 @@ void FurnaceGUI::drawInsEdit() { doAction(GUI_ACTION_INS_LIST_SAVE); } if (ImGui::BeginPopupContextItem("InsSaveFormats",ImGuiMouseButton_Right)) { + if (ImGui::MenuItem("save in legacy format...")) { + doAction(GUI_ACTION_INS_LIST_SAVE_OLD); + } if (ImGui::MenuItem("save as .dmp...")) { doAction(GUI_ACTION_INS_LIST_SAVE_DMP); }