diff --git a/papers/format.md b/papers/format.md index 54c2c0275..242e8bcc4 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 (>=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) 16 | speed pattern (this overrides speed 1 and speed 2 settings) 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/engine.h b/src/engine/engine.h index 53673a4ba..556057cc2 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -54,8 +54,8 @@ class DivWorkPool; #define DIV_UNSTABLE -#define DIV_VERSION "dev187" -#define DIV_ENGINE_VERSION 187 +#define DIV_VERSION "dev188" +#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 e7f1653ca..ef11593d2 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<188) { + 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>=188) { + 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); } diff --git a/src/engine/song.h b/src/engine/song.h index 7a7e267c2..7306ea9d8 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) { for (int i=0; isong.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();