From 8db53faf720800d769fcbddbb564a24d33e34ccd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Apr 2022 04:23:52 -0500 Subject: [PATCH 1/9] new FM frequency calculation experiments --- src/engine/dispatch.h | 1 + src/engine/platform/genesis.cpp | 78 +++++++++--------------------- src/engine/platform/genesis.h | 3 -- src/engine/platform/genesisext.cpp | 66 +++++++++++-------------- 4 files changed, 51 insertions(+), 97 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index c35ff919c..b358c464c 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -426,6 +426,7 @@ class DivDispatch { #define NOTE_PERIODIC(x) round(parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true)) #define NOTE_PERIODIC_NOROUND(x) parent->calcBaseFreq(chipClock,CHIP_DIVIDER,x,true) #define NOTE_FREQUENCY(x) parent->calcBaseFreq(chipClock,CHIP_FREQBASE,x,false) +#define NOTE_FNUM_BLOCK(x,bits) ((((int)parent->calcBaseFreq(chipClock,CHIP_FREQBASE,(x)%12,false))&((1<calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq)); - if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val; + chan[i].freq=((chan[i].baseFreq&0xf800)|parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false))+chan[i].std.pitch.val; + if (chan[i].freq>65535) chan[i].freq=65535; + int freqt=chan[i].freq; immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8); immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff); if (chan[i].furnaceDac && dacMode) { @@ -422,47 +422,6 @@ void DivPlatformGenesis::tick(bool sysTick) { } } -int DivPlatformGenesis::octave(int freq) { - if (freq>=82432) { - return 128; - } else if (freq>=41216) { - return 64; - } else if (freq>=20608) { - return 32; - } else if (freq>=10304) { - return 16; - } else if (freq>=5152) { - return 8; - } else if (freq>=2576) { - return 4; - } else if (freq>=1288) { - return 2; - } else { - return 1; - } - return 1; -} - -int DivPlatformGenesis::toFreq(int freq) { - if (freq>=82432) { - return 0x3800|((freq>>7)&0x7ff); - } else if (freq>=41216) { - return 0x3000|((freq>>6)&0x7ff); - } else if (freq>=20608) { - return 0x2800|((freq>>5)&0x7ff); - } else if (freq>=10304) { - return 0x2000|((freq>>4)&0x7ff); - } else if (freq>=5152) { - return 0x1800|((freq>>3)&0x7ff); - } else if (freq>=2576) { - return 0x1000|((freq>>2)&0x7ff); - } else if (freq>=1288) { - return 0x800|((freq>>1)&0x7ff); - } else { - return freq&0x7ff; - } -} - void DivPlatformGenesis::muteChannel(int ch, bool mute) { isMuted[ch]=mute; for (int j=0; j<4; j++) { @@ -509,7 +468,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { dacPos=0; dacPeriod=0; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].freqChanged=true; } chan[c.chan].furnaceDac=true; @@ -576,7 +535,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { chan[c.chan].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].portaPause=false; chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; @@ -656,26 +615,33 @@ int DivPlatformGenesis::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_FREQUENCY(c.value2); + int destFreq=NOTE_FNUM_BLOCK(c.value2,11); int newFreq; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { - newFreq=chan[c.chan].baseFreq+c.value*octave(chan[c.chan].baseFreq); + newFreq=chan[c.chan].baseFreq+c.value; if (newFreq>=destFreq) { newFreq=destFreq; return2=true; } } else { - newFreq=chan[c.chan].baseFreq-c.value*octave(chan[c.chan].baseFreq); + newFreq=chan[c.chan].baseFreq-c.value; if (newFreq<=destFreq) { newFreq=destFreq; return2=true; } } + // check for octave boundary if (!chan[c.chan].portaPause) { - if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) { - chan[c.chan].portaPause=true; - break; + if ((newFreq&0x7ff)>1288) { + newFreq=((newFreq&0x7ff)>>1)|((newFreq+0x800)&0xf800); + /*chan[c.chan].portaPause=true; + break;*/ + } + if ((newFreq&0x7ff)<644) { + newFreq=(newFreq&0x7ff)<<1|((newFreq-0x800)&0xf800); + /*chan[c.chan].portaPause=true; + break;*/ } } chan[c.chan].baseFreq=newFreq; @@ -699,7 +665,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); + chan[c.chan].baseFreq=NOTE_FNUM_BLOCK(c.value,11); chan[c.chan].note=c.value; chan[c.chan].freqChanged=true; break; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index 34db5a252..ce52c6df1 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -93,9 +93,6 @@ class DivPlatformGenesis: public DivDispatch { short oldWrites[512]; short pendingWrites[512]; - int octave(int freq); - int toFreq(int freq); - friend void putDispatchChan(void*,int,int); void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index f0369370c..db51f5ead 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -72,7 +72,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { opChan[ch].insChanged=false; if (c.value!=DIV_NOTE_NULL) { - opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); + opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].portaPause=false; opChan[ch].freqChanged=true; } @@ -127,31 +127,46 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=NOTE_FREQUENCY(c.value2); + int destFreq=NOTE_FNUM_BLOCK(c.value2,11); int newFreq; bool return2=false; if (destFreq>opChan[ch].baseFreq) { - newFreq=opChan[ch].baseFreq+c.value*octave(opChan[ch].baseFreq); + newFreq=opChan[ch].baseFreq+c.value; if (newFreq>=destFreq) { newFreq=destFreq; return2=true; } } else { - newFreq=opChan[ch].baseFreq-c.value*octave(opChan[ch].baseFreq); + newFreq=opChan[ch].baseFreq-c.value; if (newFreq<=destFreq) { newFreq=destFreq; return2=true; } } if (!opChan[ch].portaPause) { - if (octave(opChan[ch].baseFreq)!=octave(newFreq)) { + opChan[ch].freqChanged=true; + if ((newFreq&0x7ff)>1288) { + newFreq=((newFreq&0x7ff)>>1)|((newFreq+0x800)&0xf800); opChan[ch].portaPause=true; - break; + opChan[ch].freqChanged=false; + return2=false; + if (ch==3) printf("%d: upper bound\n",ch); + //break; } + if ((newFreq&0x7ff)<644) { + newFreq=(newFreq&0x7ff)<<1|((newFreq-0x800)&0xf800); + opChan[ch].portaPause=true; + opChan[ch].freqChanged=false; + return2=false; + if (ch==3) printf("%d: lower bound\n",ch); + //break; + } + } else { + opChan[ch].portaPause=false; + opChan[ch].freqChanged=true; } + if (ch==3) printf("%d: writing %.4x to freq\n",ch,newFreq); opChan[ch].baseFreq=newFreq; - opChan[ch].portaPause=false; - opChan[ch].freqChanged=true; if (return2) return 2; break; } @@ -172,7 +187,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } break; case DIV_CMD_LEGATO: { - opChan[ch].baseFreq=NOTE_FREQUENCY(c.value); + opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); opChan[ch].freqChanged=true; break; } @@ -289,35 +304,10 @@ void DivPlatformGenesisExt::tick(bool sysTick) { unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { if (opChan[i].freqChanged) { - opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch); - if (opChan[i].freq>262143) opChan[i].freq=262143; - if (opChan[i].freq>=82432) { - opChan[i].freqH=((opChan[i].freq>>15)&7)|0x38; - opChan[i].freqL=(opChan[i].freq>>7)&0xff; - } else if (opChan[i].freq>=41216) { - opChan[i].freqH=((opChan[i].freq>>14)&7)|0x30; - opChan[i].freqL=(opChan[i].freq>>6)&0xff; - } else if (opChan[i].freq>=20608) { - opChan[i].freqH=((opChan[i].freq>>13)&7)|0x28; - opChan[i].freqL=(opChan[i].freq>>5)&0xff; - } else if (opChan[i].freq>=10304) { - opChan[i].freqH=((opChan[i].freq>>12)&7)|0x20; - opChan[i].freqL=(opChan[i].freq>>4)&0xff; - } else if (opChan[i].freq>=5152) { - opChan[i].freqH=((opChan[i].freq>>11)&7)|0x18; - opChan[i].freqL=(opChan[i].freq>>3)&0xff; - } else if (opChan[i].freq>=2576) { - opChan[i].freqH=((opChan[i].freq>>10)&7)|0x10; - opChan[i].freqL=(opChan[i].freq>>2)&0xff; - } else if (opChan[i].freq>=1288) { - opChan[i].freqH=((opChan[i].freq>>9)&7)|0x08; - opChan[i].freqL=(opChan[i].freq>>1)&0xff; - } else { - opChan[i].freqH=(opChan[i].freq>>8)&7; - opChan[i].freqL=opChan[i].freq&0xff; - } - immWrite(opChanOffsH[i],opChan[i].freqH); - immWrite(opChanOffsL[i],opChan[i].freqL); + opChan[i].freq=(opChan[i].baseFreq&0xf800)|parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch); + if (chan[i].freq>65535) chan[i].freq=65535; + immWrite(opChanOffsH[i],opChan[i].freq>>8); + immWrite(opChanOffsL[i],opChan[i].freq&0xff); } writeMask|=opChan[i].active<<(4+i); if (opChan[i].keyOn) { From 943e013cb469319fbbda2cc9540e39677ba773d7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Apr 2022 16:46:24 -0500 Subject: [PATCH 2/9] YM2612: new pitch slide formula finally nailed it (almost) --- src/engine/platform/genesis.cpp | 21 +++++++++++++-------- src/engine/platform/genesisext.cpp | 10 +++------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 80dac1d46..615747dc4 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -632,21 +632,26 @@ int DivPlatformGenesis::dispatch(DivCommand c) { } } // check for octave boundary + // what the heck! if (!chan[c.chan].portaPause) { + chan[c.chan].freqChanged=true; if ((newFreq&0x7ff)>1288) { - newFreq=((newFreq&0x7ff)>>1)|((newFreq+0x800)&0xf800); - /*chan[c.chan].portaPause=true; - break;*/ + newFreq=(644)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPause=true; + chan[c.chan].freqChanged=false; + return2=false; } if ((newFreq&0x7ff)<644) { - newFreq=(newFreq&0x7ff)<<1|((newFreq-0x800)&0xf800); - /*chan[c.chan].portaPause=true; - break;*/ + newFreq=(1287)|((newFreq-0x800)&0xf800); + chan[c.chan].portaPause=true; + chan[c.chan].freqChanged=false; + return2=false; } + } else { + chan[c.chan].portaPause=false; + chan[c.chan].freqChanged=true; } chan[c.chan].baseFreq=newFreq; - chan[c.chan].portaPause=false; - chan[c.chan].freqChanged=true; if (return2) { chan[c.chan].inPorta=false; return 2; diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index db51f5ead..2f8fba8c1 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -143,29 +143,25 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { return2=true; } } + // what the heck! if (!opChan[ch].portaPause) { opChan[ch].freqChanged=true; if ((newFreq&0x7ff)>1288) { - newFreq=((newFreq&0x7ff)>>1)|((newFreq+0x800)&0xf800); + newFreq=(644)|((newFreq+0x800)&0xf800); opChan[ch].portaPause=true; opChan[ch].freqChanged=false; return2=false; - if (ch==3) printf("%d: upper bound\n",ch); - //break; } if ((newFreq&0x7ff)<644) { - newFreq=(newFreq&0x7ff)<<1|((newFreq-0x800)&0xf800); + newFreq=(1287)|((newFreq-0x800)&0xf800); opChan[ch].portaPause=true; opChan[ch].freqChanged=false; return2=false; - if (ch==3) printf("%d: lower bound\n",ch); - //break; } } else { opChan[ch].portaPause=false; opChan[ch].freqChanged=true; } - if (ch==3) printf("%d: writing %.4x to freq\n",ch,newFreq); opChan[ch].baseFreq=newFreq; if (return2) return 2; break; From dd80cb8b55c9adf7e7c2441cf4ca47105300d7d6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Apr 2022 17:42:42 -0500 Subject: [PATCH 3/9] what the heck --- src/engine/platform/genesis.cpp | 2 +- src/engine/platform/genesisext.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 615747dc4..43aae3f13 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -394,7 +394,7 @@ void DivPlatformGenesis::tick(bool sysTick) { for (int i=0; i<6; i++) { if (i==2 && extMode) continue; if (chan[i].freqChanged) { - chan[i].freq=((chan[i].baseFreq&0xf800)|parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false))+chan[i].std.pitch.val; + chan[i].freq=((chan[i].baseFreq&0xf800)|parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4))+chan[i].std.pitch.val; if (chan[i].freq>65535) chan[i].freq=65535; int freqt=chan[i].freq; immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 2f8fba8c1..bb33f4017 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -300,7 +300,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) { unsigned char writeMask=2; if (extMode) for (int i=0; i<4; i++) { if (opChan[i].freqChanged) { - opChan[i].freq=(opChan[i].baseFreq&0xf800)|parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch); + opChan[i].freq=(opChan[i].baseFreq&0xf800)|parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4); if (chan[i].freq>65535) chan[i].freq=65535; immWrite(opChanOffsH[i],opChan[i].freq>>8); immWrite(opChanOffsL[i],opChan[i].freq&0xff); From f6b34a5bb0535383385b3da4014c4bfc5da58eed Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Apr 2022 04:25:22 -0500 Subject: [PATCH 4/9] huh? --- src/engine/platform/genesisext.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index bb33f4017..d8ae8b389 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -144,19 +144,18 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } } // what the heck! + // TODO: rework! if (!opChan[ch].portaPause) { - opChan[ch].freqChanged=true; if ((newFreq&0x7ff)>1288) { newFreq=(644)|((newFreq+0x800)&0xf800); opChan[ch].portaPause=true; - opChan[ch].freqChanged=false; return2=false; - } - if ((newFreq&0x7ff)<644) { + } else if ((newFreq&0x7ff)<644) { newFreq=(1287)|((newFreq-0x800)&0xf800); opChan[ch].portaPause=true; - opChan[ch].freqChanged=false; return2=false; + } else { + opChan[ch].freqChanged=true; } } else { opChan[ch].portaPause=false; From 6493a0481c80bb3cd91e6121ba2a78375a1a3e3d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Apr 2022 13:39:00 -0500 Subject: [PATCH 5/9] i hate this --- src/gui/gui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 009952a63..19f2e77e3 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" From 0e3dbdc1b28cfff246ed438315b17dc3716bcb9b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Apr 2022 16:52:31 -0500 Subject: [PATCH 6/9] this might fix it --- src/engine/platform/genesisext.cpp | 24 ++++++++++++------------ src/engine/platform/genesisext.h | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index d8ae8b389..eefec5d8f 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -130,6 +130,9 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { int destFreq=NOTE_FNUM_BLOCK(c.value2,11); int newFreq; bool return2=false; + if (opChan[ch].portaPause) { + opChan[ch].baseFreq=opChan[ch].portaPauseFreq; + } if (destFreq>opChan[ch].baseFreq) { newFreq=opChan[ch].baseFreq+c.value; if (newFreq>=destFreq) { @@ -144,23 +147,20 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { } } // what the heck! - // TODO: rework! if (!opChan[ch].portaPause) { if ((newFreq&0x7ff)>1288) { - newFreq=(644)|((newFreq+0x800)&0xf800); + opChan[ch].portaPauseFreq=(644)|((newFreq+0x800)&0xf800); opChan[ch].portaPause=true; - return2=false; - } else if ((newFreq&0x7ff)<644) { - newFreq=(1287)|((newFreq-0x800)&0xf800); - opChan[ch].portaPause=true; - return2=false; - } else { - opChan[ch].freqChanged=true; + break; + } + if ((newFreq&0x7ff)<644) { + opChan[ch].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800); + opChan[ch].portaPause=true; + break; } - } else { - opChan[ch].portaPause=false; - opChan[ch].freqChanged=true; } + opChan[ch].portaPause=false; + opChan[ch].freqChanged=true; opChan[ch].baseFreq=newFreq; if (return2) return 2; break; diff --git a/src/engine/platform/genesisext.h b/src/engine/platform/genesisext.h index fc9eed892..4cdf9fc65 100644 --- a/src/engine/platform/genesisext.h +++ b/src/engine/platform/genesisext.h @@ -25,13 +25,28 @@ class DivPlatformGenesisExt: public DivPlatformGenesis { struct OpChannel { DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch; + int freq, baseFreq, pitch, portaPauseFreq; unsigned char ins; signed char konCycles; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause; int vol; unsigned char pan; - OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {} + OpChannel(): + freqH(0), + freqL(0), + freq(0), + baseFreq(0), + pitch(0), + portaPauseFreq(0), + ins(-1), + active(false), + insChanged(true), + freqChanged(false), + keyOn(false), + keyOff(false), + portaPause(false), + vol(0), + pan(3) {} }; OpChannel opChan[4]; bool isOpMuted[4]; From a7828d6ad63500ef44ba0ec2683540394982f506 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Apr 2022 16:54:49 -0500 Subject: [PATCH 7/9] update contributing guidelines --- CONTRIBUTING.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad608e4cb..eb25675d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,12 +49,27 @@ the coding style is described here: - `size_t` are 32-bit or 64-bit, depending on architecture. - in float/double operations, always use decimal and `f` if single-precision. - e.g. `1.0f` or `1.0` instead of `1`. +- prefer `NULL` over `nullptr` or any other proprietary null. - don't use `auto` unless needed. +- use `String` for `std::string` (this is typedef'd in ta-utils.h). +- prefer using operator for String (std::string) comparisons (a==""). some files (particularly the ones in `src/engine/platform/sound` and `extern/`) don't follow this style. you don't have to follow this style. I will fix it after I accept your contribution. +additional guidelines: + +- in general **strongly** avoid breaking compatibility. + - do not touch loadFur/saveFur unless you know what you're doing! + - new fields must be at the end of each block to ensure forward compatibility + - likewise, the instrument read/write functions in DivInstrument have to be handled carefully + - any change to the format requires a version bump (see `src/engine/engine.h`). + - do not bump the version number under any circumstances! + - if you are making major changes to the playback routine, make sure to test with older songs to ensure nothing breaks. + - I will run a test suite to make sure this is the case. + - if something breaks, you might want to add a compatibility flag (this requires changing the format though). + ## Demo Songs just put your demo song in `demos/`! From dd9bb8327a0ab8588d75dbc098810753f75f9958 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 23 Apr 2022 18:02:43 -0500 Subject: [PATCH 8/9] and this finally does it the last thing to do is a compatibility flag --- src/engine/platform/genesis.cpp | 19 +++++++++---------- src/engine/platform/genesis.h | 3 ++- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 43aae3f13..61fffcb81 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -618,6 +618,9 @@ int DivPlatformGenesis::dispatch(DivCommand c) { int destFreq=NOTE_FNUM_BLOCK(c.value2,11); int newFreq; bool return2=false; + if (chan[c.chan].portaPause) { + chan[c.chan].baseFreq=chan[c.chan].portaPauseFreq; + } if (destFreq>chan[c.chan].baseFreq) { newFreq=chan[c.chan].baseFreq+c.value; if (newFreq>=destFreq) { @@ -634,23 +637,19 @@ int DivPlatformGenesis::dispatch(DivCommand c) { // check for octave boundary // what the heck! if (!chan[c.chan].portaPause) { - chan[c.chan].freqChanged=true; if ((newFreq&0x7ff)>1288) { - newFreq=(644)|((newFreq+0x800)&0xf800); + chan[c.chan].portaPauseFreq=(644)|((newFreq+0x800)&0xf800); chan[c.chan].portaPause=true; - chan[c.chan].freqChanged=false; - return2=false; + break; } if ((newFreq&0x7ff)<644) { - newFreq=(1287)|((newFreq-0x800)&0xf800); + chan[c.chan].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800); chan[c.chan].portaPause=true; - chan[c.chan].freqChanged=false; - return2=false; + break; } - } else { - chan[c.chan].portaPause=false; - chan[c.chan].freqChanged=true; } + chan[c.chan].portaPause=false; + chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=newFreq; if (return2) { chan[c.chan].inPorta=false; diff --git a/src/engine/platform/genesis.h b/src/engine/platform/genesis.h index ce52c6df1..b94303066 100644 --- a/src/engine/platform/genesis.h +++ b/src/engine/platform/genesis.h @@ -36,7 +36,7 @@ class DivPlatformGenesis: public DivDispatch { DivInstrumentFM state; DivMacroInt std; unsigned char freqH, freqL; - int freq, baseFreq, pitch, note; + int freq, baseFreq, pitch, portaPauseFreq, note; unsigned char ins; bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset; int vol, outVol; @@ -47,6 +47,7 @@ class DivPlatformGenesis: public DivDispatch { freq(0), baseFreq(0), pitch(0), + portaPauseFreq(0), note(0), ins(-1), active(false), From 23be8d93367f0960338725fb26cf7f9e65437fcf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 24 Apr 2022 14:40:07 -0500 Subject: [PATCH 9/9] the final piece of f-num/block work --- papers/format.md | 6 +++++- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 14 ++++++++++++-- src/engine/platform/genesisext.cpp | 20 ++++++++++++++------ src/engine/song.h | 4 +++- src/gui/compatFlags.cpp | 6 +++++- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/papers/format.md b/papers/format.md index 7775e9ea3..ef8ab7e50 100644 --- a/papers/format.md +++ b/papers/format.md @@ -29,6 +29,8 @@ furthermore, an `or reserved` indicates this field is always present, but is res the format versions are: +- 85: Furnace dev85 +- 84: Furnace dev84 - 83: Furnace dev83 - 82: Furnace dev82 - 81: Furnace dev81 @@ -269,7 +271,9 @@ size | description 1 | ExtCh channel state is shared (>=78) or reserved 1 | ignore DAC mode change outside of intended channel (>=83) or reserved 1 | E1xx and E2xx also take priority over Slide00 (>=83) or reserved - 23 | reserved + 1 | new Sega PCM (with macros and proper vol/pan) (>=84) or reserved + 1 | weird f-num/block-based chip pitch slides (>=85) or reserved + 21 | reserved ``` # instrument diff --git a/src/engine/engine.h b/src/engine/engine.h index 515b9c590..81e15f726 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -43,8 +43,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev84" -#define DIV_ENGINE_VERSION 84 +#define DIV_VERSION "dev85" +#define DIV_ENGINE_VERSION 85 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index aee7de71f..48ef68bba 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -162,6 +162,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.gbInsAffectsEnvelope=true; ds.ignoreDACModeOutsideIntendedChannel=false; ds.e1e2AlsoTakePriority=true; + ds.fbPortaPause=true; // 1.1 compat flags if (ds.version>24) { @@ -993,6 +994,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<84) { ds.newSegaPCM=false; } + if (ds.version<85) { + ds.fbPortaPause=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1342,7 +1346,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<22; i++) { + if (ds.version>=85) { + ds.fbPortaPause=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<21; i++) { reader.readC(); } } @@ -2283,7 +2292,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.ignoreDACModeOutsideIntendedChannel); w->writeC(song.e1e2AlsoTakePriority); w->writeC(song.newSegaPCM); - for (int i=0; i<22; i++) { + w->writeC(song.fbPortaPause); + for (int i=0; i<21; i++) { w->writeC(0); } diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index eefec5d8f..479e42421 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -149,14 +149,22 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { // what the heck! if (!opChan[ch].portaPause) { if ((newFreq&0x7ff)>1288) { - opChan[ch].portaPauseFreq=(644)|((newFreq+0x800)&0xf800); - opChan[ch].portaPause=true; - break; + if (parent->song.fbPortaPause) { + opChan[ch].portaPauseFreq=(644)|((newFreq+0x800)&0xf800); + opChan[ch].portaPause=true; + break; + } else { + newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800); + } } if ((newFreq&0x7ff)<644) { - opChan[ch].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800); - opChan[ch].portaPause=true; - break; + if (parent->song.fbPortaPause) { + opChan[ch].portaPauseFreq=newFreq=(1287)|((newFreq-0x800)&0xf800); + opChan[ch].portaPause=true; + break; + } else { + newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800); + } } } opChan[ch].portaPause=false; diff --git a/src/engine/song.h b/src/engine/song.h index 20b17ae60..9b9187ac6 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -324,6 +324,7 @@ struct DivSong { bool ignoreDACModeOutsideIntendedChannel; bool e1e2AlsoTakePriority; bool newSegaPCM; + bool fbPortaPause; DivOrders orders; std::vector ins; @@ -406,7 +407,8 @@ struct DivSong { sharedExtStat(true), ignoreDACModeOutsideIntendedChannel(false), e1e2AlsoTakePriority(false), - newSegaPCM(true) { + newSegaPCM(true), + fbPortaPause(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 d2035ff70..8d1fd6d18 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -101,6 +101,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("simulates a bug in where portamento does not work after sliding."); } + ImGui::Checkbox("FM pitch slide octave boundary odd behavior",&e->song.fbPortaPause); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("if this is on, a pitch slide that crosses the octave boundary will stop for one tick and then continue from the nearest octave boundary.\nfor .dmf compatibility."); + } ImGui::Checkbox("Apply Game Boy envelope on note-less instrument change",&e->song.gbInsAffectsEnvelope); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("if this is on, an instrument change will also affect the envelope."); @@ -173,4 +177,4 @@ void FurnaceGUI::drawCompatFlags() { } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End(); -} \ No newline at end of file +}