From a1d74e7dc16c7a2e44bc3cee423050a00df79ebc Mon Sep 17 00:00:00 2001 From: MooingLemur Date: Fri, 11 Aug 2023 13:03:37 -0700 Subject: [PATCH] ZSM: add optimize for size toggle --- src/engine/engine.h | 2 +- src/engine/zsm.cpp | 14 +++++++++++--- src/engine/zsm.h | 2 ++ src/engine/zsmOps.cpp | 5 ++++- src/gui/gui.cpp | 5 ++++- src/gui/gui.h | 2 +- 6 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 0f13659b8..effa0273f 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -605,7 +605,7 @@ class DivEngine { // - -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); + SafeWriter* saveZSM(unsigned int zsmrate=60, bool loop=true, bool optimize=true); // dump command stream. SafeWriter* saveCommand(bool binary=false); // export to an audio file diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index 96d39a4a0..14e823040 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -66,6 +66,8 @@ void DivZSM::init(unsigned int rate) { // Channel masks ymMask=0; psgMask=0; + // Optimize writes + optimize=false; } int DivZSM::getoffset() { @@ -121,9 +123,6 @@ void DivZSM::writeSync(unsigned char a, unsigned char v) { } void DivZSM::writePSG(unsigned char a, unsigned char v) { - // TODO: suppress writes to PSG voice that is not audible (volume=0) - // ^ Let's leave these alone, ZSMKit has a feature that can benefit - // from silent channels. if (a>=69) { logD("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v); return; @@ -213,6 +212,10 @@ void DivZSM::setLoopPoint() { } } +void DivZSM::setOptimize(bool o) { + optimize = o; +} + SafeWriter* DivZSM::finish() { tick(0); // flush any pending writes / ticks flushTicks(); // flush ticks in case there were no writes pending @@ -278,6 +281,11 @@ void DivZSM::flushWrites() { flushTicks(); // only flush ticks if there are writes pending. for (unsigned char i=0; i<64; i++) { if (psgState[psg_NEW][i]==psgState[psg_PREV][i]) continue; + // if optimize=true, suppress writes to PSG voices that are not audible (volume=0 or R+L=0) + // ZSMKit has a feature that can benefit from having silent channels + // updated, so this is something that can be toggled off or on for export + if (optimize && i%4!=2 && (psgState[psg_NEW][(i&0x3c)+2]&0x3f)==0) continue; // vol + if (optimize && i%4!=2 && (psgState[psg_NEW][(i&0x3c)+2]&0xc0)==0) continue; // R+L psgState[psg_PREV][i]=psgState[psg_NEW][i]; w->writeC(i); w->writeC(psgState[psg_NEW][i]); diff --git a/src/engine/zsm.h b/src/engine/zsm.h index d9d4f2620..79b8b116c 100644 --- a/src/engine/zsm.h +++ b/src/engine/zsm.h @@ -70,6 +70,7 @@ class DivZSM { int tickRate; int ymMask; int psgMask; + bool optimize; public: DivZSM(); ~DivZSM(); @@ -79,6 +80,7 @@ class DivZSM { 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(); diff --git a/src/engine/zsmOps.cpp b/src/engine/zsmOps.cpp index 6b360976b..3c72da663 100644 --- a/src/engine/zsmOps.cpp +++ b/src/engine/zsmOps.cpp @@ -26,7 +26,7 @@ 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) { +SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop, bool optimize) { int VERA=-1; int YM=-1; int IGNORED=0; @@ -118,6 +118,9 @@ SafeWriter* DivEngine::saveZSM(unsigned int zsmrate, bool loop) { // 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) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6950c72f4..b2abd3401 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4108,6 +4108,8 @@ bool FurnaceGUI::loop() { } ImGui::Checkbox("loop",&zsmExportLoop); ImGui::SameLine(); + ImGui::Checkbox("optimize size",&zsmExportOptimize); + ImGui::SameLine(); if (ImGui::Button("Begin Export")) { openFileDialog(GUI_FILE_EXPORT_ZSM); ImGui::CloseCurrentPopup(); @@ -5067,7 +5069,7 @@ bool FurnaceGUI::loop() { break; } case GUI_FILE_EXPORT_ZSM: { - SafeWriter* w=e->saveZSM(zsmExportTickRate,zsmExportLoop); + SafeWriter* w=e->saveZSM(zsmExportTickRate,zsmExportLoop,zsmExportOptimize); if (w!=NULL) { FILE* f=ps_fopen(copyOfName.c_str(),"wb"); if (f!=NULL) { @@ -6799,6 +6801,7 @@ FurnaceGUI::FurnaceGUI(): displayExporting(false), vgmExportLoop(true), zsmExportLoop(true), + zsmExportOptimize(true), vgmExportPatternHints(false), vgmExportDirectStream(false), displayInsTypeList(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index 2858b72f1..b26fcc6eb 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1324,7 +1324,7 @@ class FurnaceGUI { std::vector availRenderDrivers; std::vector availAudioDrivers; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, vgmExportPatternHints; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, zsmExportOptimize, vgmExportPatternHints; bool vgmExportDirectStream, displayInsTypeList; bool portrait, injectBackUp, mobileMenuOpen, warnColorPushed; bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;