From 1003d9fcb8fe425d6fb9c54794a9e638758b0b89 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 21 Mar 2022 16:17:51 -0500 Subject: [PATCH] GUI: more "modified" status situations fixes #236 --- src/engine/engine.cpp | 69 ++++++++++++++++++++++- src/engine/engine.h | 8 ++- src/engine/fileOps.cpp | 12 +++- src/gui/gui.cpp | 70 ++++++++++++----------- src/gui/gui.h | 2 + src/gui/insEdit.cpp | 16 +++--- src/gui/orders.cpp | 28 ++++++---- src/gui/sampleEdit.cpp | 122 ++++++++++++++++++++++++----------------- 8 files changed, 223 insertions(+), 104 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 3a6812adf..2b3283917 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -584,6 +584,7 @@ void DivEngine::renderSamples() { void DivEngine::createNew(const int* description) { quitDispatch(); isBusy.lock(); + saveLock.lock(); song.unload(); song=DivSong(); if (description!=NULL) { @@ -602,6 +603,7 @@ void DivEngine::createNew(const int* description) { } recalcChans(); renderSamples(); + saveLock.unlock(); isBusy.unlock(); initDispatch(); isBusy.lock(); @@ -1214,8 +1216,10 @@ int DivEngine::addInstrument(int refChan) { int insCount=(int)song.ins.size(); ins->name=fmt::sprintf("Instrument %d",insCount); ins->type=getPreferInsType(refChan); + saveLock.lock(); song.ins.push_back(ins); song.insLen=insCount+1; + saveLock.unlock(); isBusy.unlock(); return insCount; } @@ -1230,6 +1234,9 @@ enum DivInsFormats { DIV_INSFORMAT_SBI, }; +// TODO: re-organize this function to: +// - support replacing instruments +// - support instrument formats which contain multiple instruments bool DivEngine::addInstrumentFromFile(const char* path) { warnings=""; @@ -1354,7 +1361,7 @@ bool DivEngine::addInstrumentFromFile(const char* path) { } } - // TDOO these really should be refactored to separate functions/cpp files per instrument file type. + // TDOO these really should be re-organized to separate functions per instrument file type. switch (format) { case DIV_INSFORMAT_DMP: { // this is a ridiculous mess @@ -1937,15 +1944,18 @@ bool DivEngine::addInstrumentFromFile(const char* path) { } isBusy.lock(); + saveLock.lock(); int insCount=(int)song.ins.size(); song.ins.push_back(ins); song.insLen=insCount+1; + saveLock.unlock(); isBusy.unlock(); return true; } void DivEngine::delInstrument(int index) { isBusy.lock(); + saveLock.lock(); if (index>=0 && index<(int)song.ins.size()) { for (int i=0; inotifyInsDeletion(song.ins[index]); @@ -1964,15 +1974,18 @@ void DivEngine::delInstrument(int index) { } } } + saveLock.unlock(); isBusy.unlock(); } int DivEngine::addWave() { isBusy.lock(); + saveLock.lock(); DivWavetable* wave=new DivWavetable; int waveCount=(int)song.wave.size(); song.wave.push_back(wave); song.waveLen=waveCount+1; + saveLock.unlock(); isBusy.unlock(); return waveCount; } @@ -2088,30 +2101,36 @@ bool DivEngine::addWaveFromFile(const char* path) { } isBusy.lock(); + saveLock.lock(); int waveCount=(int)song.wave.size(); song.wave.push_back(wave); song.waveLen=waveCount+1; + saveLock.unlock(); isBusy.unlock(); return true; } void DivEngine::delWave(int index) { isBusy.lock(); + saveLock.lock(); if (index>=0 && index<(int)song.wave.size()) { delete song.wave[index]; song.wave.erase(song.wave.begin()+index); song.waveLen=song.wave.size(); } + saveLock.unlock(); isBusy.unlock(); } int DivEngine::addSample() { isBusy.lock(); + saveLock.lock(); DivSample* sample=new DivSample; int sampleCount=(int)song.sample.size(); sample->name=fmt::sprintf("Sample %d",sampleCount); song.sample.push_back(sample); song.sampleLen=sampleCount+1; + saveLock.unlock(); renderSamples(); isBusy.unlock(); return sampleCount; @@ -2189,8 +2208,10 @@ bool DivEngine::addSampleFromFile(const char* path) { if (sample->centerRate<4000) sample->centerRate=4000; if (sample->centerRate>64000) sample->centerRate=64000; sf_close(f); + saveLock.lock(); song.sample.push_back(sample); song.sampleLen=sampleCount+1; + saveLock.unlock(); renderSamples(); isBusy.unlock(); return sampleCount; @@ -2198,12 +2219,14 @@ bool DivEngine::addSampleFromFile(const char* path) { void DivEngine::delSample(int index) { isBusy.lock(); + saveLock.lock(); if (index>=0 && index<(int)song.sample.size()) { delete song.sample[index]; song.sample.erase(song.sample.begin()+index); song.sampleLen=song.sample.size(); renderSamples(); } + saveLock.unlock(); isBusy.unlock(); } @@ -2232,11 +2255,14 @@ void DivEngine::addOrder(bool duplicate, bool where) { } } if (where) { // at the end + saveLock.lock(); for (int i=0; icurOrder; j--) { song.orders.ord[i][j]=song.orders.ord[i][j-1]; @@ -2244,6 +2270,7 @@ void DivEngine::addOrder(bool duplicate, bool where) { song.orders.ord[i][curOrder+1]=order[i]; } song.ordersLen++; + saveLock.unlock(); curOrder++; if (playing && !freelance) { playSub(false); @@ -2280,11 +2307,14 @@ void DivEngine::deepCloneOrder(bool where) { } } if (where) { // at the end + saveLock.lock(); for (int i=0; icurOrder; j--) { song.orders.ord[i][j]=song.orders.ord[i][j-1]; @@ -2292,6 +2322,7 @@ void DivEngine::deepCloneOrder(bool where) { song.orders.ord[i][curOrder+1]=order[i]; } song.ordersLen++; + saveLock.unlock(); curOrder++; if (playing && !freelance) { playSub(false); @@ -2303,12 +2334,14 @@ void DivEngine::deepCloneOrder(bool where) { void DivEngine::deleteOrder() { if (song.ordersLen<=1) return; isBusy.lock(); + saveLock.lock(); for (int i=0; i=song.ordersLen) curOrder=song.ordersLen-1; if (playing && !freelance) { playSub(false); @@ -2322,11 +2355,13 @@ void DivEngine::moveOrderUp() { isBusy.unlock(); return; } + saveLock.lock(); for (int i=0; i=(int)song.ins.size()) return false; isBusy.lock(); DivInstrument* prev=song.ins[which]; + saveLock.lock(); song.ins[which]=song.ins[which-1]; song.ins[which-1]=prev; exchangeIns(which,which-1); + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2382,8 +2421,10 @@ bool DivEngine::moveWaveUp(int which) { if (which<1 || which>=(int)song.wave.size()) return false; isBusy.lock(); DivWavetable* prev=song.wave[which]; + saveLock.lock(); song.wave[which]=song.wave[which-1]; song.wave[which-1]=prev; + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2392,8 +2433,10 @@ bool DivEngine::moveSampleUp(int which) { if (which<1 || which>=(int)song.sample.size()) return false; isBusy.lock(); DivSample* prev=song.sample[which]; + saveLock.lock(); song.sample[which]=song.sample[which-1]; song.sample[which-1]=prev; + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2402,9 +2445,11 @@ bool DivEngine::moveInsDown(int which) { if (which<0 || which>=((int)song.ins.size())-1) return false; isBusy.lock(); DivInstrument* prev=song.ins[which]; + saveLock.lock(); song.ins[which]=song.ins[which+1]; song.ins[which+1]=prev; exchangeIns(which,which+1); + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2413,8 +2458,10 @@ bool DivEngine::moveWaveDown(int which) { if (which<0 || which>=((int)song.wave.size())-1) return false; isBusy.lock(); DivWavetable* prev=song.wave[which]; + saveLock.lock(); song.wave[which]=song.wave[which+1]; song.wave[which+1]=prev; + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2423,8 +2470,10 @@ bool DivEngine::moveSampleDown(int which) { if (which<0 || which>=((int)song.sample.size())-1) return false; isBusy.lock(); DivSample* prev=song.sample[which]; + saveLock.lock(); song.sample[which]=song.sample[which+1]; song.sample[which+1]=prev; + saveLock.unlock(); isBusy.unlock(); return true; } @@ -2465,7 +2514,9 @@ void DivEngine::setOrder(unsigned char order) { void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) { isBusy.lock(); + saveLock.lock(); song.systemFlags[system]=flags; + saveLock.unlock(); disCont[system].dispatch->setFlags(song.systemFlags[system]); disCont[system].setRates(got.rate); if (restart && isPlaying()) { @@ -2476,6 +2527,7 @@ void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) { void DivEngine::setSongRate(float hz, bool pal) { isBusy.lock(); + saveLock.lock(); song.pal=!pal; song.hz=hz; // what? @@ -2490,6 +2542,7 @@ void DivEngine::setSongRate(float hz, bool pal) { divider=50; } } + saveLock.unlock(); isBusy.unlock(); } @@ -2539,6 +2592,20 @@ void DivEngine::synchronized(const std::function& what) { isBusy.unlock(); } +void DivEngine::lockSave(const std::function& what) { + saveLock.lock(); + what(); + saveLock.unlock(); +} + +void DivEngine::lockEngine(const std::function& what) { + isBusy.lock(); + saveLock.lock(); + what(); + saveLock.unlock(); + isBusy.unlock(); +} + TAAudioDesc& DivEngine::getAudioDescWant() { return want; } diff --git a/src/engine/engine.h b/src/engine/engine.h index 958508a3a..9f7464e37 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -201,7 +201,7 @@ class DivEngine { std::map conf; std::queue pendingNotes; bool isMuted[DIV_MAX_CHANS]; - std::mutex isBusy; + std::mutex isBusy, saveLock; String configPath; String configFile; String lastError; @@ -621,6 +621,12 @@ class DivEngine { // perform secure/sync operation void synchronized(const std::function& what); + // perform secure/sync song operation + void lockSave(const std::function& what); + + // perform secure/sync song operation (and lock audio too) + void lockEngine(const std::function& what); + // get audio desc want TAAudioDesc& getAudioDescWant(); diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index afe5df630..460f7d8d8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -733,10 +733,12 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { if (active) quitDispatch(); isBusy.lock(); + saveLock.lock(); song.unload(); song=ds; recalcChans(); renderSamples(); + saveLock.unlock(); isBusy.unlock(); if (active) { initDispatch(); @@ -1219,10 +1221,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (active) quitDispatch(); isBusy.lock(); + saveLock.lock(); song.unload(); song=ds; recalcChans(); renderSamples(); + saveLock.unlock(); isBusy.unlock(); if (active) { initDispatch(); @@ -1583,10 +1587,12 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { if (active) quitDispatch(); isBusy.lock(); + saveLock.lock(); song.unload(); song=ds; recalcChans(); renderSamples(); + saveLock.unlock(); isBusy.unlock(); if (active) { initDispatch(); @@ -1729,6 +1735,7 @@ bool DivEngine::load(unsigned char* f, size_t slen) { } SafeWriter* DivEngine::saveFur(bool notPrimary) { + saveLock.lock(); int insPtr[256]; int wavePtr[256]; int samplePtr[256]; @@ -1969,6 +1976,7 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeI(i); } + saveLock.unlock(); return w; } @@ -2028,6 +2036,7 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { lastError="this system is not possible on .dmf"; return NULL; } + saveLock.lock(); warnings=""; song.version=version; song.isDMF=true; @@ -2259,7 +2268,8 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) { w->writeC(16); w->write(i->data16,i->length16); } - + + saveLock.unlock(); return w; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index adf7c1a20..17d14f6ef 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1004,13 +1004,17 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Name",&e->song.name)) updateWindowTitle(); + if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED + updateWindowTitle(); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::Text("Author"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - ImGui::InputText("##Author",&e->song.author); + if (ImGui::InputText("##Author",&e->song.author)) { + MARK_MODIFIED; + } ImGui::EndTable(); } @@ -1026,7 +1030,7 @@ void FurnaceGUI::drawSongInfo() { float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); unsigned char realTB=e->song.timeBase+1; - if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { + if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { MARK_MODIFIED if (realTB<1) realTB=1; if (realTB>16) realTB=16; e->song.timeBase=realTB-1; @@ -1039,13 +1043,13 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Speed"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Speed1",ImGuiDataType_U8,&e->song.speed1,&_ONE,&_THREE)) { + if (ImGui::InputScalar("##Speed1",ImGuiDataType_U8,&e->song.speed1,&_ONE,&_THREE)) { MARK_MODIFIED if (e->song.speed1<1) e->song.speed1=1; if (e->isPlaying()) play(); } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputScalar("##Speed2",ImGuiDataType_U8,&e->song.speed2,&_ONE,&_THREE)) { + if (ImGui::InputScalar("##Speed2",ImGuiDataType_U8,&e->song.speed2,&_ONE,&_THREE)) { MARK_MODIFIED if (e->song.speed2<1) e->song.speed2=1; if (e->isPlaying()) play(); } @@ -1055,10 +1059,14 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Highlight"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - ImGui::InputScalar("##Highlight1",ImGuiDataType_U8,&e->song.hilightA,&_ONE,&_THREE); + if (ImGui::InputScalar("##Highlight1",ImGuiDataType_U8,&e->song.hilightA,&_ONE,&_THREE)) { + MARK_MODIFIED; + } ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - ImGui::InputScalar("##Highlight2",ImGuiDataType_U8,&e->song.hilightB,&_ONE,&_THREE); + if (ImGui::InputScalar("##Highlight2",ImGuiDataType_U8,&e->song.hilightB,&_ONE,&_THREE)) { + MARK_MODIFIED; + } ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -1066,7 +1074,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); int patLen=e->song.patLen; - if (ImGui::InputInt("##PatLength",&patLen,1,3)) { + if (ImGui::InputInt("##PatLength",&patLen,1,3)) { MARK_MODIFIED if (patLen<1) patLen=1; if (patLen>256) patLen=256; e->song.patLen=patLen; @@ -1078,7 +1086,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); int ordLen=e->song.ordersLen; - if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { + if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED if (ordLen<1) ordLen=1; if (ordLen>127) ordLen=127; e->song.ordersLen=ordLen; @@ -1092,7 +1100,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); float setHz=tempoView?e->song.hz*2.5:e->song.hz; - if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { + if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED if (tempoView) setHz/=2.5; if (setHz<10) setHz=10; if (setHz>999) setHz=999; @@ -1118,7 +1126,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); float tune=e->song.tuning; ImGui::SetNextItemWidth(avail); - if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { + if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { MARK_MODIFIED if (tune<220.0f) tune=220.0f; if (tune>880.0f) tune=880.0f; e->song.tuning=tune; @@ -2713,7 +2721,7 @@ void FurnaceGUI::makeUndo(ActionType action) { break; } if (doPush) { - modified=true; + MARK_MODIFIED; undoHist.push_back(s); redoHist.clear(); if (undoHist.size()>settings.maxUndoSteps) undoHist.pop_front(); @@ -3509,7 +3517,7 @@ void FurnaceGUI::doUndo() { if (undoHist.empty()) return; UndoStep& us=undoHist.back(); redoHist.push_back(us); - modified=true; + MARK_MODIFIED; switch (us.type) { case GUI_UNDO_CHANGE_ORDER: @@ -3555,7 +3563,7 @@ void FurnaceGUI::doRedo() { if (redoHist.empty()) return; UndoStep& us=redoHist.back(); undoHist.push_back(us); - modified=true; + MARK_MODIFIED; switch (us.type) { case GUI_UNDO_CHANGE_ORDER: @@ -4095,14 +4103,14 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_INS_LIST_ADD: curIns=e->addInstrument(cursor.xCoarse); - modified=true; + MARK_MODIFIED; break; case GUI_ACTION_INS_LIST_DUPLICATE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { int prevIns=curIns; curIns=e->addInstrument(cursor.xCoarse); (*e->song.ins[curIns])=(*e->song.ins[prevIns]); - modified=true; + MARK_MODIFIED; } break; case GUI_ACTION_INS_LIST_OPEN: @@ -4120,7 +4128,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_INS_LIST_DELETE: if (curIns>=0 && curIns<(int)e->song.ins.size()) { e->delInstrument(curIns); - modified=true; + MARK_MODIFIED; if (curIns>=(int)e->song.ins.size()) { curIns--; } @@ -4138,14 +4146,14 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WAVE_LIST_ADD: curWave=e->addWave(); - modified=true; + MARK_MODIFIED; break; case GUI_ACTION_WAVE_LIST_DUPLICATE: if (curWave>=0 && curWave<(int)e->song.wave.size()) { int prevWave=curWave; curWave=e->addWave(); (*e->song.wave[curWave])=(*e->song.wave[prevWave]); - modified=true; + MARK_MODIFIED; } break; case GUI_ACTION_WAVE_LIST_OPEN: @@ -4163,7 +4171,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WAVE_LIST_DELETE: if (curWave>=0 && curWave<(int)e->song.wave.size()) { e->delWave(curWave); - modified=true; + MARK_MODIFIED; if (curWave>=(int)e->song.wave.size()) { curWave--; } @@ -4181,7 +4189,7 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_LIST_ADD: curSample=e->addSample(); - modified=true; + MARK_MODIFIED; break; case GUI_ACTION_SAMPLE_LIST_OPEN: openFileDialog(GUI_FILE_SAMPLE_OPEN); @@ -4197,7 +4205,7 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_SAMPLE_LIST_DELETE: e->delSample(curSample); - modified=true; + MARK_MODIFIED; if (curSample>=(int)e->song.sample.size()) { curSample--; } @@ -4498,7 +4506,9 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { int num=valueKeys.at(ev.key.keysym.sym); if (orderCursor>=0 && orderCursorgetTotalChannelCount()) { int curOrder=e->getOrder(); - e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num)&0x7f; + e->lockSave([this,curOrder,num]() { + e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num)&0x7f; + }); if (orderEditMode==2 || orderEditMode==3) { curNibble=!curNibble; if (!curNibble) { @@ -4813,13 +4823,11 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { int FurnaceGUI::save(String path, int dmfVersion) { SafeWriter* w; - backupLock.lock(); if (dmfVersion) { w=e->saveDMF(dmfVersion); } else { w=e->saveFur(); } - backupLock.unlock(); if (w==NULL) { lastError=e->getLastError(); return 3; @@ -5062,7 +5070,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { if (ynotifyWaveChange(curWave); - modified=true; + MARK_MODIFIED; } } if (sampleDragActive) { @@ -5363,7 +5371,9 @@ bool FurnaceGUI::loop() { break; } case SDL_MOUSEBUTTONUP: - if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode)) modified=true; + if (macroDragActive || macroLoopDragActive || waveDragActive || (sampleDragActive && sampleDragMode)) { + MARK_MODIFIED; + } macroDragActive=false; macroDragBitMode=false; macroDragInitialValue=false; @@ -6272,7 +6282,7 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_SAMPLE_OPEN: e->addSampleFromFile(copyOfName.c_str()); - modified=true; + MARK_MODIFIED; break; case GUI_FILE_SAMPLE_SAVE: if (curSample>=0 && curSample<(int)e->song.sample.size()) { @@ -6299,7 +6309,7 @@ bool FurnaceGUI::loop() { break; case GUI_FILE_WAVE_OPEN: e->addWaveFromFile(copyOfName.c_str()); - modified=true; + MARK_MODIFIED; break; case GUI_FILE_EXPORT_VGM: { SafeWriter* w=e->saveVGM(willExport,vgmExportLoop); @@ -6444,9 +6454,7 @@ bool FurnaceGUI::loop() { return true; } logD("saving backup...\n"); - backupLock.lock(); SafeWriter* w=e->saveFur(true); - backupLock.unlock(); if (w!=NULL) { FILE* outFile=ps_fopen(backupPath.c_str(),"wb"); diff --git a/src/gui/gui.h b/src/gui/gui.h index ad73fba96..75ebab6e2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -36,6 +36,8 @@ #define handleUnimportant if (settings.insFocusesPattern && patternOpen) {nextWindow=GUI_WINDOW_PATTERN;} #define unimportant(x) if (x) {handleUnimportant} +#define MARK_MODIFIED modified=true; + enum FurnaceGUIColors { GUI_COLOR_BACKGROUND=0, GUI_COLOR_FRAME_BACKGROUND, diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index def41aad3..0257c6073 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -669,11 +669,11 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } #define P(x) if (x) { \ - modified=true; \ + MARK_MODIFIED; \ e->notifyInsChange(curIns); \ } -#define PARAMETER modified=true; e->notifyInsChange(curIns); +#define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns); #define NORMAL_MACRO(macro,macroLen,macroLoop,macroRel,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,macroDispMin,bitOff,macroMode,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \ ImGui::TableNextRow(); \ @@ -685,7 +685,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ if (displayLoop) { \ ImGui::SetNextItemWidth(lenAvail); \ - if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { \ + if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED \ if (macroLen>127) macroLen=127; \ } \ if (macroMode!=NULL) { \ @@ -774,7 +774,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } \ if (displayLoop) { \ ImGui::SetNextItemWidth(lenAvail); \ - if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { \ + if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED \ if (macroLen>127) macroLen=127; \ } \ } \ @@ -924,7 +924,9 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("no instrument selected"); } else { DivInstrument* ins=e->song.ins[curIns]; - ImGui::InputText("Name",&ins->name); + if (ImGui::InputText("Name",&ins->name)) { + MARK_MODIFIED; + } if (ins->type<0 || ins->type>=DIV_INS_MAX) ins->type=DIV_INS_FM; int insType=ins->type; if (ImGui::Combo("Type",&insType,insTypes,DIV_INS_MAX,DIV_INS_MAX)) { @@ -2011,7 +2013,7 @@ void FurnaceGUI::drawWaveEdit() { if (wave->len<1) wave->len=1; e->notifyWaveChange(curWave); if (wavePreviewOn) e->previewWave(curWave,wavePreviewNote); - modified=true; + MARK_MODIFIED; } ImGui::SameLine(); ImGui::Text("Height"); @@ -2024,7 +2026,7 @@ void FurnaceGUI::drawWaveEdit() { if (wave->max>255) wave->max=255; if (wave->max<1) wave->max=1; e->notifyWaveChange(curWave); - modified=true; + MARK_MODIFIED; } for (int i=0; ilen; i++) { if (wave->data[i]>wave->max) wave->data[i]=wave->max; diff --git a/src/gui/orders.cpp b/src/gui/orders.cpp index 43976fdc0..37faba8d4 100644 --- a/src/gui/orders.cpp +++ b/src/gui/orders.cpp @@ -97,13 +97,15 @@ void FurnaceGUI::drawOrders() { if (curOrder==i) { if (orderEditMode==0) { prepareUndo(GUI_UNDO_CHANGE_ORDER); - if (changeAllOrders) { - for (int k=0; kgetTotalChannelCount(); k++) { - if (e->song.orders.ord[k][i]<0x7f) e->song.orders.ord[k][i]++; + e->lockSave([this,i,j]() { + if (changeAllOrders) { + for (int k=0; kgetTotalChannelCount(); k++) { + if (e->song.orders.ord[k][i]<0x7f) e->song.orders.ord[k][i]++; + } + } else { + if (e->song.orders.ord[j][i]<0x7f) e->song.orders.ord[j][i]++; } - } else { - if (e->song.orders.ord[j][i]<0x7f) e->song.orders.ord[j][i]++; - } + }); e->walkSong(loopOrder,loopRow,loopEnd); makeUndo(GUI_UNDO_CHANGE_ORDER); } else { @@ -130,13 +132,15 @@ void FurnaceGUI::drawOrders() { if (curOrder==i) { if (orderEditMode==0) { prepareUndo(GUI_UNDO_CHANGE_ORDER); - if (changeAllOrders) { - for (int k=0; kgetTotalChannelCount(); k++) { - if (e->song.orders.ord[k][i]>0) e->song.orders.ord[k][i]--; + e->lockSave([this,i,j]() { + if (changeAllOrders) { + for (int k=0; kgetTotalChannelCount(); k++) { + if (e->song.orders.ord[k][i]>0) e->song.orders.ord[k][i]--; + } + } else { + if (e->song.orders.ord[j][i]>0) e->song.orders.ord[j][i]--; } - } else { - if (e->song.orders.ord[j][i]>0) e->song.orders.ord[j][i]--; - } + }); e->walkSong(loopOrder,loopRow,loopEnd); makeUndo(GUI_UNDO_CHANGE_ORDER); } else { diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 1af7ddf63..55d2e4859 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -60,7 +60,9 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Text("Name"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputText("##SampleName",&sample->name); + if (ImGui::InputText("##SampleName",&sample->name)) { + MARK_MODIFIED; + } if (ImGui::BeginTable("SampleProps",4,ImGuiTableFlags_SizingStretchSame)) { ImGui::TableNextRow(); @@ -75,6 +77,7 @@ void FurnaceGUI::drawSampleEdit() { sample->depth=i; e->renderSamplesP(); updateSampleTex=true; + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("no undo for sample type change operations!"); @@ -87,7 +90,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Text("Rate (Hz)"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SampleRate",&sample->rate,10,200)) { + if (ImGui::InputInt("##SampleRate",&sample->rate,10,200)) { MARK_MODIFIED if (sample->rate<100) sample->rate=100; if (sample->rate>96000) sample->rate=96000; } @@ -96,14 +99,14 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Text("C-4 (Hz)"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##SampleCenter",&sample->centerRate,10,200)) { + if (ImGui::InputInt("##SampleCenter",&sample->centerRate,10,200)) { MARK_MODIFIED if (sample->centerRate<100) sample->centerRate=100; if (sample->centerRate>65535) sample->centerRate=65535; } ImGui::TableNextColumn(); bool doLoop=(sample->loopStart>=0); - if (ImGui::Checkbox("Loop",&doLoop)) { + if (ImGui::Checkbox("Loop",&doLoop)) { MARK_MODIFIED if (doLoop) { sample->loopStart=0; } else { @@ -114,7 +117,7 @@ void FurnaceGUI::drawSampleEdit() { if (doLoop) { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { + if (ImGui::InputInt("##LoopPosition",&sample->loopStart,1,10)) { MARK_MODIFIED if (sample->loopStart<0 || sample->loopStart>=(int)sample->samples) { sample->loopStart=0; } @@ -161,13 +164,16 @@ void FurnaceGUI::drawSampleEdit() { if (resizeSize>16777215) resizeSize=16777215; } if (ImGui::Button("Resize")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { if (!sample->resize(resizeSize)) { showError("couldn't resize! make sure your sample is 8 or 16-bit."); } e->renderSamples(); }); updateSampleTex=true; + sampleSelStart=-1; + sampleSelEnd=-1; + MARK_MODIFIED; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -208,13 +214,16 @@ void FurnaceGUI::drawSampleEdit() { } ImGui::Combo("Filter",&resampleStrat,resampleStrats,6); if (ImGui::Button("Resample")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { if (!sample->resample(resampleTarget,resampleStrat)) { showError("couldn't resample! make sure your sample is 8 or 16-bit."); } e->renderSamples(); }); updateSampleTex=true; + sampleSelStart=-1; + sampleSelEnd=-1; + MARK_MODIFIED; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -237,7 +246,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::SameLine(); ImGui::Text("(%.1fdB)",20.0*log10(amplifyVol/100.0f)); if (ImGui::Button("Apply")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; float vol=amplifyVol/100.0f; @@ -261,59 +270,61 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROWS_V "##SNormalize")) { - e->synchronized([this,sample]() { - SAMPLE_OP_BEGIN; - float maxVal=0.0f; + e->lockEngine([this,sample]() { + SAMPLE_OP_BEGIN; + float maxVal=0.0f; - if (sample->depth==16) { - for (unsigned int i=start; idata16[i]/32767.0f); - if (val>maxVal) maxVal=val; - } - if (maxVal>1.0f) maxVal=1.0f; - if (maxVal>0.0f) { - float vol=1.0f/maxVal; + if (sample->depth==16) { for (unsigned int i=start; idata16[i]*vol; - if (val<-32768) val=-32768; - if (val>32767) val=32767; - sample->data16[i]=val; + float val=fabs((float)sample->data16[i]/32767.0f); + if (val>maxVal) maxVal=val; + } + if (maxVal>1.0f) maxVal=1.0f; + if (maxVal>0.0f) { + float vol=1.0f/maxVal; + for (unsigned int i=start; idata16[i]*vol; + if (val<-32768) val=-32768; + if (val>32767) val=32767; + sample->data16[i]=val; + } + } + } else if (sample->depth==8) { + for (unsigned int i=start; idata8[i]/127.0f); + if (val>maxVal) maxVal=val; + } + if (maxVal>1.0f) maxVal=1.0f; + if (maxVal>0.0f) { + float vol=1.0f/maxVal; + for (unsigned int i=start; idata8[i]*vol; + if (val<-128) val=-128; + if (val>127) val=127; + sample->data8[i]=val; + } } } - } else if (sample->depth==8) { - for (unsigned int i=start; idata8[i]/127.0f); - if (val>maxVal) maxVal=val; - } - if (maxVal>1.0f) maxVal=1.0f; - if (maxVal>0.0f) { - float vol=1.0f/maxVal; - for (unsigned int i=start; idata8[i]*vol; - if (val<-128) val=-128; - if (val>127) val=127; - sample->data8[i]=val; - } - } - } - updateSampleTex=true; + updateSampleTex=true; - e->renderSamples(); - }); + e->renderSamples(); + }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Normalize"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROW_UP "##SFadeIn")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -336,13 +347,14 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Fade in"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_ARROW_DOWN "##SFadeOut")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -365,13 +377,14 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Fade out"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_ERASER "##SSilence")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -388,13 +401,14 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Apply silence"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_TIMES "##SDelete")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; sample->strip(start,end); @@ -404,13 +418,14 @@ void FurnaceGUI::drawSampleEdit() { }); sampleSelStart=-1; sampleSelEnd=-1; + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Delete"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_CROP "##STrim")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; sample->trim(start,end); @@ -420,6 +435,7 @@ void FurnaceGUI::drawSampleEdit() { }); sampleSelStart=-1; sampleSelEnd=-1; + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Trim"); @@ -428,7 +444,7 @@ void FurnaceGUI::drawSampleEdit() { ImGui::Dummy(ImVec2(4.0*dpiScale,dpiScale)); ImGui::SameLine(); if (ImGui::Button(ICON_FA_BACKWARD "##SReverse")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -453,13 +469,14 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Reverse"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_SORT_AMOUNT_ASC "##SInvert")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -478,13 +495,14 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Invert"); } ImGui::SameLine(); if (ImGui::Button(ICON_FA_LEVEL_DOWN "##SSign")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; if (sample->depth==16) { @@ -501,6 +519,7 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; } if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Signed/unsigned exchange"); @@ -561,7 +580,7 @@ void FurnaceGUI::drawSampleEdit() { } if (ImGui::Button("Apply")) { - e->synchronized([this,sample]() { + e->lockEngine([this,sample]() { SAMPLE_OP_BEGIN; float res=1.0-pow(sampleFilterRes,0.5f); float low=0; @@ -608,6 +627,7 @@ void FurnaceGUI::drawSampleEdit() { e->renderSamples(); }); + MARK_MODIFIED; ImGui::CloseCurrentPopup(); } ImGui::EndPopup();