From 39923742ab29714abd17c43c7442d87eaabe7a91 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Aug 2024 17:20:17 -0500 Subject: [PATCH 01/23] ZSM export: move to ROM export framework --- CMakeLists.txt | 3 +- src/engine/engine.h | 3 +- src/engine/export.cpp | 4 + src/engine/{ => export}/zsm.cpp | 309 +++++++++++++++++++++++++++++++- src/engine/export/zsm.h | 38 ++++ src/engine/zsm.h | 92 ---------- src/engine/zsmOps.cpp | 208 --------------------- src/gui/exportOptions.cpp | 58 +++--- src/gui/gui.cpp | 62 ------- src/gui/gui.h | 8 +- src/main.cpp | 38 +--- 11 files changed, 382 insertions(+), 441 deletions(-) rename src/engine/{ => export}/zsm.cpp (64%) create mode 100644 src/engine/export/zsm.h delete mode 100644 src/engine/zsm.h delete mode 100644 src/engine/zsmOps.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d02350b16..59f04d451 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -717,8 +717,6 @@ src/engine/wavetable.cpp src/engine/waveSynth.cpp src/engine/wavOps.cpp src/engine/vgmOps.cpp -src/engine/zsmOps.cpp -src/engine/zsm.cpp src/engine/platform/abstract.cpp src/engine/platform/genesis.cpp @@ -797,6 +795,7 @@ src/engine/platform/dummy.cpp src/engine/export/abstract.cpp src/engine/export/amigaValidation.cpp src/engine/export/tiuna.cpp +src/engine/export/zsm.cpp src/engine/effect/abstract.cpp src/engine/effect/dummy.cpp diff --git a/src/engine/engine.h b/src/engine/engine.h index ac897d136..a845cb0e1 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -669,6 +669,7 @@ class DivEngine { friend class DivROMExport; friend class DivExportAmigaValidation; friend class DivExportTiuna; + friend class DivExportZSM; public: DivSong song; @@ -721,8 +722,6 @@ class DivEngine { // - -1 to auto-determine trailing // - -2 to add a whole loop of trailing SafeWriter* saveVGM(bool* sysToExport=NULL, bool loop=true, int version=0x171, bool patternHints=false, bool directStream=false, int trailingTicks=-1); - // dump to ZSM. - SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true, bool optimize=true); // dump to TIunA. SafeWriter* saveTiuna(const bool* sysToExport, const char* baseLabel, int firstBankSize, int otherBankSize); // dump command stream. diff --git a/src/engine/export.cpp b/src/engine/export.cpp index 33544e252..5a3700097 100644 --- a/src/engine/export.cpp +++ b/src/engine/export.cpp @@ -21,6 +21,7 @@ #include "export/amigaValidation.h" #include "export/tiuna.h" +#include "export/zsm.h" DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { DivROMExport* exporter=NULL; @@ -31,6 +32,9 @@ DivROMExport* DivEngine::buildROM(DivROMExportOptions sys) { case DIV_ROM_TIUNA: exporter=new DivExportTiuna; break; + case DIV_ROM_ZSM: + exporter=new DivExportZSM; + break; default: exporter=new DivROMExport; break; diff --git a/src/engine/zsm.cpp b/src/engine/export/zsm.cpp similarity index 64% rename from src/engine/zsm.cpp rename to src/engine/export/zsm.cpp index 75cc3d9da..81c5021a0 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/export/zsm.cpp @@ -18,9 +18,77 @@ */ #include "zsm.h" +#include "../engine.h" #include "../ta-log.h" -#include "../utfutils.h" -#include "song.h" +#include + +/// DivZSM definitions + +#define ZSM_HEADER_SIZE 16 +#define ZSM_VERSION 1 +#define ZSM_YM_CMD 0x40 +#define ZSM_DELAY_CMD 0x80 +#define ZSM_YM_MAX_WRITES 63 +#define ZSM_SYNC_MAX_WRITES 31 +#define ZSM_DELAY_MAX 127 +#define ZSM_EOF ZSM_DELAY_CMD + +#define ZSM_EXT ZSM_YM_CMD +#define ZSM_EXT_PCM 0x00 +#define ZSM_EXT_CHIP 0x40 +#define ZSM_EXT_SYNC 0x80 +#define ZSM_EXT_CUSTOM 0xC0 + +enum YM_STATE { ym_PREV, ym_NEW, ym_STATES }; +enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; + +class DivZSM { + private: + struct S_pcmInst { + int geometry; + unsigned int offset, length, loopPoint; + bool isLooped; + }; + SafeWriter* w; + int ymState[ym_STATES][256]; + int psgState[psg_STATES][64]; + int pcmRateCache; + int pcmCtrlRVCache; + int pcmCtrlDCCache; + unsigned int pcmLoopPointCache; + bool pcmIsLooped; + std::vector ymwrites; + std::vector pcmMeta; + std::vector pcmData; + std::vector pcmCache; + std::vector pcmInsts; + std::vector syncCache; + int loopOffset; + int numWrites; + int ticks; + int tickRate; + int ymMask; + int psgMask; + bool optimize; + public: + DivZSM(); + ~DivZSM(); + void init(unsigned int rate = 60); + int getoffset(); + void writeYM(unsigned char a, unsigned char v); + void writePSG(unsigned char a, unsigned char v); + void writePCM(unsigned char a, unsigned char v); + void writeSync(unsigned char a, unsigned char v); + void setOptimize(bool o); + void tick(int numticks = 1); + void setLoopPoint(); + SafeWriter* finish(); + private: + void flushWrites(); + void flushTicks(); +}; + +/// DivZSM implementation DivZSM::DivZSM() { w=NULL; @@ -447,3 +515,240 @@ void DivZSM::flushTicks() { } ticks=0; } + +/// ZSM export + +constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; +constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; + +void DivExportZSM::run() { + // settings + unsigned int zsmrate=conf.getInt("zsmrate",60); + bool loop=conf.getBool("loop",true); + bool optimize=conf.getBool("optimize",true); + + // system IDs + int VERA=-1; + int YM=-1; + int IGNORED=0; + + // find indexes for YM and VERA. Ignore other systems. + for (int i=0; isong.systemLen; i++) { + switch (e->song.system[i]) { + case DIV_SYSTEM_VERA: + if (VERA>=0) { + IGNORED++; + break; + } + VERA=i; + logAppendf("VERA detected as chip id %d",i); + break; + case DIV_SYSTEM_YM2151: + if (YM>=0) { + IGNORED++; + break; + } + YM=i; + logAppendf("YM detected as chip id %d",i); + break; + default: + IGNORED++; + logAppendf("Ignoring chip %d systemID %d",i,(int)e->song.system[i]); + break; + } + } + if (VERA<0 && YM<0) { + logAppend("ERROR: No supported systems for ZSM"); + failed=true; + running=false; + return; + } + if (IGNORED>0) { + logAppendf("ZSM export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); + } + + DivZSM zsm; + + e->stop(); + e->repeatPattern=false; + e->setOrder(0); + e->synchronizedSoft([&]() { + double origRate=e->got.rate; + e->got.rate=zsmrate&0xffff; + + // determine loop point + int loopOrder=0; + int loopRow=0; + int loopEnd=0; + e->walkSong(loopOrder,loopRow,loopEnd); + logAppendf("loop point: %d %d",loopOrder,loopRow); + + zsm.init(zsmrate); + + // reset the playback state + e->curOrder=0; + e->freelance=false; + e->playing=false; + e->extValuePresent=false; + e->remainingLoops=-1; + + // Prepare to write song data + e->playSub(false); + //size_t tickCount=0; + bool done=false; + bool loopNow=false; + int loopPos=-1; + int fracWait=0; // accumulates fractional ticks + if (VERA>=0) e->disCont[VERA].dispatch->toggleRegisterDump(true); + if (YM>=0) { + e->disCont[YM].dispatch->toggleRegisterDump(true); + // emit LFO initialization commands + zsm.writeYM(0x18,0); // freq=0 + zsm.writeYM(0x19,0x7F); // AMD =7F + zsm.writeYM(0x19,0xFF); // PMD =7F + // TODO: incorporate the Furnace meta-command for init data and filter + // out writes to otherwise-unused channels. + } + // Indicate the song's tuning as a sync meta-event + // specified in terms of how many 1/256th semitones + // the song is offset from standard A-440 tuning. + // This is mainly to benefit visualizations in players + // for non-standard tunings so that they can avoid + // displaying the entire song held in pitch bend. + // Tunings offsets that exceed a half semitone + // will simply be represented in a different key + // by nature of overflowing the signed char value + signed char tuningoffset=(signed char)(round(3072*(log(e->song.tuning/440.0)/log(2))))&0xff; + zsm.writeSync(0x01,tuningoffset); + // Set optimize flag, which mainly buffers PSG writes + // whenever the channel is silent + zsm.setOptimize(optimize); + + while (!done) { + if (loopPos==-1) { + if (loopOrder==e->curOrder && loopRow==e->curRow && loop) + loopNow=true; + if (loopNow) { + // If Virtual Tempo is in use, our exact loop point + // might be skipped due to quantization error. + // If this happens, the tick immediately following is our loop point. + if (e->ticks==1 || !(loopOrder==e->curOrder && loopRow==e->curRow)) { + loopPos=zsm.getoffset(); + zsm.setLoopPoint(); + loopNow=false; + } + } + } + if (e->nextTick() || !e->playing) { + done=true; + if (!loop) { + for (int i=0; isong.systemLen; i++) { + e->disCont[i].dispatch->getRegisterWrites().clear(); + } + break; + } + if (!e->playing) { + loopPos=-1; + } + } + // get register dumps + for (int j=0; j<2; j++) { + int i=0; + // dump YM writes first + if (j==0) { + if (YM<0) { + continue; + } else { + i=YM; + } + } + // dump VERA writes second + if (j==1) { + if (VERA<0) { + continue; + } else { + i=VERA; + } + } + std::vector& writes=e->disCont[i].dispatch->getRegisterWrites(); + if (writes.size()>0) + logD("zsmOps: Writing %d messages to chip %d",writes.size(),i); + for (DivRegWrite& write: writes) { + if (i==YM) zsm.writeYM(write.addr&0xff,write.val); + if (i==VERA) { + if (done && write.addr>=64) continue; // don't process any PCM or sync events on the loop lookahead + zsm.writePSG(write.addr&0xff,write.val); + } + } + writes.clear(); + } + + // write wait + int totalWait=e->cycles>>MASTER_CLOCK_PREC; + fracWait+=e->cycles&MASTER_CLOCK_MASK; + totalWait+=fracWait>>MASTER_CLOCK_PREC; + fracWait&=MASTER_CLOCK_MASK; + if (totalWait>0 && !done) { + zsm.tick(totalWait); + //tickCount+=totalWait; + } + } + // end of song + + // done - close out. + e->got.rate=origRate; + if (VERA>=0) e->disCont[VERA].dispatch->toggleRegisterDump(false); + if (YM>=0) e->disCont[YM].dispatch->toggleRegisterDump(false); + + e->remainingLoops=-1; + e->playing=false; + e->freelance=false; + e->extValuePresent=false; + }); + + progress[0].amount=1.0f; + + logAppend("finished!"); + + output.push_back(DivROMExportOutput("out.zsm",zsm.finish())); + running=false; +} + +/// DivExpottZSM - FRONTEND + +bool DivExportZSM::go(DivEngine* eng) { + progress[0].name="Generate"; + progress[0].amount=0.0f; + + e=eng; + running=true; + failed=false; + mustAbort=false; + exportThread=new std::thread(&DivExportZSM::run,this); + return true; +} + +void DivExportZSM::wait() { + if (exportThread!=NULL) { + exportThread->join(); + delete exportThread; + } +} + +void DivExportZSM::abort() { + mustAbort=true; + wait(); +} + +bool DivExportZSM::isRunning() { + return running; +} + +bool DivExportZSM::hasFailed() { + return failed; +} + +DivROMExportProgress DivExportZSM::getProgress(int index) { + if (index<0 || index>1) return progress[1]; + return progress[index]; +} diff --git a/src/engine/export/zsm.h b/src/engine/export/zsm.h new file mode 100644 index 000000000..fd6468608 --- /dev/null +++ b/src/engine/export/zsm.h @@ -0,0 +1,38 @@ +/** + * Furnace Tracker - multi-system chiptune tracker + * Copyright (C) 2021-2024 tildearrow and contributors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "../export.h" + +#include + +class DivExportZSM: public DivROMExport { + DivEngine* e; + std::thread* exportThread; + DivROMExportProgress progress[2]; + bool running, failed, mustAbort; + void run(); + public: + bool go(DivEngine* e); + bool isRunning(); + bool hasFailed(); + void abort(); + void wait(); + DivROMExportProgress getProgress(int index=0); + ~DivExportZSM() {} +}; diff --git a/src/engine/zsm.h b/src/engine/zsm.h deleted file mode 100644 index d1fd8ec04..000000000 --- a/src/engine/zsm.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2024 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _ZSM_H -#define _ZSM_H - -//#include "engine.h" -#include "safeWriter.h" -#include "dispatch.h" -#include - -#define ZSM_HEADER_SIZE 16 -#define ZSM_VERSION 1 -#define ZSM_YM_CMD 0x40 -#define ZSM_DELAY_CMD 0x80 -#define ZSM_YM_MAX_WRITES 63 -#define ZSM_SYNC_MAX_WRITES 31 -#define ZSM_DELAY_MAX 127 -#define ZSM_EOF ZSM_DELAY_CMD - -#define ZSM_EXT ZSM_YM_CMD -#define ZSM_EXT_PCM 0x00 -#define ZSM_EXT_CHIP 0x40 -#define ZSM_EXT_SYNC 0x80 -#define ZSM_EXT_CUSTOM 0xC0 - -enum YM_STATE { ym_PREV, ym_NEW, ym_STATES }; -enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; - -class DivZSM { - private: - struct S_pcmInst { - int geometry; - unsigned int offset, length, loopPoint; - bool isLooped; - }; - SafeWriter* w; - int ymState[ym_STATES][256]; - int psgState[psg_STATES][64]; - int pcmRateCache; - int pcmCtrlRVCache; - int pcmCtrlDCCache; - unsigned int pcmLoopPointCache; - bool pcmIsLooped; - std::vector ymwrites; - std::vector pcmMeta; - std::vector pcmData; - std::vector pcmCache; - std::vector pcmInsts; - std::vector syncCache; - int loopOffset; - int numWrites; - int ticks; - int tickRate; - int ymMask; - int psgMask; - bool optimize; - public: - DivZSM(); - ~DivZSM(); - void init(unsigned int rate = 60); - int getoffset(); - void writeYM(unsigned char a, unsigned char v); - void writePSG(unsigned char a, unsigned char v); - void writePCM(unsigned char a, unsigned char v); - void writeSync(unsigned char a, unsigned char v); - void setOptimize(bool o); - void tick(int numticks = 1); - void setLoopPoint(); - SafeWriter* finish(); - private: - void flushWrites(); - void flushTicks(); -}; - -#endif diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp deleted file mode 100644 index a2f9385ba..000000000 --- a/src/engine/zsmOps.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Furnace Tracker - multi-system chiptune tracker - * Copyright (C) 2021-2024 tildearrow and contributors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "engine.h" -#include "../ta-log.h" -#include "../utfutils.h" -#include "song.h" -#include "zsm.h" - -constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; -constexpr int MASTER_CLOCK_MASK=(sizeof(void*)==8)?0xff:0; - -SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop, bool optimize) { - int VERA=-1; - int YM=-1; - int IGNORED=0; - - // find indexes for YM and VERA. Ignore other systems. - for (int i=0; i=0) { - IGNORED++; - break; - } - VERA=i; - logD("VERA detected as chip id %d",i); - break; - case DIV_SYSTEM_YM2151: - if (YM>=0) { - IGNORED++; - break; - } - YM=i; - logD("YM detected as chip id %d",i); - break; - default: - IGNORED++; - logD("Ignoring chip %d systemID %d",i,(int)song.system[i]); - break; - } - } - if (VERA<0 && YM<0) { - logE("No supported systems for ZSM"); - return NULL; - } - if (IGNORED>0) { - logW("ZSM export ignoring %d unsupported system%c",IGNORED,IGNORED>1?'s':' '); - } - - stop(); - repeatPattern=false; - setOrder(0); - BUSY_BEGIN_SOFT; - - double origRate=got.rate; - got.rate=zsmrate&0xffff; - - // determine loop point - int loopOrder=0; - int loopRow=0; - int loopEnd=0; - walkSong(loopOrder,loopRow,loopEnd); - logI("loop point: %d %d",loopOrder,loopRow); - warnings=""; - - DivZSM zsm; - zsm.init(zsmrate); - - // reset the playback state - curOrder=0; - freelance=false; - playing=false; - extValuePresent=false; - remainingLoops=-1; - - // Prepare to write song data - playSub(false); - //size_t tickCount=0; - bool done=false; - bool loopNow=false; - int loopPos=-1; - int fracWait=0; // accumulates fractional ticks - if (VERA>=0) disCont[VERA].dispatch->toggleRegisterDump(true); - if (YM>=0) { - disCont[YM].dispatch->toggleRegisterDump(true); - // emit LFO initialization commands - zsm.writeYM(0x18,0); // freq=0 - zsm.writeYM(0x19,0x7F); // AMD =7F - zsm.writeYM(0x19,0xFF); // PMD =7F - // TODO: incorporate the Furnace meta-command for init data and filter - // out writes to otherwise-unused channels. - } - // Indicate the song's tuning as a sync meta-event - // specified in terms of how many 1/256th semitones - // the song is offset from standard A-440 tuning. - // This is mainly to benefit visualizations in players - // for non-standard tunings so that they can avoid - // displaying the entire song held in pitch bend. - // Tunings offsets that exceed a half semitone - // will simply be represented in a different key - // by nature of overflowing the signed char value - signed char tuningoffset=(signed char)(round(3072*(log(song.tuning/440.0)/log(2))))&0xff; - zsm.writeSync(0x01,tuningoffset); - // Set optimize flag, which mainly buffers PSG writes - // whenever the channel is silent - zsm.setOptimize(optimize); - - while (!done) { - if (loopPos==-1) { - if (loopOrder==curOrder && loopRow==curRow && loop) - loopNow=true; - if (loopNow) { - // If Virtual Tempo is in use, our exact loop point - // might be skipped due to quantization error. - // If this happens, the tick immediately following is our loop point. - if (ticks==1 || !(loopOrder==curOrder && loopRow==curRow)) { - loopPos=zsm.getoffset(); - zsm.setLoopPoint(); - loopNow=false; - } - } - } - if (nextTick() || !playing) { - done=true; - if (!loop) { - for (int i=0; igetRegisterWrites().clear(); - } - break; - } - if (!playing) { - loopPos=-1; - } - } - // get register dumps - for (int j=0; j<2; j++) { - int i=0; - // dump YM writes first - if (j==0) { - if (YM<0) { - continue; - } else { - i=YM; - } - } - // dump VERA writes second - if (j==1) { - if (VERA<0) { - continue; - } else { - i=VERA; - } - } - std::vector& writes=disCont[i].dispatch->getRegisterWrites(); - if (writes.size()>0) - logD("zsmOps: Writing %d messages to chip %d",writes.size(),i); - for (DivRegWrite& write: writes) { - if (i==YM) zsm.writeYM(write.addr&0xff,write.val); - if (i==VERA) { - if (done && write.addr>=64) continue; // don't process any PCM or sync events on the loop lookahead - zsm.writePSG(write.addr&0xff,write.val); - } - } - writes.clear(); - } - - // write wait - int totalWait=cycles>>MASTER_CLOCK_PREC; - fracWait+=cycles&MASTER_CLOCK_MASK; - totalWait+=fracWait>>MASTER_CLOCK_PREC; - fracWait&=MASTER_CLOCK_MASK; - if (totalWait>0 && !done) { - zsm.tick(totalWait); - //tickCount+=totalWait; - } - } - // end of song - - // done - close out. - got.rate=origRate; - if (VERA>=0) disCont[VERA].dispatch->toggleRegisterDump(false); - if (YM>=0) disCont[YM].dispatch->toggleRegisterDump(false); - - remainingLoops=-1; - playing=false; - freelance=false; - extValuePresent=false; - - BUSY_END; - return zsm.finish(); -} diff --git a/src/gui/exportOptions.cpp b/src/gui/exportOptions.cpp index bb223aac4..7b6e699dd 100644 --- a/src/gui/exportOptions.cpp +++ b/src/gui/exportOptions.cpp @@ -319,6 +319,29 @@ void FurnaceGUI::drawExportROM(bool onWindow) { } break; } + case DIV_ROM_ZSM: { + int zsmExportTickRate=romConfig.getInt("zsmrate",60); + bool zsmExportLoop=romConfig.getBool("loop",true); + bool zsmExportOptimize=romConfig.getBool("optimize",true); + + if (ImGui::InputInt(_("Tick Rate (Hz)"),&zsmExportTickRate,1,2)) { + if (zsmExportTickRate<1) zsmExportTickRate=1; + if (zsmExportTickRate>44100) zsmExportTickRate=44100; + altered=true; + } + if (ImGui::Checkbox(_("loop"),&zsmExportLoop)) { + altered=true; + } + if (ImGui::Checkbox(_("optimize size"),&zsmExportOptimize)) { + altered=true; + } + if (altered) { + romConfig.set("zsmrate",zsmExportTickRate); + romConfig.set("loop",zsmExportLoop); + romConfig.set("optimize",zsmExportOptimize); + } + break; + } case DIV_ROM_ABSTRACT: ImGui::TextWrapped("%s",_("select a target from the menu at the top of this dialog.")); break; @@ -340,28 +363,6 @@ void FurnaceGUI::drawExportROM(bool onWindow) { } } -void FurnaceGUI::drawExportZSM(bool onWindow) { - exitDisabledTimer=1; - - ImGui::Text(_("Commander X16 Zsound Music File")); - if (ImGui::InputInt(_("Tick Rate (Hz)"),&zsmExportTickRate,1,2)) { - if (zsmExportTickRate<1) zsmExportTickRate=1; - if (zsmExportTickRate>44100) zsmExportTickRate=44100; - } - ImGui::Checkbox(_("loop"),&zsmExportLoop); - ImGui::SameLine(); - ImGui::Checkbox(_("optimize size"),&zsmExportOptimize); - if (onWindow) { - ImGui::Separator(); - if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup(); - ImGui::SameLine(); - } - if (ImGui::Button(_("Export"),ImVec2(200.0f*dpiScale,0))) { - openFileDialog(GUI_FILE_EXPORT_ZSM); - ImGui::CloseCurrentPopup(); - } -} - void FurnaceGUI::drawExportText(bool onWindow) { exitDisabledTimer=1; @@ -444,16 +445,6 @@ void FurnaceGUI::drawExport() { ImGui::EndTabItem(); } } - int numZSMCompat=0; - for (int i=0; isong.systemLen; i++) { - if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; - } - if (numZSMCompat>0) { - if (ImGui::BeginTabItem(_("ZSM"))) { - drawExportZSM(true); - ImGui::EndTabItem(); - } - } if (ImGui::BeginTabItem(_("Text"))) { drawExportText(true); ImGui::EndTabItem(); @@ -478,9 +469,6 @@ void FurnaceGUI::drawExport() { case GUI_EXPORT_ROM: drawExportROM(true); break; - case GUI_EXPORT_ZSM: - drawExportZSM(true); - break; case GUI_EXPORT_TEXT: drawExportText(true); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 95e8ffd36..6a8514a1b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2022,16 +2022,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { (settings.autoFillSave)?shortName:"" ); break; - case GUI_FILE_EXPORT_ZSM: - if (!dirExists(workingDirZSMExport)) workingDirZSMExport=getHomeDir(); - hasOpened=fileDialog->openSave( - _("Export ZSM"), - {_("ZSM file"), "*.zsm"}, - workingDirZSMExport, - dpiScale, - (settings.autoFillSave)?shortName:"" - ); - break; case GUI_FILE_EXPORT_TEXT: if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir(); hasOpened=fileDialog->openSave( @@ -4405,16 +4395,6 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } } - int numZSMCompat=0; - for (int i=0; isong.systemLen; i++) { - if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; - } - if (numZSMCompat>0) { - if (ImGui::BeginMenu(_("export ZSM..."))) { - drawExportZSM(); - ImGui::EndMenu(); - } - } if (ImGui::BeginMenu(_("export text..."))) { drawExportText(); ImGui::EndMenu(); @@ -4442,16 +4422,6 @@ bool FurnaceGUI::loop() { displayExport=true; } } - int numZSMCompat=0; - for (int i=0; isong.systemLen; i++) { - if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++; - } - if (numZSMCompat>0) { - if (ImGui::MenuItem(_("export ZSM..."))) { - curExportType=GUI_EXPORT_ZSM; - displayExport=true; - } - } if (ImGui::MenuItem(_("export text..."))) { curExportType=GUI_EXPORT_TEXT; displayExport=true; @@ -5034,9 +5004,6 @@ bool FurnaceGUI::loop() { case GUI_FILE_EXPORT_VGM: workingDirVGMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; break; - case GUI_FILE_EXPORT_ZSM: - workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR; - break; case GUI_FILE_EXPORT_ROM: case GUI_FILE_EXPORT_TEXT: case GUI_FILE_EXPORT_CMDSTREAM: @@ -5136,9 +5103,6 @@ bool FurnaceGUI::loop() { if (curFileDialog==GUI_FILE_EXPORT_ROM) { checkExtension(romFilterExt.c_str()); } - if (curFileDialog==GUI_FILE_EXPORT_ZSM) { - checkExtension(".zsm"); - } if (curFileDialog==GUI_FILE_EXPORT_TEXT) { checkExtension(".txt"); } @@ -5614,27 +5578,6 @@ bool FurnaceGUI::loop() { } break; } - case GUI_FILE_EXPORT_ZSM: { - SafeWriter* w=e->saveZSM(zsmExportTickRate,zsmExportLoop,zsmExportOptimize); - if (w!=NULL) { - FILE* f=ps_fopen(copyOfName.c_str(),"wb"); - if (f!=NULL) { - fwrite(w->getFinalBuf(),1,w->size(),f); - fclose(f); - pushRecentSys(copyOfName.c_str()); - } else { - showError(_("could not open file!")); - } - w->finish(); - delete w; - if (!e->getWarnings().empty()) { - showWarning(e->getWarnings(),GUI_WARN_GENERIC); - } - } else { - showError(fmt::sprintf(_("Could not write ZSM! (%s)"),e->getLastError())); - } - break; - } case GUI_FILE_EXPORT_ROM: romExportPath=copyOfName; pendingExport=e->buildROM(romTarget); @@ -7879,7 +7822,6 @@ void FurnaceGUI::syncState() { workingDirSample=e->getConfString("lastDirSample",workingDir); workingDirAudioExport=e->getConfString("lastDirAudioExport",workingDir); workingDirVGMExport=e->getConfString("lastDirVGMExport",workingDir); - workingDirZSMExport=e->getConfString("lastDirZSMExport",workingDir); workingDirROMExport=e->getConfString("lastDirROMExport",workingDir); workingDirFont=e->getConfString("lastDirFont",workingDir); workingDirColors=e->getConfString("lastDirColors",workingDir); @@ -8038,7 +7980,6 @@ void FurnaceGUI::commitState(DivConfig& conf) { conf.set("lastDirSample",workingDirSample); conf.set("lastDirAudioExport",workingDirAudioExport); conf.set("lastDirVGMExport",workingDirVGMExport); - conf.set("lastDirZSMExport",workingDirZSMExport); conf.set("lastDirROMExport",workingDirROMExport); conf.set("lastDirFont",workingDirFont); conf.set("lastDirColors",workingDirColors); @@ -8256,8 +8197,6 @@ FurnaceGUI::FurnaceGUI(): displayError(false), displayExporting(false), vgmExportLoop(true), - zsmExportLoop(true), - zsmExportOptimize(true), vgmExportPatternHints(false), vgmExportDirectStream(false), displayInsTypeList(false), @@ -8300,7 +8239,6 @@ FurnaceGUI::FurnaceGUI(): vgmExportVersion(0x171), vgmExportTrailingTicks(-1), drawHalt(10), - zsmExportTickRate(60), macroPointSize(16), waveEditStyle(0), displayInsTypeListMakeInsSample(-1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 59413e3e1..adc066229 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -598,7 +598,6 @@ enum FurnaceGUIFileDialogs { GUI_FILE_EXPORT_AUDIO_PER_SYS, GUI_FILE_EXPORT_AUDIO_PER_CHANNEL, GUI_FILE_EXPORT_VGM, - GUI_FILE_EXPORT_ZSM, GUI_FILE_EXPORT_CMDSTREAM, GUI_FILE_EXPORT_TEXT, GUI_FILE_EXPORT_ROM, @@ -651,7 +650,6 @@ enum FurnaceGUIExportTypes { GUI_EXPORT_AUDIO=0, GUI_EXPORT_VGM, GUI_EXPORT_ROM, - GUI_EXPORT_ZSM, GUI_EXPORT_CMD_STREAM, GUI_EXPORT_TEXT, GUI_EXPORT_DMF @@ -1594,7 +1592,7 @@ class FurnaceGUI { String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery, newSongQuery, paletteQuery, sampleBankSearchQuery; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport; - String workingDirVGMExport, workingDirZSMExport, workingDirROMExport; + String workingDirVGMExport, workingDirROMExport; String workingDirFont, workingDirColors, workingDirKeybinds; String workingDirLayout, workingDirROM, workingDirTest; String workingDirConfig; @@ -1613,7 +1611,7 @@ class FurnaceGUI { std::vector availRenderDrivers; std::vector availAudioDrivers; - bool quit, warnQuit, willCommit, edit, editClone, isPatUnique, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, zsmExportOptimize, vgmExportPatternHints; + bool quit, warnQuit, willCommit, edit, editClone, isPatUnique, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints; bool vgmExportDirectStream, displayInsTypeList, displayWaveSizeList; bool portrait, injectBackUp, mobileMenuOpen, warnColorPushed; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; @@ -1634,7 +1632,6 @@ class FurnaceGUI { int vgmExportTrailingTicks; int cvHiScore; int drawHalt; - int zsmExportTickRate; int macroPointSize; int waveEditStyle; int displayInsTypeListMakeInsSample; @@ -2700,7 +2697,6 @@ class FurnaceGUI { void drawExportAudio(bool onWindow=false); void drawExportVGM(bool onWindow=false); void drawExportROM(bool onWindow=false); - void drawExportZSM(bool onWindow=false); void drawExportText(bool onWindow=false); void drawExportCommand(bool onWindow=false); void drawExportDMF(bool onWindow=false); diff --git a/src/main.cpp b/src/main.cpp index ac6e231b2..30b551a83 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,7 +85,6 @@ FurnaceCLI cli; String outName; String vgmOutName; -String zsmOutName; String cmdOutName; int benchMode=0; int subsong=-1; @@ -429,12 +428,6 @@ TAParamResult pVGMOut(String val) { return TA_PARAM_SUCCESS; } -TAParamResult pZSMOut(String val) { - zsmOutName=val; - e.setAudio(DIV_AUDIO_DUMMY); - return TA_PARAM_SUCCESS; -} - TAParamResult pCmdOut(String val) { cmdOutName=val; e.setAudio(DIV_AUDIO_DUMMY); @@ -457,7 +450,6 @@ void initParams() { params.push_back(TAParam("o","output",true,pOutput,"","output audio to file")); params.push_back(TAParam("O","vgmout",true,pVGMOut,"","output .vgm data")); params.push_back(TAParam("D","direct",false,pDirect,"","set VGM export direct stream mode")); - params.push_back(TAParam("Z","zsmout",true,pZSMOut,"","output .zsm data for Commander X16 Zsound")); params.push_back(TAParam("C","cmdout",true,pCmdOut,"","output command stream")); params.push_back(TAParam("L","loglevel",true,pLogLevel,"debug|info|warning|error","set the log level (info by default)")); params.push_back(TAParam("v","view",true,pView,"pattern|commands|nothing","set visualization (nothing by default)")); @@ -560,7 +552,6 @@ int main(int argc, char** argv) { #endif outName=""; vgmOutName=""; - zsmOutName=""; cmdOutName=""; // load config for locale @@ -729,14 +720,14 @@ int main(int argc, char** argv) { return 1; } - if (fileName.empty() && (benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) { + if (fileName.empty() && (benchMode || infoMode || outName!="" || vgmOutName!="" || cmdOutName!="")) { logE("provide a file!"); return 1; } #ifdef HAVE_GUI - if (e.preInit(consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) { - if (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="") { + if (e.preInit(consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || cmdOutName!="")) { + if (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || cmdOutName!="") { logW("engine wants safe mode, but Furnace GUI is not going to start."); } else { safeMode=true; @@ -748,7 +739,7 @@ int main(int argc, char** argv) { } #endif - if (safeMode && (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) { + if (safeMode && (consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || cmdOutName!="")) { logE("you can't use safe mode and console/export mode together."); return 1; } @@ -757,7 +748,7 @@ int main(int argc, char** argv) { e.setAudio(DIV_AUDIO_DUMMY); } - if (!fileName.empty() && ((!e.getConfBool("tutIntroPlayed",TUT_INTRO_PLAYED)) || e.getConfInt("alwaysPlayIntro",0)!=3 || consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="")) { + if (!fileName.empty() && ((!e.getConfBool("tutIntroPlayed",TUT_INTRO_PLAYED)) || e.getConfInt("alwaysPlayIntro",0)!=3 || consoleMode || benchMode || infoMode || outName!="" || vgmOutName!="" || cmdOutName!="")) { logI("loading module..."); FILE* f=ps_fopen(fileName.c_str(),"rb"); if (f==NULL) { @@ -849,7 +840,7 @@ int main(int argc, char** argv) { return 0; } - if (outName!="" || vgmOutName!="" || zsmOutName!="" || cmdOutName!="") { + if (outName!="" || vgmOutName!="" || cmdOutName!="") { if (cmdOutName!="") { SafeWriter* w=e.saveCommand(); if (w!=NULL) { @@ -882,23 +873,6 @@ int main(int argc, char** argv) { reportError(_("could not write VGM!")); } } - if (zsmOutName!="") { - // TODO: changing parameters - SafeWriter* w=e.saveZSM(60,true,true); - if (w!=NULL) { - FILE* f=ps_fopen(zsmOutName.c_str(),"wb"); - if (f!=NULL) { - fwrite(w->getFinalBuf(),1,w->size(),f); - fclose(f); - } else { - reportError(fmt::sprintf(_("could not open file! (%s)"),e.getLastError())); - } - w->finish(); - delete w; - } else { - reportError(fmt::sprintf(_("could not write ZSM! (%s)"),e.getLastError())); - } - } if (outName!="") { e.setConsoleMode(true); e.saveAudio(outName.c_str(),exportOptions); From 2dac603f1796836a69c33a95a8819dcbc5a98b9a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Aug 2024 17:23:09 -0500 Subject: [PATCH 02/23] GUI: fix indentation --- src/gui/presets.cpp | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 1ecb39204..0421c149f 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1204,62 +1204,62 @@ void FurnaceGUI::initSystemPresets() { } ); SUB_ENTRY( - "Sega TeraDrive", { - CH(DIV_SYSTEM_YM2612, 1.0f, 0, ""), - CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), - CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") + "Sega TeraDrive", { + CH(DIV_SYSTEM_YM2612, 1.0f, 0, ""), + CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") } ); SUB_SUB_ENTRY( - "Sega TeraDrive (extended channel 3)", { - CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, ""), - CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), - CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") + "Sega TeraDrive (extended channel 3)", { + CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, ""), + CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") } ); SUB_SUB_ENTRY( - "Sega TeraDrive (CSM)", { - CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0, ""), - CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), - CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") + "Sega TeraDrive (CSM)", { + CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0, ""), + CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") } ); SUB_SUB_ENTRY( - "Sega TeraDrive (DualPCM)", { - CH(DIV_SYSTEM_YM2612_DUALPCM, 1.0f, 0, ""), - CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), - CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") + "Sega TeraDrive (DualPCM)", { + CH(DIV_SYSTEM_YM2612_DUALPCM, 1.0f, 0, ""), + CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") } ); SUB_SUB_ENTRY( - "Sega TeraDrive (DualPCM, extended channel 3)", { - CH(DIV_SYSTEM_YM2612_DUALPCM_EXT, 1.0f, 0, ""), - CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), - CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") + "Sega TeraDrive (DualPCM, extended channel 3)", { + CH(DIV_SYSTEM_YM2612_DUALPCM_EXT, 1.0f, 0, ""), + CH(DIV_SYSTEM_SMS, 0.5f, 0, ""), + CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "") } ); ENTRY( "Sharp X1", { CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=3") - } + } ); SUB_ENTRY( "Sharp X1 + FM Addon", { CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=3"), CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2") - } + } ); ENTRY( "Sharp X68000", { CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2"), CH(DIV_SYSTEM_MSM6258, 1.0f, 0, "clockSel=2") - } + } ); ENTRY( "FM-7", { CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=12"), CH(DIV_SYSTEM_YM2203, 1.0f, 0, "clockSel=5") - } + } ); SUB_ENTRY( "FM-7 (extended channel 3)", { From 272fcfccca471973cc4d0ea18bfb4668ee71f03a Mon Sep 17 00:00:00 2001 From: Jankboy <59789453+Jankboy@users.noreply.github.com> Date: Mon, 19 Aug 2024 06:29:39 +0800 Subject: [PATCH 03/23] Merge PO files conveniently via scripts (#2070) * Add files via upload This script can merge the post-translation order wrong PO files in the correct order! * Update and rename merge.py to MERGE.py Changed the name to all caps to make it prominent * Update MERGE.py * Update and rename MERGE.py to Reorganize-po-sequence.py rename * Reorganize-po-sequence Usage: Reorganize-po-sequence.sh base_file new_file output_file base.po is the PO file within the repo with the correct order new.po is your translated PO file but may not be in the correct order --- po/Reorganize-po-sequence.py | 42 ++++++++++++++++++++++++ scripts/Reorganize-po-sequence.sh | 54 +++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 po/Reorganize-po-sequence.py create mode 100644 scripts/Reorganize-po-sequence.sh diff --git a/po/Reorganize-po-sequence.py b/po/Reorganize-po-sequence.py new file mode 100644 index 000000000..69b953a96 --- /dev/null +++ b/po/Reorganize-po-sequence.py @@ -0,0 +1,42 @@ +def merge_po_files_preserve_format(base_file, new_file, output_file): + with open(base_file, 'r', encoding='utf-8') as f1, open(new_file, 'r', encoding='utf-8') as f2: + base_lines = f1.readlines() + new_lines = f2.readlines() + + # Traverse the new_lines and extract msgid and msgstr + new_translations = {} + i = 0 + while i < len(new_lines): + if new_lines[i].startswith('msgid '): + msgid_start = i + while not new_lines[i].startswith('msgstr '): + i += 1 + msgid = ''.join(new_lines[msgid_start:i]) + msgstr = new_lines[i].split('msgstr ')[1].strip() + new_translations[msgid] = msgstr + i += 1 + + # Open the output_file and write the merged content + with open(output_file, 'w', encoding='utf-8') as output: + i = 0 + while i < len(base_lines): + if base_lines[i].startswith('msgid '): + msgid_start = i + while not base_lines[i].startswith('msgstr '): + i += 1 + msgid = ''.join(base_lines[msgid_start:i]) + if msgid in new_translations: + output.write(f'{msgid}') + output.write(f'msgstr {new_translations[msgid]}\n') + else: + output.write(base_lines[i]) + i += 1 + else: + output.write(base_lines[i]) + i += 1 + +if __name__ == '__main__': + base_file = 'base.po' + new_file = 'new.po' + output_file = 'output.po' + merge_po_files_preserve_format(base_file, new_file, output_file) diff --git a/scripts/Reorganize-po-sequence.sh b/scripts/Reorganize-po-sequence.sh new file mode 100644 index 000000000..98ff5bd94 --- /dev/null +++ b/scripts/Reorganize-po-sequence.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +merge_po_files_preserve_format() { + base_file="base.po" + new_file="new.po" + output_file="output.po" + + declare -A new_translations + + # Read new_file and extract msgid and msgstr + msgid="" + while IFS= read -r line; do + if [[ $line == msgid* ]]; then + msgid="$line" + msgstr="" + elif [[ $line == msgstr* ]]; then + msgstr="$line" + new_translations["$msgid"]="$msgstr" + elif [[ $line == "\"\"" ]]; then + msgid+="$line" + fi + done < "$new_file" + + # Open output_file and write merged content + msgid="" + while IFS= read -r line; do + if [[ $line == msgid* ]]; then + msgid="$line" + msgstr="" + elif [[ $line == msgstr* ]]; then + msgstr="$line" + if [[ -n ${new_translations["$msgid"]} ]]; then + echo "$msgid" >> "$output_file" + echo "${new_translations["$msgid"]}" >> "$output_file" + else + echo "$msgid" >> "$output_file" + echo "$msgstr" >> "$output_file" + fi + msgid="" + msgstr="" + elif [[ $line == "\"\"" ]]; then + msgid+="$line" + else + echo "$line" >> "$output_file" + fi + done < "$base_file" +} + +if [[ $# -ne 3 ]]; then + echo "Usage: $0 base_file new_file output_file" + exit 1 +fi + +merge_po_files_preserve_format "base.po" "new.po" "output.po" From a318508b40281a3a150d4bb36139652ee65c18f8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Aug 2024 18:18:25 -0500 Subject: [PATCH 04/23] 0.5 leftover --- src/engine/fileOpsSample.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOpsSample.cpp b/src/engine/fileOpsSample.cpp index 5008392f8..aed0db7b8 100644 --- a/src/engine/fileOpsSample.cpp +++ b/src/engine/fileOpsSample.cpp @@ -401,8 +401,8 @@ std::vector DivEngine::sampleFromFile(const char* path) { sample->loop=false; } - if (sample->centerRate<4000) sample->centerRate=4000; - if (sample->centerRate>64000) sample->centerRate=64000; + if (sample->centerRate<100) sample->centerRate=100; + if (sample->centerRate>384000) sample->centerRate=384000; sfWrap.doClose(); BUSY_END; ret.push_back(sample); From 5c9fd69ac1c06e4001f43373b4f6cfbad8d08f46 Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 4 Aug 2024 21:07:08 -0700 Subject: [PATCH 05/23] add undo to instrument editor (check for diffs on the current DivInstrument in insEdit, record them in a stack) --- src/engine/instrument.cpp | 139 ++++++++++++++++++++++++++++++++++++++ src/engine/instrument.h | 70 +++++++++++++++++-- src/fixedQueue.h | 93 ++++++++++++------------- src/gui/debugWindow.cpp | 2 +- src/gui/doAction.cpp | 4 ++ src/gui/gui.cpp | 1 + src/gui/gui.h | 5 ++ src/gui/insEdit.cpp | 48 ++++++++++++- 8 files changed, 307 insertions(+), 55 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index ad5ebe8e1..2f80aaca1 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "dataErrors.h" #include "engine.h" #include "instrument.h" @@ -363,6 +364,144 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) { FEATURE_END; } +void MemPatch::clear() { + data = nullptr; + offset = 0; + size = 0; +} + +bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { + bool diffValid = false; + size_t firstDiff = 0; + size_t lastDiff = 0; + const uint8_t* preBytes = (const uint8_t*)pre; + const uint8_t* postBytes = (const uint8_t*)post; + + for (size_t ii = 0; ii < inputSize; ++ii) { + if (preBytes[ii] != postBytes[ii]) { + lastDiff=ii; + firstDiff=diffValid ? firstDiff : ii; + diffValid=true; + } + } + + if (diffValid) { + offset = firstDiff; + size = lastDiff - firstDiff + 1; + data = new uint8_t[size]; + + // the diff is to make pre into post (MemPatch is general, not specific to + // undo), so copy from postBytes + memcpy(data, postBytes + offset, size); + } + + return diffValid; +} + +void MemPatch::applyAndReverse(void* target, size_t targetSize) { + if (size == 0) { return; } + assert(offset + size <= targetSize); + uint8_t* targetBytes = (uint8_t*)target; + + // swap this->data and its segment on target + for (size_t ii = 0; ii < size; ++ii) { + uint8_t tmp = targetBytes[offset + ii]; + targetBytes[offset + ii] = data[ii]; + data[ii] = tmp; + } +} + +void DivInstrumentUndoStep::clear() { + podPatch.clear(); + name.clear(); +} + +void DivInstrumentUndoStep::applyAndReverse(DivInstrument* target) { + if (nameValid) { + name.swap(target->name); + } + podPatch.applyAndReverse((DivInstrumentPOD*)target, sizeof(DivInstrumentPOD)); +} + +bool DivInstrumentUndoStep::makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post) { + processTime = processTime_; + + // create the patch that will make post into pre + podPatch.calcDiff((const DivInstrumentPOD*)post, (const DivInstrumentPOD*)pre, sizeof(DivInstrumentPOD)); + if (pre->name.compare(post->name) != 0) { + nameValid = true; + name = pre->name; + } + + return nameValid || podPatch.isValid(); +} + +void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrument* old) { + DivInstrumentUndoStep step; + + // generate a patch to go back to old + if (step.makeUndoPatch(processTime, old, this)) { + + // make room + if (undoHist.size() >= undoHist.capacity()) { + DivInstrumentUndoStep* step = undoHist.front(); + delete step; + undoHist.pop_front(); + } + + // clear redo + while (!redoHist.empty()) { + delete redoHist.back(); + redoHist.pop_back(); + } + + DivInstrumentUndoStep* stepPtr = new DivInstrumentUndoStep; + *stepPtr = step; + step.clear(); // don't let it delete the data ptr that's been copied! + undoHist.push_back(stepPtr); + + logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); + } +} + +int DivInstrument::undo() { + if (undoHist.empty()) { return 0; } + + DivInstrumentUndoStep* step = undoHist.back(); + undoHist.pop_back(); + logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + step->applyAndReverse(this); + + // make room + if (redoHist.size() >= redoHist.capacity()) { + DivInstrumentUndoStep* step = redoHist.front(); + delete step; + redoHist.pop_front(); + } + redoHist.push_back(step); + + return 1; +} + +int DivInstrument::redo() { + if (redoHist.empty()) { return 0; } + + DivInstrumentUndoStep* step = redoHist.back(); + redoHist.pop_back(); + logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + step->applyAndReverse(this); + + // make room + if (undoHist.size() >= undoHist.capacity()) { + DivInstrumentUndoStep* step = undoHist.front(); + delete step; + undoHist.pop_front(); + } + undoHist.push_back(step); + + return 1; +} + void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m) { if (!m.len) return; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 49b2991d4..c4fd743cd 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -23,8 +23,10 @@ #include "dataErrors.h" #include "../ta-utils.h" #include "../pch.h" +#include "../fixedQueue.h" struct DivSong; +struct DivInstrument; // NOTICE! // before adding new instrument types to this struct, please ask me first. @@ -860,8 +862,7 @@ struct DivInstrumentSID2 { noiseMode(0) {} }; -struct DivInstrument { - String name; +struct DivInstrumentPOD { DivInstrumentType type; DivInstrumentFM fm; DivInstrumentSTD std; @@ -880,6 +881,63 @@ struct DivInstrument { DivInstrumentPowerNoise powernoise; DivInstrumentSID2 sid2; + DivInstrumentPOD() : + type(DIV_INS_FM) { + } +}; + +struct MemPatch { + MemPatch() : + data(nullptr) + , offset(0) + , size(0) { + } + + ~MemPatch() { + if (data) { + free(data); + } + } + + void clear(); + bool calcDiff(const void* pre, const void* post, size_t size); + void applyAndReverse(void* target, size_t inputSize); + bool isValid() const { return size > 0; } + + uint8_t* data; + size_t offset; + size_t size; +}; + +struct DivInstrumentUndoStep { + DivInstrumentUndoStep() : + name(""), + nameValid(false), + processTime(0) { + } + + MemPatch podPatch; + String name; + bool nameValid; + size_t processTime; + + void clear(); + void applyAndReverse(DivInstrument* target); + bool makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post); +}; + +struct DivInstrument : DivInstrumentPOD { + String name; + + /** + * undo stuff + */ + FixedQueue undoHist; + FixedQueue redoHist; + void recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); + int undo(); + int redo(); + /** * these are internal functions. */ @@ -964,9 +1022,11 @@ struct DivInstrument { * @return whether it was successful. */ bool saveDMP(const char* path); - DivInstrument(): - name(""), - type(DIV_INS_FM) { + DivInstrument() : + name("") { + // clear and construct DivInstrumentPOD so it doesn't have any garbage in the padding + memset((DivInstrumentPOD*)this, 0, sizeof(DivInstrumentPOD)); + new ((DivInstrumentPOD*)this) DivInstrumentPOD; } }; #endif diff --git a/src/fixedQueue.h b/src/fixedQueue.h index 68f883edc..f781b3d33 100644 --- a/src/fixedQueue.h +++ b/src/fixedQueue.h @@ -24,7 +24,7 @@ #include "ta-log.h" template struct FixedQueue { - size_t readPos, writePos; + size_t readPos, curSize; T data[items]; T& operator[](size_t pos); @@ -41,17 +41,21 @@ template struct FixedQueue { bool push_back(const T& item); void clear(); bool empty(); + size_t writePos(); size_t size(); + size_t capacity(); FixedQueue(): readPos(0), - writePos(0) {} + curSize(0) {} }; template T& FixedQueue::operator[](size_t pos) { - if (pos>=size()) { + if (pos>=curSize) { logW("accessing invalid position. bug!"); } - return data[(readPos+pos)%items]; + size_t idx=readPos+pos; + if (idx>=items) idx-=items; + return data[idx]; } template T& FixedQueue::front() { @@ -59,12 +63,13 @@ template T& FixedQueue::front() { } template T& FixedQueue::back() { - if (writePos==0) return data[items-1]; - return data[writePos-1]; + if (curSize==0) return data[0]; + size_t idx=readPos+curSize-1; + if (idx>=items) idx-=items; + return data[idx]; } template bool FixedQueue::erase(size_t pos) { - size_t curSize=size(); if (pos>=curSize) { logW("accessing invalid position. bug!"); return false; @@ -84,72 +89,56 @@ template bool FixedQueue::erase(size_t pos) p1++; } - if (writePos>0) { - writePos--; - } else { - writePos=items-1; - } - + curSize--; return true; } template bool FixedQueue::pop() { - if (readPos==writePos) return false; - if (++readPos>=items) readPos=0; + if (curSize==0) return false; + curSize--; return true; } template bool FixedQueue::push(const T& item) { - if (writePos==(readPos-1)) { + if (curSize==items) { //logW("queue overflow!"); return false; } - if (writePos==items-1 && readPos==0) { - //logW("queue overflow!"); - return false; - } - data[writePos]=item; - if (++writePos>=items) writePos=0; + size_t idx=readPos+curSize; + if (idx>=items) { idx-=items; } + data[idx]=item; + curSize++; return true; } template bool FixedQueue::pop_front() { - if (readPos==writePos) return false; + if (curSize==0) return false; if (++readPos>=items) readPos=0; + curSize--; return true; } template bool FixedQueue::push_back(const T& item) { - if (writePos==(readPos-1)) { + if (curSize==items) { //logW("queue overflow!"); return false; } - if (writePos==items-1 && readPos==0) { - //logW("queue overflow!"); - return false; - } - data[writePos]=item; - if (++writePos>=items) writePos=0; + size_t idx=readPos+curSize; + if (idx>=items) { idx-=items; } + data[idx]=item; + curSize++; return true; } template bool FixedQueue::pop_back() { - if (readPos==writePos) return false; - if (writePos>0) { - writePos--; - } else { - writePos=items-1; - } + if (curSize==0) return false; + curSize--; return true; } template bool FixedQueue::push_front(const T& item) { - if (readPos==(writePos+1)) { - //logW("stack overflow!"); - return false; - } - if (readPos==0 && writePos==items-1) { - //logW("stack overflow!"); + if (curSize==items) { + //logW("queue overflow!"); return false; } if (readPos>0) { @@ -158,23 +147,31 @@ template bool FixedQueue::push_front(const T readPos=items-1; } data[readPos]=item; + curSize++; return true; } template void FixedQueue::clear() { readPos=0; - writePos=0; + curSize=0; } template bool FixedQueue::empty() { - return (readPos==writePos); + return curSize==0; +} + +template size_t FixedQueue::writePos() { + size_t idx=readPos+curSize; + if (idx>=items) { idx-=items; } + return idx; } template size_t FixedQueue::size() { - if (readPos>writePos) { - return items+writePos-readPos; - } - return writePos-readPos; + return curSize; +} + +template size_t FixedQueue::capacity() { + return items; } #endif diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index b08c60532..25969d2ec 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -605,7 +605,7 @@ void FurnaceGUI::drawDebug() { } if (ImGui::TreeNode("Recent Files")) { ImGui::Text("Items: %d - Max: %d",(int)recentFile.size(),settings.maxRecentFile); - ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos); + ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos()); ImGui::Indent(); for (size_t i=0; i localeExtraRanges; DivInstrument* prevInsData; + DivInstrument cachedCurIns; + DivInstrument* cachedCurInsPtr; unsigned char* pendingLayoutImport; size_t pendingLayoutImportLen; @@ -2922,6 +2924,9 @@ class FurnaceGUI { void doUndoSample(); void doRedoSample(); + void doUndoInstrument(); + void doRedoInstrument(); + void play(int row=0); void setOrder(unsigned char order, bool forced=false); void stop(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 99dbf26dc..8fb588a98 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5250,6 +5250,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) { + DivInstrument* ins=nullptr; if (curIns==-2) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("waiting...")); @@ -5277,6 +5278,7 @@ void FurnaceGUI::drawInsEdit() { curIns=i; wavePreviewInit=true; updateFMPreview=true; + ins = e->song.ins[curIns]; } } ImGui::EndCombo(); @@ -5299,7 +5301,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } } else { - DivInstrument* ins=e->song.ins[curIns]; + ins=e->song.ins[curIns]; if (updateFMPreview) { renderFMPreview(ins); updateFMPreview=false; @@ -7738,7 +7740,51 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndPopup(); } + + if (ins) { + bool insChanged = ins != cachedCurInsPtr; + bool delayDiff = ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; + + // check against the last cached to see if diff -- note that modifications to instruments happen outside + // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) + if (!insChanged && !delayDiff) { + ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); + } + + if (insChanged || !delayDiff) { + cachedCurIns = *ins; + } + + cachedCurInsPtr = ins; + } else { + cachedCurInsPtr = nullptr; + } } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; ImGui::End(); } + +void FurnaceGUI::doUndoInstrument() { + if (!insEditOpen) return; + if (curIns<0 || curIns>=(int)e->song.ins.size()) return; + DivInstrument* ins=e->song.ins[curIns]; + // is locking the engine necessary? copied from doUndoSample + e->lockEngine([this,ins]() { + ins->undo(); + cachedCurInsPtr=ins; + cachedCurIns=*ins; + }); +} + +void FurnaceGUI::doRedoInstrument() { + if (!insEditOpen) return; + if (curIns<0 || curIns>=(int)e->song.ins.size()) return; + DivInstrument* ins=e->song.ins[curIns]; + // is locking the engine necessary? copied from doRedoSample + e->lockEngine([this,ins]() { + ins->redo(); + cachedCurInsPtr=ins; + cachedCurIns=*ins; + }); +} From 15d47d0aae9c78f3c77979c39b7cd7e90d807751 Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 4 Aug 2024 21:59:30 -0700 Subject: [PATCH 06/23] style fixes --- src/engine/instrument.cpp | 66 +++++++++++++++++++-------------------- src/engine/instrument.h | 6 ++-- src/gui/insEdit.cpp | 12 +++---- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 2f80aaca1..bccd14acb 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -365,19 +365,19 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) { } void MemPatch::clear() { - data = nullptr; - offset = 0; - size = 0; + data = NULL; + offset=0; + size=0; } bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { - bool diffValid = false; - size_t firstDiff = 0; - size_t lastDiff = 0; - const uint8_t* preBytes = (const uint8_t*)pre; - const uint8_t* postBytes = (const uint8_t*)post; + bool diffValid=false; + size_t firstDiff=0; + size_t lastDiff=0; + const unsigned char* preBytes=(const unsigned char*)pre; + const unsigned char* postBytes=(const unsigned char*)post; - for (size_t ii = 0; ii < inputSize; ++ii) { + for (size_t ii=0; iidata and its segment on target - for (size_t ii = 0; ii < size; ++ii) { - uint8_t tmp = targetBytes[offset + ii]; - targetBytes[offset + ii] = data[ii]; + for (size_t ii=0; iiname.compare(post->name) != 0) { - nameValid = true; - name = pre->name; + if (pre->name!=post->name != 0) { + nameValid=true; + name=pre->name; } return nameValid || podPatch.isValid(); @@ -443,7 +443,7 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum if (step.makeUndoPatch(processTime, old, this)) { // make room - if (undoHist.size() >= undoHist.capacity()) { + if (undoHist.size()>=undoHist.capacity()) { DivInstrumentUndoStep* step = undoHist.front(); delete step; undoHist.pop_front(); @@ -455,8 +455,8 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum redoHist.pop_back(); } - DivInstrumentUndoStep* stepPtr = new DivInstrumentUndoStep; - *stepPtr = step; + DivInstrumentUndoStep* stepPtr=new DivInstrumentUndoStep; + *stepPtr=step; step.clear(); // don't let it delete the data ptr that's been copied! undoHist.push_back(stepPtr); @@ -465,16 +465,16 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum } int DivInstrument::undo() { - if (undoHist.empty()) { return 0; } + if (undoHist.empty()) return 0; - DivInstrumentUndoStep* step = undoHist.back(); + DivInstrumentUndoStep* step=undoHist.back(); undoHist.pop_back(); logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room - if (redoHist.size() >= redoHist.capacity()) { - DivInstrumentUndoStep* step = redoHist.front(); + if (redoHist.size()>=redoHist.capacity()) { + DivInstrumentUndoStep* step=redoHist.front(); delete step; redoHist.pop_front(); } @@ -484,7 +484,7 @@ int DivInstrument::undo() { } int DivInstrument::redo() { - if (redoHist.empty()) { return 0; } + if (redoHist.empty()) return 0; DivInstrumentUndoStep* step = redoHist.back(); redoHist.pop_back(); @@ -492,8 +492,8 @@ int DivInstrument::redo() { step->applyAndReverse(this); // make room - if (undoHist.size() >= undoHist.capacity()) { - DivInstrumentUndoStep* step = undoHist.front(); + if (undoHist.size()>=undoHist.capacity()) { + DivInstrumentUndoStep* step=undoHist.front(); delete step; undoHist.pop_front(); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c4fd743cd..473cf777e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -888,7 +888,7 @@ struct DivInstrumentPOD { struct MemPatch { MemPatch() : - data(nullptr) + data(NULL) , offset(0) , size(0) { } @@ -902,9 +902,9 @@ struct MemPatch { void clear(); bool calcDiff(const void* pre, const void* post, size_t size); void applyAndReverse(void* target, size_t inputSize); - bool isValid() const { return size > 0; } + bool isValid() const { return size>0; } - uint8_t* data; + unsigned char* data; size_t offset; size_t size; }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8fb588a98..9a0c920b1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5250,7 +5250,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) { - DivInstrument* ins=nullptr; + DivInstrument* ins=NULL; if (curIns==-2) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("waiting...")); @@ -7742,8 +7742,8 @@ void FurnaceGUI::drawInsEdit() { } if (ins) { - bool insChanged = ins != cachedCurInsPtr; - bool delayDiff = ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; + bool insChanged=ins!=cachedCurInsPtr; + bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; // check against the last cached to see if diff -- note that modifications to instruments happen outside // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) @@ -7752,12 +7752,12 @@ void FurnaceGUI::drawInsEdit() { } if (insChanged || !delayDiff) { - cachedCurIns = *ins; + cachedCurIns=*ins; } - cachedCurInsPtr = ins; + cachedCurInsPtr=ins; } else { - cachedCurInsPtr = nullptr; + cachedCurInsPtr=NULL; } } From 55af1648e7b2772995e97ccd64695d907cec88ca Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 4 Aug 2024 22:18:00 -0700 Subject: [PATCH 07/23] accidentally left some logs in --- src/engine/instrument.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index bccd14acb..d6351d8a3 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -460,7 +460,7 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum step.clear(); // don't let it delete the data ptr that's been copied! undoHist.push_back(stepPtr); - logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); + // logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); } } @@ -469,7 +469,7 @@ int DivInstrument::undo() { DivInstrumentUndoStep* step=undoHist.back(); undoHist.pop_back(); - logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + // logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room @@ -488,7 +488,7 @@ int DivInstrument::redo() { DivInstrumentUndoStep* step = redoHist.back(); redoHist.pop_back(); - logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + // logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room From 91d36d0a624c603227b83dd066c0bb38f380a72e Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 4 Aug 2024 22:23:21 -0700 Subject: [PATCH 08/23] typo in style fix --- src/engine/instrument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index d6351d8a3..924169e16 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -428,7 +428,7 @@ bool DivInstrumentUndoStep::makeUndoPatch(size_t processTime_, const DivInstrume // create the patch that will make post into pre podPatch.calcDiff((const DivInstrumentPOD*)post, (const DivInstrumentPOD*)pre, sizeof(DivInstrumentPOD)); - if (pre->name!=post->name != 0) { + if (pre->name!=post->name) { nameValid=true; name=pre->name; } From 94ef697ea615498e6cef13ed9a8987202d3b2742 Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 18 Aug 2024 05:16:38 -0700 Subject: [PATCH 09/23] cheat to avoid warning -Werror=class-memaccess on linux --- src/engine/instrument.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 473cf777e..bf04dac2e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -1025,7 +1025,7 @@ struct DivInstrument : DivInstrumentPOD { DivInstrument() : name("") { // clear and construct DivInstrumentPOD so it doesn't have any garbage in the padding - memset((DivInstrumentPOD*)this, 0, sizeof(DivInstrumentPOD)); + memset((unsigned char*)this, 0, sizeof(DivInstrumentPOD)); new ((DivInstrumentPOD*)this) DivInstrumentPOD; } }; From ea02a913b2e15b46ece292f29138cd3ee4cf2eb7 Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Sun, 18 Aug 2024 20:00:11 -0700 Subject: [PATCH 10/23] warn instead of assert on case where MemPatch application would exceed size of target buffer (which should never happen, if you're applying the patch to the same type it was generated from) --- src/engine/instrument.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 924169e16..7c3619a3a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include "dataErrors.h" #include "engine.h" #include "instrument.h" @@ -400,7 +399,11 @@ bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { void MemPatch::applyAndReverse(void* target, size_t targetSize) { if (size==0) return; - assert(offset+size<=targetSize); + if (offset+size>targetSize) { + logW("MemPatch (offset %d, size %d) exceeds target size (%d), can't apply!",offset,size,targetSize); + return; + } + unsigned char* targetBytes=(unsigned char*)target; // swap this->data and its segment on target From ad53b33d7cba5a22c9deee427d420d467e599d41 Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Mon, 19 Aug 2024 00:02:42 -0700 Subject: [PATCH 11/23] instrument editor undo: don't check delta if no user input has come in that could potentially have dirtied the editor --- src/engine/instrument.cpp | 7 +++++- src/engine/instrument.h | 2 +- src/gui/gui.cpp | 12 +++++++++ src/gui/gui.h | 2 ++ src/gui/insEdit.cpp | 53 ++++++++++++++++++++++++--------------- 5 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 7c3619a3a..2083f08be 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -376,6 +376,8 @@ bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { const unsigned char* preBytes=(const unsigned char*)pre; const unsigned char* postBytes=(const unsigned char*)post; + // @NOTE: consider/profile using a memcmp==0 check to early-out, if it's potentially faster + // for the common case, which is no change for (size_t ii=0; iipodPatch.offset, stepPtr->podPatch.size); + return true; } + + return false; } int DivInstrument::undo() { diff --git a/src/engine/instrument.h b/src/engine/instrument.h index bf04dac2e..8421a0658 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -934,7 +934,7 @@ struct DivInstrument : DivInstrumentPOD { */ FixedQueue undoHist; FixedQueue redoHist; - void recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); + bool recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); int undo(); int redo(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c8afaaa8b..714e4b291 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3704,6 +3704,7 @@ bool FurnaceGUI::loop() { ImGui::GetIO().AddKeyEvent(ImGuiKey_Backspace,false); injectBackUp=false; } + while (SDL_PollEvent(&ev)) { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); @@ -3720,13 +3721,16 @@ bool FurnaceGUI::loop() { } case SDL_MOUSEBUTTONUP: pointUp(ev.button.x,ev.button.y,ev.button.button); + insEditMayBeDirty=true; break; case SDL_MOUSEBUTTONDOWN: pointDown(ev.button.x,ev.button.y,ev.button.button); + insEditMayBeDirty=true; break; case SDL_MOUSEWHEEL: wheelX+=ev.wheel.x; wheelY+=ev.wheel.y; + insEditMayBeDirty=true; break; case SDL_WINDOWEVENT: switch (ev.window.event) { @@ -3803,12 +3807,14 @@ bool FurnaceGUI::loop() { if (!ImGui::GetIO().WantCaptureKeyboard) { keyDown(ev); } + insEditMayBeDirty=true; #ifdef IS_MOBILE injectBackUp=true; #endif break; case SDL_KEYUP: // for now + insEditMayBeDirty=true; break; case SDL_DROPFILE: if (ev.drop.file!=NULL) { @@ -7145,6 +7151,11 @@ bool FurnaceGUI::loop() { willCommit=false; } + // To check for instrument editor modification, we need an up-to-date `insEditMayBeDirty` + // (based on incoming user input events), and we want any possible instrument modifications + // to already have been made. + checkRecordInstrumentUndoStep(); + if (shallDetectScale) { if (--shallDetectScale<1) { if (settings.dpiScale<0.5f) { @@ -8311,6 +8322,7 @@ FurnaceGUI::FurnaceGUI(): localeRequiresKorean(false), prevInsData(NULL), cachedCurInsPtr(NULL), + insEditMayBeDirty(false), pendingLayoutImport(NULL), pendingLayoutImportLen(0), pendingLayoutImportStep(0), diff --git a/src/gui/gui.h b/src/gui/gui.h index b169963c8..1d5f0d17b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2258,6 +2258,7 @@ class FurnaceGUI { DivInstrument* prevInsData; DivInstrument cachedCurIns; DivInstrument* cachedCurInsPtr; + bool insEditMayBeDirty; unsigned char* pendingLayoutImport; size_t pendingLayoutImportLen; @@ -2924,6 +2925,7 @@ class FurnaceGUI { void doUndoSample(); void doRedoSample(); + void checkRecordInstrumentUndoStep(); void doUndoInstrument(); void doRedoInstrument(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9a0c920b1..1bc77bbf9 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7740,31 +7740,44 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndPopup(); } - - if (ins) { - bool insChanged=ins!=cachedCurInsPtr; - bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; - - // check against the last cached to see if diff -- note that modifications to instruments happen outside - // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) - if (!insChanged && !delayDiff) { - ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); - } - - if (insChanged || !delayDiff) { - cachedCurIns=*ins; - } - - cachedCurInsPtr=ins; - } else { - cachedCurInsPtr=NULL; - } } - + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; ImGui::End(); } +void FurnaceGUI::checkRecordInstrumentUndoStep() { + if (curIns>=0 && curIns<(int)e->song.ins.size()) { + DivInstrument* ins=e->song.ins[curIns]; + + // invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different + // instrument altgoether + bool insChanged=ins!=cachedCurInsPtr; + if (insChanged) { + insEditMayBeDirty=false; + cachedCurInsPtr=ins; + cachedCurIns=*ins; + } + + cachedCurInsPtr=ins; + + // check against the last cached to see if diff -- note that modifications to instruments + // happen outside drawInsEdit (e.g. cursor inputs are processed and can directly modify + // macro data). but don't check until we think the user input is complete. + bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; + if (!delayDiff && insEditMayBeDirty) { + bool hasChange=ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); + if (hasChange) { + cachedCurIns=*ins; + } + insEditMayBeDirty=false; + } + } else { + cachedCurInsPtr=NULL; + insEditMayBeDirty=false; + } +} + void FurnaceGUI::doUndoInstrument() { if (!insEditOpen) return; if (curIns<0 || curIns>=(int)e->song.ins.size()) return; From 2ab5ac4e075efe7dedc99c6ff7ea4d3d1de2542d Mon Sep 17 00:00:00 2001 From: Adam Lederer Date: Mon, 19 Aug 2024 00:32:14 -0700 Subject: [PATCH 12/23] don't run a delta against cached instrument if not insEditOpen --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1bc77bbf9..581251dc7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7747,7 +7747,7 @@ void FurnaceGUI::drawInsEdit() { } void FurnaceGUI::checkRecordInstrumentUndoStep() { - if (curIns>=0 && curIns<(int)e->song.ins.size()) { + if (insEditOpen && curIns>=0 && curIns<(int)e->song.ins.size()) { DivInstrument* ins=e->song.ins[curIns]; // invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different From 4f3d61c0f1b3d464c458fdf24130307a65a8bcd6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 13/23] Revert "don't run a delta against cached instrument if not insEditOpen" This reverts commit 2ab5ac4e075efe7dedc99c6ff7ea4d3d1de2542d. --- src/gui/insEdit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 581251dc7..1bc77bbf9 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7747,7 +7747,7 @@ void FurnaceGUI::drawInsEdit() { } void FurnaceGUI::checkRecordInstrumentUndoStep() { - if (insEditOpen && curIns>=0 && curIns<(int)e->song.ins.size()) { + if (curIns>=0 && curIns<(int)e->song.ins.size()) { DivInstrument* ins=e->song.ins[curIns]; // invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different From 251be67b695f43a8edee4423623de2079efeff1a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 14/23] Revert "instrument editor undo: don't check delta if no user input has come in that could potentially have dirtied the editor" This reverts commit ad53b33d7cba5a22c9deee427d420d467e599d41. --- src/engine/instrument.cpp | 7 +----- src/engine/instrument.h | 2 +- src/gui/gui.cpp | 12 ---------- src/gui/gui.h | 2 -- src/gui/insEdit.cpp | 47 ++++++++++++++------------------------- 5 files changed, 19 insertions(+), 51 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 2083f08be..7c3619a3a 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -376,8 +376,6 @@ bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { const unsigned char* preBytes=(const unsigned char*)pre; const unsigned char* postBytes=(const unsigned char*)post; - // @NOTE: consider/profile using a memcmp==0 check to early-out, if it's potentially faster - // for the common case, which is no change for (size_t ii=0; iipodPatch.offset, stepPtr->podPatch.size); - return true; } - - return false; } int DivInstrument::undo() { diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 8421a0658..bf04dac2e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -934,7 +934,7 @@ struct DivInstrument : DivInstrumentPOD { */ FixedQueue undoHist; FixedQueue redoHist; - bool recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); + void recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); int undo(); int redo(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 714e4b291..c8afaaa8b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3704,7 +3704,6 @@ bool FurnaceGUI::loop() { ImGui::GetIO().AddKeyEvent(ImGuiKey_Backspace,false); injectBackUp=false; } - while (SDL_PollEvent(&ev)) { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); @@ -3721,16 +3720,13 @@ bool FurnaceGUI::loop() { } case SDL_MOUSEBUTTONUP: pointUp(ev.button.x,ev.button.y,ev.button.button); - insEditMayBeDirty=true; break; case SDL_MOUSEBUTTONDOWN: pointDown(ev.button.x,ev.button.y,ev.button.button); - insEditMayBeDirty=true; break; case SDL_MOUSEWHEEL: wheelX+=ev.wheel.x; wheelY+=ev.wheel.y; - insEditMayBeDirty=true; break; case SDL_WINDOWEVENT: switch (ev.window.event) { @@ -3807,14 +3803,12 @@ bool FurnaceGUI::loop() { if (!ImGui::GetIO().WantCaptureKeyboard) { keyDown(ev); } - insEditMayBeDirty=true; #ifdef IS_MOBILE injectBackUp=true; #endif break; case SDL_KEYUP: // for now - insEditMayBeDirty=true; break; case SDL_DROPFILE: if (ev.drop.file!=NULL) { @@ -7151,11 +7145,6 @@ bool FurnaceGUI::loop() { willCommit=false; } - // To check for instrument editor modification, we need an up-to-date `insEditMayBeDirty` - // (based on incoming user input events), and we want any possible instrument modifications - // to already have been made. - checkRecordInstrumentUndoStep(); - if (shallDetectScale) { if (--shallDetectScale<1) { if (settings.dpiScale<0.5f) { @@ -8322,7 +8311,6 @@ FurnaceGUI::FurnaceGUI(): localeRequiresKorean(false), prevInsData(NULL), cachedCurInsPtr(NULL), - insEditMayBeDirty(false), pendingLayoutImport(NULL), pendingLayoutImportLen(0), pendingLayoutImportStep(0), diff --git a/src/gui/gui.h b/src/gui/gui.h index 1d5f0d17b..b169963c8 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -2258,7 +2258,6 @@ class FurnaceGUI { DivInstrument* prevInsData; DivInstrument cachedCurIns; DivInstrument* cachedCurInsPtr; - bool insEditMayBeDirty; unsigned char* pendingLayoutImport; size_t pendingLayoutImportLen; @@ -2925,7 +2924,6 @@ class FurnaceGUI { void doUndoSample(); void doRedoSample(); - void checkRecordInstrumentUndoStep(); void doUndoInstrument(); void doRedoInstrument(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 1bc77bbf9..9a0c920b1 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -7740,42 +7740,29 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndPopup(); } - } + + if (ins) { + bool insChanged=ins!=cachedCurInsPtr; + bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; - ImGui::End(); -} + // check against the last cached to see if diff -- note that modifications to instruments happen outside + // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) + if (!insChanged && !delayDiff) { + ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); + } -void FurnaceGUI::checkRecordInstrumentUndoStep() { - if (curIns>=0 && curIns<(int)e->song.ins.size()) { - DivInstrument* ins=e->song.ins[curIns]; - - // invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different - // instrument altgoether - bool insChanged=ins!=cachedCurInsPtr; - if (insChanged) { - insEditMayBeDirty=false; - cachedCurInsPtr=ins; - cachedCurIns=*ins; - } - - cachedCurInsPtr=ins; - - // check against the last cached to see if diff -- note that modifications to instruments - // happen outside drawInsEdit (e.g. cursor inputs are processed and can directly modify - // macro data). but don't check until we think the user input is complete. - bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; - if (!delayDiff && insEditMayBeDirty) { - bool hasChange=ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); - if (hasChange) { + if (insChanged || !delayDiff) { cachedCurIns=*ins; } - insEditMayBeDirty=false; + + cachedCurInsPtr=ins; + } else { + cachedCurInsPtr=NULL; } - } else { - cachedCurInsPtr=NULL; - insEditMayBeDirty=false; } + + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; + ImGui::End(); } void FurnaceGUI::doUndoInstrument() { From 257abca831aa58e830e52d93aeb8d989cd9cab57 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 15/23] Revert "warn instead of assert on case where MemPatch application would exceed size of target buffer (which should never happen, if you're applying the patch to the same type it was generated from)" This reverts commit ea02a913b2e15b46ece292f29138cd3ee4cf2eb7. --- src/engine/instrument.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 7c3619a3a..924169e16 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include "dataErrors.h" #include "engine.h" #include "instrument.h" @@ -399,11 +400,7 @@ bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { void MemPatch::applyAndReverse(void* target, size_t targetSize) { if (size==0) return; - if (offset+size>targetSize) { - logW("MemPatch (offset %d, size %d) exceeds target size (%d), can't apply!",offset,size,targetSize); - return; - } - + assert(offset+size<=targetSize); unsigned char* targetBytes=(unsigned char*)target; // swap this->data and its segment on target From 78d7fb4da04d08b8101f8365ad353af94eb2b736 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 16/23] Revert "cheat to avoid warning -Werror=class-memaccess on linux" This reverts commit 94ef697ea615498e6cef13ed9a8987202d3b2742. --- src/engine/instrument.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/instrument.h b/src/engine/instrument.h index bf04dac2e..473cf777e 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -1025,7 +1025,7 @@ struct DivInstrument : DivInstrumentPOD { DivInstrument() : name("") { // clear and construct DivInstrumentPOD so it doesn't have any garbage in the padding - memset((unsigned char*)this, 0, sizeof(DivInstrumentPOD)); + memset((DivInstrumentPOD*)this, 0, sizeof(DivInstrumentPOD)); new ((DivInstrumentPOD*)this) DivInstrumentPOD; } }; From c00947071aea854aebb34d33a88edfb72d1d6481 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 17/23] Revert "typo in style fix" This reverts commit 91d36d0a624c603227b83dd066c0bb38f380a72e. --- src/engine/instrument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 924169e16..d6351d8a3 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -428,7 +428,7 @@ bool DivInstrumentUndoStep::makeUndoPatch(size_t processTime_, const DivInstrume // create the patch that will make post into pre podPatch.calcDiff((const DivInstrumentPOD*)post, (const DivInstrumentPOD*)pre, sizeof(DivInstrumentPOD)); - if (pre->name!=post->name) { + if (pre->name!=post->name != 0) { nameValid=true; name=pre->name; } From 73c61d9ac7ebe87e1d11150d3c223a2bc0463849 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 18/23] Revert "accidentally left some logs in" This reverts commit 55af1648e7b2772995e97ccd64695d907cec88ca. --- src/engine/instrument.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index d6351d8a3..bccd14acb 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -460,7 +460,7 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum step.clear(); // don't let it delete the data ptr that's been copied! undoHist.push_back(stepPtr); - // logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); + logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); } } @@ -469,7 +469,7 @@ int DivInstrument::undo() { DivInstrumentUndoStep* step=undoHist.back(); undoHist.pop_back(); - // logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room @@ -488,7 +488,7 @@ int DivInstrument::redo() { DivInstrumentUndoStep* step = redoHist.back(); redoHist.pop_back(); - // logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); + logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room From f1de0bf2b7a1317650ec6b0978353f25c3afe84c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 19/23] Revert "style fixes" This reverts commit 15d47d0aae9c78f3c77979c39b7cd7e90d807751. --- src/engine/instrument.cpp | 66 +++++++++++++++++++-------------------- src/engine/instrument.h | 6 ++-- src/gui/insEdit.cpp | 12 +++---- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index bccd14acb..2f80aaca1 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -365,19 +365,19 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) { } void MemPatch::clear() { - data = NULL; - offset=0; - size=0; + data = nullptr; + offset = 0; + size = 0; } bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { - bool diffValid=false; - size_t firstDiff=0; - size_t lastDiff=0; - const unsigned char* preBytes=(const unsigned char*)pre; - const unsigned char* postBytes=(const unsigned char*)post; + bool diffValid = false; + size_t firstDiff = 0; + size_t lastDiff = 0; + const uint8_t* preBytes = (const uint8_t*)pre; + const uint8_t* postBytes = (const uint8_t*)post; - for (size_t ii=0; iidata and its segment on target - for (size_t ii=0; iiname!=post->name != 0) { - nameValid=true; - name=pre->name; + if (pre->name.compare(post->name) != 0) { + nameValid = true; + name = pre->name; } return nameValid || podPatch.isValid(); @@ -443,7 +443,7 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum if (step.makeUndoPatch(processTime, old, this)) { // make room - if (undoHist.size()>=undoHist.capacity()) { + if (undoHist.size() >= undoHist.capacity()) { DivInstrumentUndoStep* step = undoHist.front(); delete step; undoHist.pop_front(); @@ -455,8 +455,8 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum redoHist.pop_back(); } - DivInstrumentUndoStep* stepPtr=new DivInstrumentUndoStep; - *stepPtr=step; + DivInstrumentUndoStep* stepPtr = new DivInstrumentUndoStep; + *stepPtr = step; step.clear(); // don't let it delete the data ptr that's been copied! undoHist.push_back(stepPtr); @@ -465,16 +465,16 @@ void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrum } int DivInstrument::undo() { - if (undoHist.empty()) return 0; + if (undoHist.empty()) { return 0; } - DivInstrumentUndoStep* step=undoHist.back(); + DivInstrumentUndoStep* step = undoHist.back(); undoHist.pop_back(); logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); step->applyAndReverse(this); // make room - if (redoHist.size()>=redoHist.capacity()) { - DivInstrumentUndoStep* step=redoHist.front(); + if (redoHist.size() >= redoHist.capacity()) { + DivInstrumentUndoStep* step = redoHist.front(); delete step; redoHist.pop_front(); } @@ -484,7 +484,7 @@ int DivInstrument::undo() { } int DivInstrument::redo() { - if (redoHist.empty()) return 0; + if (redoHist.empty()) { return 0; } DivInstrumentUndoStep* step = redoHist.back(); redoHist.pop_back(); @@ -492,8 +492,8 @@ int DivInstrument::redo() { step->applyAndReverse(this); // make room - if (undoHist.size()>=undoHist.capacity()) { - DivInstrumentUndoStep* step=undoHist.front(); + if (undoHist.size() >= undoHist.capacity()) { + DivInstrumentUndoStep* step = undoHist.front(); delete step; undoHist.pop_front(); } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index 473cf777e..c4fd743cd 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -888,7 +888,7 @@ struct DivInstrumentPOD { struct MemPatch { MemPatch() : - data(NULL) + data(nullptr) , offset(0) , size(0) { } @@ -902,9 +902,9 @@ struct MemPatch { void clear(); bool calcDiff(const void* pre, const void* post, size_t size); void applyAndReverse(void* target, size_t inputSize); - bool isValid() const { return size>0; } + bool isValid() const { return size > 0; } - unsigned char* data; + uint8_t* data; size_t offset; size_t size; }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 9a0c920b1..8fb588a98 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5250,7 +5250,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) { - DivInstrument* ins=NULL; + DivInstrument* ins=nullptr; if (curIns==-2) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("waiting...")); @@ -7742,8 +7742,8 @@ void FurnaceGUI::drawInsEdit() { } if (ins) { - bool insChanged=ins!=cachedCurInsPtr; - bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; + bool insChanged = ins != cachedCurInsPtr; + bool delayDiff = ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; // check against the last cached to see if diff -- note that modifications to instruments happen outside // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) @@ -7752,12 +7752,12 @@ void FurnaceGUI::drawInsEdit() { } if (insChanged || !delayDiff) { - cachedCurIns=*ins; + cachedCurIns = *ins; } - cachedCurInsPtr=ins; + cachedCurInsPtr = ins; } else { - cachedCurInsPtr=NULL; + cachedCurInsPtr = nullptr; } } From d3af8104625ad767cd7d9918f73feb49b182fcc5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 02:49:14 -0500 Subject: [PATCH 20/23] Revert "add undo to instrument editor (check for diffs on the current DivInstrument in insEdit, record them in a stack)" This reverts commit 5c9fd69ac1c06e4001f43373b4f6cfbad8d08f46. --- src/engine/instrument.cpp | 139 -------------------------------------- src/engine/instrument.h | 70 ++----------------- src/fixedQueue.h | 93 +++++++++++++------------ src/gui/debugWindow.cpp | 2 +- src/gui/doAction.cpp | 4 -- src/gui/gui.cpp | 1 - src/gui/gui.h | 5 -- src/gui/insEdit.cpp | 48 +------------ 8 files changed, 55 insertions(+), 307 deletions(-) diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 2f80aaca1..ad5ebe8e1 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include "dataErrors.h" #include "engine.h" #include "instrument.h" @@ -364,144 +363,6 @@ void DivInstrument::writeFeatureFM(SafeWriter* w, bool fui) { FEATURE_END; } -void MemPatch::clear() { - data = nullptr; - offset = 0; - size = 0; -} - -bool MemPatch::calcDiff(const void* pre, const void* post, size_t inputSize) { - bool diffValid = false; - size_t firstDiff = 0; - size_t lastDiff = 0; - const uint8_t* preBytes = (const uint8_t*)pre; - const uint8_t* postBytes = (const uint8_t*)post; - - for (size_t ii = 0; ii < inputSize; ++ii) { - if (preBytes[ii] != postBytes[ii]) { - lastDiff=ii; - firstDiff=diffValid ? firstDiff : ii; - diffValid=true; - } - } - - if (diffValid) { - offset = firstDiff; - size = lastDiff - firstDiff + 1; - data = new uint8_t[size]; - - // the diff is to make pre into post (MemPatch is general, not specific to - // undo), so copy from postBytes - memcpy(data, postBytes + offset, size); - } - - return diffValid; -} - -void MemPatch::applyAndReverse(void* target, size_t targetSize) { - if (size == 0) { return; } - assert(offset + size <= targetSize); - uint8_t* targetBytes = (uint8_t*)target; - - // swap this->data and its segment on target - for (size_t ii = 0; ii < size; ++ii) { - uint8_t tmp = targetBytes[offset + ii]; - targetBytes[offset + ii] = data[ii]; - data[ii] = tmp; - } -} - -void DivInstrumentUndoStep::clear() { - podPatch.clear(); - name.clear(); -} - -void DivInstrumentUndoStep::applyAndReverse(DivInstrument* target) { - if (nameValid) { - name.swap(target->name); - } - podPatch.applyAndReverse((DivInstrumentPOD*)target, sizeof(DivInstrumentPOD)); -} - -bool DivInstrumentUndoStep::makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post) { - processTime = processTime_; - - // create the patch that will make post into pre - podPatch.calcDiff((const DivInstrumentPOD*)post, (const DivInstrumentPOD*)pre, sizeof(DivInstrumentPOD)); - if (pre->name.compare(post->name) != 0) { - nameValid = true; - name = pre->name; - } - - return nameValid || podPatch.isValid(); -} - -void DivInstrument::recordUndoStepIfChanged(size_t processTime, const DivInstrument* old) { - DivInstrumentUndoStep step; - - // generate a patch to go back to old - if (step.makeUndoPatch(processTime, old, this)) { - - // make room - if (undoHist.size() >= undoHist.capacity()) { - DivInstrumentUndoStep* step = undoHist.front(); - delete step; - undoHist.pop_front(); - } - - // clear redo - while (!redoHist.empty()) { - delete redoHist.back(); - redoHist.pop_back(); - } - - DivInstrumentUndoStep* stepPtr = new DivInstrumentUndoStep; - *stepPtr = step; - step.clear(); // don't let it delete the data ptr that's been copied! - undoHist.push_back(stepPtr); - - logI("DivInstrument::undoHist push (%u off, %u size)", stepPtr->podPatch.offset, stepPtr->podPatch.size); - } -} - -int DivInstrument::undo() { - if (undoHist.empty()) { return 0; } - - DivInstrumentUndoStep* step = undoHist.back(); - undoHist.pop_back(); - logI("DivInstrument::undo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); - step->applyAndReverse(this); - - // make room - if (redoHist.size() >= redoHist.capacity()) { - DivInstrumentUndoStep* step = redoHist.front(); - delete step; - redoHist.pop_front(); - } - redoHist.push_back(step); - - return 1; -} - -int DivInstrument::redo() { - if (redoHist.empty()) { return 0; } - - DivInstrumentUndoStep* step = redoHist.back(); - redoHist.pop_back(); - logI("DivInstrument::redo (%u off, %u size)", step->podPatch.offset, step->podPatch.size); - step->applyAndReverse(this); - - // make room - if (undoHist.size() >= undoHist.capacity()) { - DivInstrumentUndoStep* step = undoHist.front(); - delete step; - undoHist.pop_front(); - } - undoHist.push_back(step); - - return 1; -} - void DivInstrument::writeMacro(SafeWriter* w, const DivInstrumentMacro& m) { if (!m.len) return; diff --git a/src/engine/instrument.h b/src/engine/instrument.h index c4fd743cd..49b2991d4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -23,10 +23,8 @@ #include "dataErrors.h" #include "../ta-utils.h" #include "../pch.h" -#include "../fixedQueue.h" struct DivSong; -struct DivInstrument; // NOTICE! // before adding new instrument types to this struct, please ask me first. @@ -862,7 +860,8 @@ struct DivInstrumentSID2 { noiseMode(0) {} }; -struct DivInstrumentPOD { +struct DivInstrument { + String name; DivInstrumentType type; DivInstrumentFM fm; DivInstrumentSTD std; @@ -881,63 +880,6 @@ struct DivInstrumentPOD { DivInstrumentPowerNoise powernoise; DivInstrumentSID2 sid2; - DivInstrumentPOD() : - type(DIV_INS_FM) { - } -}; - -struct MemPatch { - MemPatch() : - data(nullptr) - , offset(0) - , size(0) { - } - - ~MemPatch() { - if (data) { - free(data); - } - } - - void clear(); - bool calcDiff(const void* pre, const void* post, size_t size); - void applyAndReverse(void* target, size_t inputSize); - bool isValid() const { return size > 0; } - - uint8_t* data; - size_t offset; - size_t size; -}; - -struct DivInstrumentUndoStep { - DivInstrumentUndoStep() : - name(""), - nameValid(false), - processTime(0) { - } - - MemPatch podPatch; - String name; - bool nameValid; - size_t processTime; - - void clear(); - void applyAndReverse(DivInstrument* target); - bool makeUndoPatch(size_t processTime_, const DivInstrument* pre, const DivInstrument* post); -}; - -struct DivInstrument : DivInstrumentPOD { - String name; - - /** - * undo stuff - */ - FixedQueue undoHist; - FixedQueue redoHist; - void recordUndoStepIfChanged(size_t processTime, const DivInstrument* old); - int undo(); - int redo(); - /** * these are internal functions. */ @@ -1022,11 +964,9 @@ struct DivInstrument : DivInstrumentPOD { * @return whether it was successful. */ bool saveDMP(const char* path); - DivInstrument() : - name("") { - // clear and construct DivInstrumentPOD so it doesn't have any garbage in the padding - memset((DivInstrumentPOD*)this, 0, sizeof(DivInstrumentPOD)); - new ((DivInstrumentPOD*)this) DivInstrumentPOD; + DivInstrument(): + name(""), + type(DIV_INS_FM) { } }; #endif diff --git a/src/fixedQueue.h b/src/fixedQueue.h index f781b3d33..68f883edc 100644 --- a/src/fixedQueue.h +++ b/src/fixedQueue.h @@ -24,7 +24,7 @@ #include "ta-log.h" template struct FixedQueue { - size_t readPos, curSize; + size_t readPos, writePos; T data[items]; T& operator[](size_t pos); @@ -41,21 +41,17 @@ template struct FixedQueue { bool push_back(const T& item); void clear(); bool empty(); - size_t writePos(); size_t size(); - size_t capacity(); FixedQueue(): readPos(0), - curSize(0) {} + writePos(0) {} }; template T& FixedQueue::operator[](size_t pos) { - if (pos>=curSize) { + if (pos>=size()) { logW("accessing invalid position. bug!"); } - size_t idx=readPos+pos; - if (idx>=items) idx-=items; - return data[idx]; + return data[(readPos+pos)%items]; } template T& FixedQueue::front() { @@ -63,13 +59,12 @@ template T& FixedQueue::front() { } template T& FixedQueue::back() { - if (curSize==0) return data[0]; - size_t idx=readPos+curSize-1; - if (idx>=items) idx-=items; - return data[idx]; + if (writePos==0) return data[items-1]; + return data[writePos-1]; } template bool FixedQueue::erase(size_t pos) { + size_t curSize=size(); if (pos>=curSize) { logW("accessing invalid position. bug!"); return false; @@ -89,56 +84,72 @@ template bool FixedQueue::erase(size_t pos) p1++; } - curSize--; + if (writePos>0) { + writePos--; + } else { + writePos=items-1; + } + return true; } template bool FixedQueue::pop() { - if (curSize==0) return false; - curSize--; + if (readPos==writePos) return false; + if (++readPos>=items) readPos=0; return true; } template bool FixedQueue::push(const T& item) { - if (curSize==items) { + if (writePos==(readPos-1)) { //logW("queue overflow!"); return false; } - size_t idx=readPos+curSize; - if (idx>=items) { idx-=items; } - data[idx]=item; - curSize++; + if (writePos==items-1 && readPos==0) { + //logW("queue overflow!"); + return false; + } + data[writePos]=item; + if (++writePos>=items) writePos=0; return true; } template bool FixedQueue::pop_front() { - if (curSize==0) return false; + if (readPos==writePos) return false; if (++readPos>=items) readPos=0; - curSize--; return true; } template bool FixedQueue::push_back(const T& item) { - if (curSize==items) { + if (writePos==(readPos-1)) { //logW("queue overflow!"); return false; } - size_t idx=readPos+curSize; - if (idx>=items) { idx-=items; } - data[idx]=item; - curSize++; + if (writePos==items-1 && readPos==0) { + //logW("queue overflow!"); + return false; + } + data[writePos]=item; + if (++writePos>=items) writePos=0; return true; } template bool FixedQueue::pop_back() { - if (curSize==0) return false; - curSize--; + if (readPos==writePos) return false; + if (writePos>0) { + writePos--; + } else { + writePos=items-1; + } return true; } template bool FixedQueue::push_front(const T& item) { - if (curSize==items) { - //logW("queue overflow!"); + if (readPos==(writePos+1)) { + //logW("stack overflow!"); + return false; + } + if (readPos==0 && writePos==items-1) { + //logW("stack overflow!"); return false; } if (readPos>0) { @@ -147,31 +158,23 @@ template bool FixedQueue::push_front(const T readPos=items-1; } data[readPos]=item; - curSize++; return true; } template void FixedQueue::clear() { readPos=0; - curSize=0; + writePos=0; } template bool FixedQueue::empty() { - return curSize==0; -} - -template size_t FixedQueue::writePos() { - size_t idx=readPos+curSize; - if (idx>=items) { idx-=items; } - return idx; + return (readPos==writePos); } template size_t FixedQueue::size() { - return curSize; -} - -template size_t FixedQueue::capacity() { - return items; + if (readPos>writePos) { + return items+writePos-readPos; + } + return writePos-readPos; } #endif diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 25969d2ec..b08c60532 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -605,7 +605,7 @@ void FurnaceGUI::drawDebug() { } if (ImGui::TreeNode("Recent Files")) { ImGui::Text("Items: %d - Max: %d",(int)recentFile.size(),settings.maxRecentFile); - ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos()); + ImGui::Text("readPos: %d - writePos: %d",(int)recentFile.readPos,(int)recentFile.writePos); ImGui::Indent(); for (size_t i=0; i localeExtraRanges; DivInstrument* prevInsData; - DivInstrument cachedCurIns; - DivInstrument* cachedCurInsPtr; unsigned char* pendingLayoutImport; size_t pendingLayoutImportLen; @@ -2924,9 +2922,6 @@ class FurnaceGUI { void doUndoSample(); void doRedoSample(); - void doUndoInstrument(); - void doRedoInstrument(); - void play(int row=0); void setOrder(unsigned char order, bool forced=false); void stop(); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 8fb588a98..99dbf26dc 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -5250,7 +5250,6 @@ void FurnaceGUI::drawInsEdit() { ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH)); } if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) { - DivInstrument* ins=nullptr; if (curIns==-2) { ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f); CENTER_TEXT(_("waiting...")); @@ -5278,7 +5277,6 @@ void FurnaceGUI::drawInsEdit() { curIns=i; wavePreviewInit=true; updateFMPreview=true; - ins = e->song.ins[curIns]; } } ImGui::EndCombo(); @@ -5301,7 +5299,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndTable(); } } else { - ins=e->song.ins[curIns]; + DivInstrument* ins=e->song.ins[curIns]; if (updateFMPreview) { renderFMPreview(ins); updateFMPreview=false; @@ -7740,51 +7738,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndPopup(); } - - if (ins) { - bool insChanged = ins != cachedCurInsPtr; - bool delayDiff = ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard; - - // check against the last cached to see if diff -- note that modifications to instruments happen outside - // drawInsEdit (e.g. cursor inputs are processed and can directly modify macro data) - if (!insChanged && !delayDiff) { - ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns); - } - - if (insChanged || !delayDiff) { - cachedCurIns = *ins; - } - - cachedCurInsPtr = ins; - } else { - cachedCurInsPtr = nullptr; - } } - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT; ImGui::End(); } - -void FurnaceGUI::doUndoInstrument() { - if (!insEditOpen) return; - if (curIns<0 || curIns>=(int)e->song.ins.size()) return; - DivInstrument* ins=e->song.ins[curIns]; - // is locking the engine necessary? copied from doUndoSample - e->lockEngine([this,ins]() { - ins->undo(); - cachedCurInsPtr=ins; - cachedCurIns=*ins; - }); -} - -void FurnaceGUI::doRedoInstrument() { - if (!insEditOpen) return; - if (curIns<0 || curIns>=(int)e->song.ins.size()) return; - DivInstrument* ins=e->song.ins[curIns]; - // is locking the engine necessary? copied from doRedoSample - e->lockEngine([this,ins]() { - ins->redo(); - cachedCurInsPtr=ins; - cachedCurIns=*ins; - }); -} From ecbfacef1f1b80464a8d2923b40e46ae7a422ae2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 12:40:51 -0500 Subject: [PATCH 21/23] add SFWrapper error logging --- src/engine/sfWrapper.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/engine/sfWrapper.cpp b/src/engine/sfWrapper.cpp index 814f9c00f..d1b8d0fa5 100644 --- a/src/engine/sfWrapper.cpp +++ b/src/engine/sfWrapper.cpp @@ -91,10 +91,12 @@ SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) { f=ps_fopen(path,modeC); if (f==NULL) { + logE("SFWrapper: failed to open (%s)",strerror(errno)); return NULL; } if (fseek(f,0,SEEK_END)==-1) { + logE("SFWrapper: failed to seek to end (%s)",strerror(errno)); fclose(f); f=NULL; return NULL; @@ -102,6 +104,7 @@ SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) { len=ftell(f); if (len==(SIZE_MAX>>1)) { + logE("SFWrapper: failed to tell (%s)",strerror(errno)); len=0; fclose(f); f=NULL; @@ -109,6 +112,7 @@ SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) { } if (fseek(f,0,SEEK_SET)==-1) { + logE("SFWrapper: failed to seek to beginning (%s)",strerror(errno)); len=0; fclose(f); f=NULL; @@ -117,5 +121,8 @@ SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) { sf=sf_open_virtual(&vio,mode,sfinfo,this); if (sf!=NULL) fileMode=mode; + if (sf==NULL) { + logE("SFWrapper: WHY IS IT NULL?!"); + } return sf; -} \ No newline at end of file +} From a410b9045218f812bd68687e5a0ab9cd35f52629 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 19 Aug 2024 12:54:09 -0500 Subject: [PATCH 22/23] CRAP --- src/engine/sfWrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/sfWrapper.cpp b/src/engine/sfWrapper.cpp index d1b8d0fa5..18a1c0c34 100644 --- a/src/engine/sfWrapper.cpp +++ b/src/engine/sfWrapper.cpp @@ -19,6 +19,7 @@ #include "sfWrapper.h" #include "../fileutils.h" +#include "../ta-log.h" #include "sndfile.h" sf_count_t _vioGetSize(void* user) { @@ -80,6 +81,7 @@ SNDFILE* SFWrapper::doOpen(const char* path, int mode, SF_INFO* sfinfo) { vio.seek=_vioSeek; vio.tell=_vioTell; vio.write=_vioWrite; + logV("SFWrapper: opening %s",path); const char* modeC="rb"; if (mode==SFM_WRITE) { From 28dc0b12a14c8abae69463165fc00cb1f910ab06 Mon Sep 17 00:00:00 2001 From: alederer Date: Mon, 19 Aug 2024 11:19:50 -0700 Subject: [PATCH 23/23] "Adopt instrument" action also adopts octave (#2095) * push test * remove test file * add GUI_ACTION_PAT_ABSORB_INSTRUMENT action (set current instrument to channel's current instrument column) * rename 'absorb instrument' to 'adopt instrument' (clearer), adopt octave as well, replace editor octave min/max numbers in the code with defines * CRAP * rename 'adopt instrument' back to 'absorb instrument' --------- Co-authored-by: Adam Lederer Co-authored-by: tildearrow --- src/gui/doAction.cpp | 30 +++++++++++++++++++++++------- src/gui/editControls.cpp | 16 ++++++++-------- src/gui/gui.h | 3 +++ src/gui/guiConst.cpp | 2 +- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index bf5b89519..00bfe95ea 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -123,16 +123,16 @@ void FurnaceGUI::doAction(int what) { pendingStepUpdate=1; break; case GUI_ACTION_OCTAVE_UP: - if (++curOctave>7) { - curOctave=7; + if (++curOctave>GUI_EDIT_OCTAVE_MAX) { + curOctave=GUI_EDIT_OCTAVE_MAX; } else { e->autoNoteOffAll(); failedNoteOn=false; } break; case GUI_ACTION_OCTAVE_DOWN: - if (--curOctave<-5) { - curOctave=-5; + if (--curOctaveautoNoteOffAll(); failedNoteOn=false; @@ -679,10 +679,26 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_PAT_ABSORB_INSTRUMENT: { DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false); if (!pat) break; - for (int i=cursor.y; i>=0; i--) { - if (pat->data[i][2] >= 0) { + bool foundIns=false; + bool foundOctave=false; + for (int i=cursor.y; i>=0 && !(foundIns && foundOctave); i--) { + // absorb most recent instrument + if (!foundIns && pat->data[i][2] >= 0) { curIns=pat->data[i][2]; - break; + foundIns=true; + } + // absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of notes + // will result in an octave number equal to the previous note). + if (!foundOctave && pat->data[i][0] != 0) { + // decode octave data (was signed cast to unsigned char) + int octave=pat->data[i][1]; + if (octave>128) octave-=256; + // @NOTE the special handling when note==12, which is really an octave above what's + // stored in the octave data. without this handling, if you press Q, then + // "ABSORB_INSTRUMENT", then Q again, you'd get a different octave! + if (pat->data[i][0]==12) octave++; + curOctave=CLAMP(octave-1, GUI_EDIT_OCTAVE_MIN, GUI_EDIT_OCTAVE_MAX); + foundOctave=true; } } break; diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index c492a8e17..34beff48b 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -647,8 +647,8 @@ void FurnaceGUI::drawEditControls() { ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::InputInt("##Octave",&curOctave,1,1)) { - if (curOctave>7) curOctave=7; - if (curOctave<-5) curOctave=-5; + if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX; + if (curOctaveautoNoteOffAll(); failedNoteOn=false; @@ -808,8 +808,8 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); ImGui::SetNextItemWidth(96.0f*dpiScale); if (ImGui::InputInt("##Octave",&curOctave,1,1)) { - if (curOctave>7) curOctave=7; - if (curOctave<-5) curOctave=-5; + if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX; + if (curOctaveautoNoteOffAll(); failedNoteOn=false; @@ -926,8 +926,8 @@ void FurnaceGUI::drawEditControls() { float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); if (ImGui::InputInt("##Octave",&curOctave,0,0)) { - if (curOctave>7) curOctave=7; - if (curOctave<-5) curOctave=-5; + if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX; + if (curOctaveautoNoteOffAll(); failedNoteOn=false; @@ -1093,8 +1093,8 @@ void FurnaceGUI::drawEditControls() { float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); if (ImGui::InputInt("##Octave",&curOctave,1,1)) { - if (curOctave>7) curOctave=7; - if (curOctave<-5) curOctave=-5; + if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX; + if (curOctaveautoNoteOffAll(); failedNoteOn=false; diff --git a/src/gui/gui.h b/src/gui/gui.h index adc066229..9ff06e013 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -137,6 +137,9 @@ enum FurnaceGUIRenderBackend { #define ngettext momo_ngettext #endif +#define GUI_EDIT_OCTAVE_MIN -5 +#define GUI_EDIT_OCTAVE_MAX 7 + // TODO: // - add colors for FM envelope and waveform // - maybe add "alternate" color for FM modulators/carriers (a bit difficult) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 13e8a9478..8fd662824 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -687,7 +687,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("PAT_LATCH", _N("Set note input latch"), 0), D("PAT_SCROLL_MODE", _N("Change mobile scroll mode"), 0), D("PAT_CLEAR_LATCH", _N("Clear note input latch"), 0), - D("PAT_ABSORB_INSTRUMENT", _N("Set current instrument to channel's current instrument column"), 0), + D("PAT_ABSORB_INSTRUMENT", _N("Absorb instrument/octave from status at cursor"), 0), D("PAT_MAX", "", NOT_AN_ACTION), D("INS_LIST_MIN", _N("---Instrument list"), NOT_AN_ACTION),