From 36804d7c9b29724d7cc64918de9b82ddf09c8ae0 Mon Sep 17 00:00:00 2001 From: Zeta Date: Tue, 14 Nov 2023 03:27:03 -0500 Subject: [PATCH 1/5] Add an option to round volumes up when applying linear scaling This is secretly a FamiTracker compatibility mode, but it's useful in many other contexts. With upwards rounding, if both the channel and the macro volume are positive, then the computed result is also positive, ie, it will never become 0, which is silent on many chips. Still needs UI changes to expose the setting, and save/load work to persist it to file. --- src/engine/dispatch.h | 2 +- src/engine/song.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 2f6b7c04a..bfdcf6883 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -782,7 +782,7 @@ class DivDispatch { #define NOTE_FNUM_BLOCK(x,bits) parent->calcBaseFreqFNumBlock(chipClock,CHIP_FREQBASE,x,bits) // this is for volume scaling calculation. -#define VOL_SCALE_LINEAR(x,y,range) (((x)*(y))/(range)) +#define VOL_SCALE_LINEAR(x,y,range) ((parent->song.ceilVolumeScaling)?((((x)*(y))+(range-1))/(range)):(((x)*(y))/(range))) #define VOL_SCALE_LOG(x,y,range) (CLAMP(((x)+(y))-(range),0,(range))) #define VOL_SCALE_LINEAR_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(VOL_SCALE_LINEAR(x,y,range)):(VOL_SCALE_LOG(x,y,range))) #define VOL_SCALE_LOG_BROKEN(x,y,range) ((parent->song.newVolumeScaling)?(VOL_SCALE_LOG(x,y,range)):(VOL_SCALE_LINEAR(x,y,range))) diff --git a/src/engine/song.h b/src/engine/song.h index 7a7e267c2..50435aee1 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -379,6 +379,7 @@ struct DivSong { bool preNoteNoEffect; bool oldDPCM; bool resetArpPhaseOnNewNote; + bool ceilVolumeScaling; std::vector ins; std::vector wave; @@ -500,7 +501,8 @@ struct DivSong { brokenFMOff(false), preNoteNoEffect(false), oldDPCM(false), - resetArpPhaseOnNewNote(false) { + resetArpPhaseOnNewNote(false), + ceilVolumeScaling(false) { // DEBUG: before accepting PR, set this to false! (zeta hasn't touched the UI yet) for (int i=0; i Date: Tue, 14 Nov 2023 03:29:42 -0500 Subject: [PATCH 2/5] Expose volume ceiling option in the Compatibility Flags window --- src/gui/compatFlags.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index d5419c01c..a11200544 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -336,6 +336,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("when enabled, arpeggio effect (00xy) position is reset on a new note."); } + ImGui::Checkbox("Volume scaling rounds up",&e->song.ceilVolumeScaling); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("when enabled, volume macros round up when applied\nthis prevents volume scaling from causing vol=0, which is silent on some chips\n\nineffective on logarithmic channels"); + } ImGui::EndTabItem(); } ImGui::EndTabBar(); From 67d6f449472e0379ffb947d630536bc8cf74502b Mon Sep 17 00:00:00 2001 From: Zeta Date: Tue, 14 Nov 2023 03:51:51 -0500 Subject: [PATCH 3/5] Persist new volume rounding option to furnace module when saving --- papers/format.md | 3 ++- src/engine/fileOps.cpp | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/papers/format.md b/papers/format.md index 54c2c0275..bac66ca29 100644 --- a/papers/format.md +++ b/papers/format.md @@ -363,7 +363,8 @@ size | description 1 | pre note (C64) does not compensate for portamento or legato (>=168) 1 | disable new NES DPCM features (>=183) 1 | reset arp effect phase on new note (>=184) - 3 | reserved + 1 | linear volume scaling rounds up (>=187) + 2 | reserved --- | **speed pattern of first song** (>=139) 1 | length of speed pattern (fail if this is lower than 0 or higher than 16) 16 | speed pattern (this overrides speed 1 and speed 2 settings) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index c2dea0085..3cb2dce79 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1873,6 +1873,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<184) { ds.resetArpPhaseOnNewNote=false; } + if (ds.version<187) { + ds.ceilVolumeScaling=false; + } ds.isDMF=false; reader.readS(); // reserved @@ -2409,7 +2412,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<3; i++) { + if (ds.version>=187) { + ds.ceilVolumeScaling=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<2; i++) { reader.readC(); } } @@ -5494,7 +5502,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) { w->writeC(song.preNoteNoEffect); w->writeC(song.oldDPCM); w->writeC(song.resetArpPhaseOnNewNote); - for (int i=0; i<3; i++) { + w->writeC(song.ceilVolumeScaling); + for (int i=0; i<2; i++) { w->writeC(0); } From 947b7add5e69ddad9b4f3d2503eef7959019bd4b Mon Sep 17 00:00:00 2001 From: Zeta Date: Tue, 14 Nov 2023 04:17:05 -0500 Subject: [PATCH 4/5] Bump DIV_VERSION to 188, since we added a new compatibiltiy flag (Also adjust the file save/load to use that version) --- src/engine/engine.h | 2 +- src/engine/fileOps.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 43af4127f..73aecf0ef 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -55,7 +55,7 @@ class DivWorkPool; #define DIV_UNSTABLE #define DIV_VERSION "dev187" -#define DIV_ENGINE_VERSION 187 +#define DIV_ENGINE_VERSION 188 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 3cb2dce79..a13a1c8e4 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1873,7 +1873,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<184) { ds.resetArpPhaseOnNewNote=false; } - if (ds.version<187) { + if (ds.version<188) { ds.ceilVolumeScaling=false; } ds.isDMF=false; @@ -2412,7 +2412,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - if (ds.version>=187) { + if (ds.version>=188) { ds.ceilVolumeScaling=reader.readC(); } else { reader.readC(); From 52f0683c7f1e3d6c8e2637c06ca3946dfd3cdb7a Mon Sep 17 00:00:00 2001 From: Zeta Date: Tue, 14 Nov 2023 04:22:06 -0500 Subject: [PATCH 5/5] cleanup: remove silly comments, reference correct version number --- papers/format.md | 2 +- src/engine/song.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/papers/format.md b/papers/format.md index bac66ca29..242e8bcc4 100644 --- a/papers/format.md +++ b/papers/format.md @@ -363,7 +363,7 @@ size | description 1 | pre note (C64) does not compensate for portamento or legato (>=168) 1 | disable new NES DPCM features (>=183) 1 | reset arp effect phase on new note (>=184) - 1 | linear volume scaling rounds up (>=187) + 1 | linear volume scaling rounds up (>=188) 2 | reserved --- | **speed pattern of first song** (>=139) 1 | length of speed pattern (fail if this is lower than 0 or higher than 16) diff --git a/src/engine/song.h b/src/engine/song.h index 50435aee1..7306ea9d8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -502,7 +502,7 @@ struct DivSong { preNoteNoEffect(false), oldDPCM(false), resetArpPhaseOnNewNote(false), - ceilVolumeScaling(false) { // DEBUG: before accepting PR, set this to false! (zeta hasn't touched the UI yet) + ceilVolumeScaling(false) { for (int i=0; i