diff --git a/papers/format.md b/papers/format.md index bef8b1f8..3e358346 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 101: Furnace 0.6pre1 (dev101) - 100: Furnace 0.6pre1 - 99: Furnace dev99 - 98: Furnace dev98 @@ -318,7 +319,8 @@ size | description 1 | volume macro still applies after end (>=99) or reserved 1 | broken outVol (>=99) or reserved 1 | E1xy and E2xy stop on same note (>=100) or reserved - 8 | reserved + 1 | broken initial position of porta after arp (>=101) or reserved + 7 | 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 962e0fcc..5f5ab1a3 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 "0.6pre1" -#define DIV_ENGINE_VERSION 100 +#define DIV_VERSION "0.6pre1 (dev101)" +#define DIV_ENGINE_VERSION 101 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index d4c45323..ddc5edf6 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -172,6 +172,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.volMacroLinger=false; ds.brokenOutVol=true; // ??? ds.e1e2StopOnSameNote=true; + ds.brokenPortaArp=false; // 1.1 compat flags if (ds.version>24) { @@ -1047,6 +1048,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<100) { ds.e1e2StopOnSameNote=false; } + if (ds.version<101) { + ds.brokenPortaArp=true; + } ds.isDMF=false; reader.readS(); // reserved @@ -1448,7 +1452,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<8; i++) { + if (ds.version>=101) { + ds.brokenPortaArp=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<7; i++) { reader.readC(); } } @@ -2922,7 +2931,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.volMacroLinger); w->writeC(song.brokenOutVol); w->writeC(song.e1e2StopOnSameNote); - for (int i=0; i<8; i++) { + w->writeC(song.brokenPortaArp); + for (int i=0; i<7; i++) { w->writeC(0); } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 8037feaf..65b44136 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -355,6 +355,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 1be61fa2..41042cd5 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -827,6 +827,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 07377610..7018824b 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -474,6 +474,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 0fad4025..581ebb9e 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -506,6 +506,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 48a07880..5fe4462f 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -250,6 +250,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index a55b5390..640df54e 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -369,6 +369,7 @@ int DivPlatformC64::dispatch(DivCommand c) { chan[c.chan].keyOn=true; } } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index ea4b83e9..f9fc5b50 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -406,6 +406,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index 999d31b9..2b7dcf6d 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -393,6 +393,7 @@ int DivPlatformGB::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GB_SWEEP_DIR: diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 4fd30db9..3f5e92c0 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -387,6 +387,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 2b97f46f..dc9e5aba 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -324,6 +324,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 50f9d836..b20b460e 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -562,6 +562,7 @@ int DivPlatformN163::dispatch(DivCommand c) { chan[c.chan].keyOn=true; } } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/namcowsg.cpp b/src/engine/platform/namcowsg.cpp index 6bcf43d2..00b12793 100644 --- a/src/engine/platform/namcowsg.cpp +++ b/src/engine/platform/namcowsg.cpp @@ -442,6 +442,7 @@ int DivPlatformNamcoWSG::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 67ad2852..d801fe66 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -573,6 +573,7 @@ int DivPlatformNES::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 9373d0cd..823e764b 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1434,6 +1434,9 @@ int DivPlatformOPL::dispatch(DivCommand c) { return 63; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) { + chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(chan[c.chan].note)):(NOTE_FREQUENCY(chan[c.chan].note)); + } chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 08292be6..5c9611b4 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -831,6 +831,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (c.chan>=9 && !properDrums) return 0; + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index b8c580e5..9e1302a0 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -445,6 +445,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 57c72b67..d40a297a 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -471,6 +471,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 9b3c9988..49343627 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -239,6 +239,7 @@ int DivPlatformPET::dispatch(DivCommand c) { if (chan.active && c.value2) { if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_PET)); } + if (!chan.inPorta && c.value && !parent->song.brokenPortaArp && chan.std.arp.will) chan.baseFreq=NOTE_PERIODIC(chan.note); chan.inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 8af565df..6eb14be7 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -496,6 +496,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=QS_NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/rf5c68.cpp b/src/engine/platform/rf5c68.cpp index 2106a5a7..176b6e7c 100644 --- a/src/engine/platform/rf5c68.cpp +++ b/src/engine/platform/rf5c68.cpp @@ -265,6 +265,7 @@ int DivPlatformRF5C68::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index c562838a..103c3348 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -335,6 +335,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/scc.cpp b/src/engine/platform/scc.cpp index 8175bc01..485839bf 100644 --- a/src/engine/platform/scc.cpp +++ b/src/engine/platform/scc.cpp @@ -267,6 +267,7 @@ int DivPlatformSCC::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 19b8eb82..71d45298 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -365,6 +365,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<6); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 28462027..3d11a5ac 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -353,9 +353,8 @@ int DivPlatformSMS::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; - // TODO: pre porta cancel arp compat flag - //if (chan[c.chan].inPorta) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); break; case DIV_CMD_GET_VOLMAX: return 15; diff --git a/src/engine/platform/su.cpp b/src/engine/platform/su.cpp index c6860afb..f3be01a7 100644 --- a/src/engine/platform/su.cpp +++ b/src/engine/platform/su.cpp @@ -454,6 +454,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 905fa82a..b3e83319 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -431,6 +431,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index da347244..ddb38084 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -259,6 +259,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=(chan[c.chan].note<<8); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 123d1193..9d24e4db 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -933,6 +933,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_LINEAR(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 62e1ea68..092bbb6a 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -359,6 +359,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=calcNoteFreq(c.chan,chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_STD_NOISE_MODE: diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 8475b0e5..771b87d1 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -243,6 +243,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 08c6d053..88fcb37b 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -399,6 +399,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_PERIODIC(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index dc5c7ed2..e2e360b1 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -732,6 +732,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NoteX1_010(c.chan,chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_FREQ: diff --git a/src/engine/platform/ymz280b.cpp b/src/engine/platform/ymz280b.cpp index 45631a94..d8d98478 100644 --- a/src/engine/platform/ymz280b.cpp +++ b/src/engine/platform/ymz280b.cpp @@ -293,6 +293,7 @@ int DivPlatformYMZ280B::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: diff --git a/src/engine/platform/zxbeeper.cpp b/src/engine/platform/zxbeeper.cpp index 524d3c11..01702dc5 100644 --- a/src/engine/platform/zxbeeper.cpp +++ b/src/engine/platform/zxbeeper.cpp @@ -224,6 +224,7 @@ int DivPlatformZXBeeper::dispatch(DivCommand c) { if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note); chan[c.chan].inPorta=c.value; break; case DIV_CMD_GET_VOLMAX: diff --git a/src/engine/song.h b/src/engine/song.h index d06c5737..185cac8a 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -497,6 +497,7 @@ struct DivSong { bool volMacroLinger; bool brokenOutVol; bool e1e2StopOnSameNote; + bool brokenPortaArp; std::vector ins; std::vector wave; @@ -595,7 +596,8 @@ struct DivSong { newVolumeScaling(true), volMacroLinger(true), brokenOutVol(false), - e1e2StopOnSameNote(false) { + e1e2StopOnSameNote(false), + brokenPortaArp(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 8e5d7517..9024992e 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -207,31 +207,35 @@ void FurnaceGUI::drawCompatFlags() { } ImGui::Checkbox("Stop portamento on note off",&e->song.stopPortaOnNoteOff); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Allow instrument change during slides",&e->song.newInsTriggersInPorta); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Reset note to base on arpeggio stop",&e->song.arp0Reset); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("ExtCh channel status is shared among operators",&e->song.sharedExtStat); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("New SegaPCM features (macros and better panning)",&e->song.newSegaPCM); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("Old FM octave boundary behavior",&e->song.oldOctaveBoundary); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); } ImGui::Checkbox("No OPN2 DAC volume control",&e->song.noOPN2Vol); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("behavior changed in 0.6"); + ImGui::SetTooltip("behavior changed in 0.6pre1"); + } + ImGui::Checkbox("Broken initial position of portamento after arpeggio",&e->song.brokenPortaArp); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6pre1.5"); } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;