diff --git a/papers/format.md b/papers/format.md index b04deac7..d5b9c67e 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: +- 66: Furnace dev66 - 65: Furnace dev65 - 64: Furnace dev64 - 63: Furnace dev63 @@ -207,7 +208,8 @@ size | description 1 | continuous vibrato (>=62) or reserved 1 | broken DAC mode (>=64) or reserved 1 | one tick cut (>=65) or reserved - 2 | reserved + 1 | instrument change allowed during porta (>=66) or reserved + 1 | reserved 4?? | pointers to instruments 4?? | pointers to wavetables 4?? | pointers to samples diff --git a/src/engine/engine.h b/src/engine/engine.h index fc70c873..b75fc2f0 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -37,8 +37,8 @@ warnings+=(String("\n")+x); \ } -#define DIV_VERSION "dev65" -#define DIV_ENGINE_VERSION 65 +#define DIV_VERSION "dev66" +#define DIV_ENGINE_VERSION 66 enum DivStatusView { DIV_STATUS_NOTHING=0, @@ -69,7 +69,7 @@ enum DivHaltPositions { struct DivChannelState { std::vector delayed; - int note, oldNote, pitch, portaSpeed, portaNote; + int note, oldNote, lastIns, pitch, portaSpeed, portaNote; int volume, volSpeed, cut, rowDelay, volMax; int delayOrder, delayRow, retrigSpeed, retrigTick; int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine; @@ -80,6 +80,7 @@ struct DivChannelState { DivChannelState(): note(-1), oldNote(-1), + lastIns(-1), pitch(0), portaSpeed(-1), portaNote(-1), diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 3c1a9d2a..524531f8 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -142,6 +142,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.ignoreDuplicateSlides=true; ds.brokenDACMode=true; ds.oneTickCut=false; + ds.newInsTriggersInPorta=true; // 1.1 compat flags if (ds.version>24) { @@ -807,6 +808,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<65) { ds.oneTickCut=false; } + if (ds.version<66) { + ds.newInsTriggersInPorta=false; + } ds.isDMF=false; reader.readS(); // reserved @@ -993,7 +997,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<2; i++) reader.readC(); + if (ds.version>=66) { + ds.newInsTriggersInPorta=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<1; i++) reader.readC(); } else { for (int i=0; i<20; i++) reader.readC(); } @@ -1437,7 +1446,8 @@ SafeWriter* DivEngine::saveFur() { w->writeC(song.continuousVibrato); w->writeC(song.brokenDACMode); w->writeC(song.oneTickCut); - for (int i=0; i<2; i++) { + w->writeC(song.newInsTriggersInPorta); + for (int i=0; i<1; i++) { w->writeC(0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 4626635b..8a543fee 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -654,6 +654,12 @@ void DivEngine::processRow(int i, bool afterDelay) { // instrument if (pat->data[whatRow][2]!=-1) { dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,i,pat->data[whatRow][2])); + if (chan[i].lastIns!=pat->data[whatRow][2]) { + chan[i].lastIns=pat->data[whatRow][2]; + if (chan[i].inPorta && song.newInsTriggersInPorta) { + dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL)); + } + } } // note if (pat->data[whatRow][0]==100) { // note off diff --git a/src/engine/song.h b/src/engine/song.h index 5747aa51..7fc6ec7f 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -297,6 +297,7 @@ struct DivSong { bool continuousVibrato; bool brokenDACMode; bool oneTickCut; + bool newInsTriggersInPorta; DivOrders orders; std::vector ins; @@ -363,7 +364,8 @@ struct DivSong { stopPortaOnNoteOff(false), continuousVibrato(false), brokenDACMode(false), - oneTickCut(false) { + oneTickCut(false), + newInsTriggersInPorta(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 3143f684..24b7d46b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2216,6 +2216,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6"); } + ImGui::Checkbox("Allow instrument change during slides",&e->song.newInsTriggersInPorta); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6"); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End();