From 393d1c018dfe6790139423609ce09216134b8c66 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 22 May 2022 13:25:59 -0500 Subject: [PATCH] dev97 - add old octave boundary compat flag --- papers/format.md | 4 +++- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 ++++++++++++-- src/engine/platform/genesis.cpp | 20 ++++++++++++++------ src/engine/platform/ym2203.cpp | 20 ++++++++++++++------ src/engine/platform/ym2608.cpp | 20 ++++++++++++++------ src/engine/platform/ym2610.cpp | 20 ++++++++++++++------ src/engine/platform/ym2610b.cpp | 20 ++++++++++++++------ src/engine/song.h | 4 +++- src/gui/compatFlags.cpp | 4 ++++ 10 files changed, 94 insertions(+), 36 deletions(-) diff --git a/papers/format.md b/papers/format.md index a2c66da7..d519e863 100644 --- a/papers/format.md +++ b/papers/format.md @@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res the format versions are: +- 97: Furnace dev97 - 96: Furnace dev96 - 95: Furnace dev95 - 94: Furnace dev94 @@ -300,7 +301,8 @@ size | description 1 | SN duty macro always resets phase (>=86) or reserved 1 | pitch macro is linear (>=90) or reserved 1 | pitch slide speed in full linear pitch mode (>=94) or reserved - 14 | reserved + 1 | old octave boundary behavior (>=97) or reserved + 13 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved diff --git a/src/engine/engine.h b/src/engine/engine.h index 5537dcc0..171c7424 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -45,8 +45,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev96" -#define DIV_ENGINE_VERSION 96 +#define DIV_VERSION "dev97" +#define DIV_ENGINE_VERSION 97 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 7fee6f82..5b8fa728 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -166,6 +166,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2AlsoTakePriority=true; ds.fbPortaPause=true; ds.snDutyReset=true; + ds.oldOctaveBoundary=false; // 1.1 compat flags if (ds.version>24) { @@ -1027,6 +1028,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<90) { ds.pitchMacroIsLinear=false; } + if (ds.version<97) { + ds.oldOctaveBoundary=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1404,7 +1408,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<14; i++) { + if (ds.version>=97) { + ds.oldOctaveBoundary=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<13; i++) { reader.readC(); } } @@ -2871,7 +2880,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.snDutyReset); w->writeC(song.pitchMacroIsLinear); w->writeC(song.pitchSlideSpeed); - for (int i=0; i<14; i++) { + w->writeC(song.oldOctaveBoundary); + for (int i=0; i<13; i++) { w->writeC(0); } diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 40ef34a5..8c707067 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -781,14 +781,22 @@ int DivPlatformGenesis::dispatch(DivCommand c) { // what the heck! if (!chan[c.chan].portaPause) { if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { - chan[c.chan].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=(parent->song.oldOctaveBoundary?(newFreq>>1):boundaryBottom)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)0) { - chan[c.chan].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=newFreq=(parent->song.oldOctaveBoundary?(newFreq<<1):(boundaryTop-1))|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } chan[c.chan].portaPause=false; diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 24e092d1..78fe66b4 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -684,14 +684,22 @@ int DivPlatformYM2203::dispatch(DivCommand c) { // what the heck! if (!chan[c.chan].portaPause) { if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { - chan[c.chan].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=(parent->song.oldOctaveBoundary?(newFreq>>1):boundaryBottom)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)0) { - chan[c.chan].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=newFreq=(parent->song.oldOctaveBoundary?(newFreq<<1):(boundaryTop-1))|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } chan[c.chan].portaPause=false; diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 8782ac27..8941f673 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1005,14 +1005,22 @@ int DivPlatformYM2608::dispatch(DivCommand c) { // what the heck! if (!chan[c.chan].portaPause) { if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { - chan[c.chan].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=(parent->song.oldOctaveBoundary?(newFreq>>1):boundaryBottom)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)0) { - chan[c.chan].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=newFreq=(parent->song.oldOctaveBoundary?(newFreq<<1):(boundaryTop-1))|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } chan[c.chan].portaPause=false; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 7f94421e..08479b00 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -1052,14 +1052,22 @@ int DivPlatformYM2610::dispatch(DivCommand c) { // what the heck! if (!chan[c.chan].portaPause) { if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { - chan[c.chan].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=(parent->song.oldOctaveBoundary?(newFreq>>1):boundaryBottom)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)0) { - chan[c.chan].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=newFreq=(parent->song.oldOctaveBoundary?(newFreq<<1):(boundaryTop-1))|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } chan[c.chan].portaPause=false; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index fd7c8739..2468a6d9 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -1030,14 +1030,22 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { // what the heck! if (!chan[c.chan].portaPause) { if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) { - chan[c.chan].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=(parent->song.oldOctaveBoundary?(newFreq>>1):boundaryBottom)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)0) { - chan[c.chan].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800); - chan[c.chan].portaPause=true; - break; + if (parent->song.fbPortaPause) { + chan[c.chan].portaPauseFreq=newFreq=(parent->song.oldOctaveBoundary?(newFreq<<1):(boundaryTop-1))|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } chan[c.chan].portaPause=false; diff --git a/src/engine/song.h b/src/engine/song.h index b96339d5..68417e71 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -393,6 +393,7 @@ struct DivSong { bool fbPortaPause; bool snDutyReset; bool pitchMacroIsLinear; + bool oldOctaveBoundary; std::vector ins; std::vector wave; @@ -485,7 +486,8 @@ struct DivSong { newSegaPCM(true), fbPortaPause(false), snDutyReset(false), - pitchMacroIsLinear(true) { + pitchMacroIsLinear(true), + oldOctaveBoundary(false) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index ca4195af..b6dabafc 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -209,6 +209,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6"); } + ImGui::Checkbox("Old FM octave boundary behavior",&e->song.oldOctaveBoundary); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6"); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End();