From 10aaf7f0cb9dcddad32a444125cef56224e17abd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 19:57:01 -0500 Subject: [PATCH 1/9] YM2612: #580 --- src/engine/platform/genesisext.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 1f320dd3..dfd7d514 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -561,6 +561,11 @@ void DivPlatformGenesisExt::forceIns() { opChan[i].freqChanged=true; } } + if (extMode && softPCM && chan[7].active) { // CSM + chan[7].insChanged=true; + chan[7].freqChanged=true; + chan[7].keyOn=true; + } } void* DivPlatformGenesisExt::getChanState(int ch) { From b223bc80de9f16fc137f033e7ed50d0037cebbe1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 20:06:01 -0500 Subject: [PATCH 2/9] YM2612: #581 --- src/engine/platform/genesis.cpp | 36 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 143a90fe..7dde9790 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -263,19 +263,37 @@ void DivPlatformGenesis::tick(bool sysTick) { } } - if (chan[i].std.arp.had) { - if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); - } else { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); + if (i>=5 && chan[i].furnaceDac) { + if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + if (chan[i].std.arp.mode) { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].std.arp.val,false); + } else { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note+(signed char)chan[i].std.arp.val,false); + } + } + chan[i].freqChanged=true; + } else { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { + chan[i].baseFreq=parent->calcBaseFreq(1,1,chan[i].note,false); + chan[i].freqChanged=true; } } - chan[i].freqChanged=true; } else { - if (chan[i].std.arp.mode && chan[i].std.arp.finished) { - chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); + if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + if (chan[i].std.arp.mode) { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].std.arp.val,11); + } else { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note+(signed char)chan[i].std.arp.val,11); + } + } chan[i].freqChanged=true; + } else { + if (chan[i].std.arp.mode && chan[i].std.arp.finished) { + chan[i].baseFreq=NOTE_FNUM_BLOCK(chan[i].note,11); + chan[i].freqChanged=true; + } } } From 38afdd3378bcac8878c41d6442f6b54caf50c458 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 21 Aug 2022 23:56:58 -0500 Subject: [PATCH 3/9] dev110 - add cut/delay effect policy compat flag INCOMPLETE!!! --- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 15 +++++++++++++-- src/engine/playback.cpp | 5 ++++- src/engine/song.h | 6 ++++++ src/gui/compatFlags.cpp | 20 ++++++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index c433def8..d379540c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev109" -#define DIV_ENGINE_VERSION 109 +#define DIV_VERSION "dev110" +#define DIV_ENGINE_VERSION 110 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index df32f055..e64e02a0 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -176,6 +176,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ds.e1e2StopOnSameNote=true; ds.brokenPortaArp=false; ds.snNoLowPeriods=true; + ds.delayBehavior=0; // 1.1 compat flags if (ds.version>24) { @@ -1067,6 +1068,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<108) { ds.snNoLowPeriods=true; } + if (ds.version<110) { + ds.delayBehavior=1; + } ds.isDMF=false; reader.readS(); // reserved @@ -1484,7 +1488,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<6; i++) { + if (ds.version>=110) { + ds.delayBehavior=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<5; i++) { reader.readC(); } } @@ -1917,6 +1926,7 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) { ds.noSlidesOnFirstTick=true; ds.rowResetsArpPos=true; ds.ignoreJumpAtEnd=false; + ds.delayBehavior=0; int insCount=31; bool bypassLimits=false; @@ -3729,7 +3739,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.e1e2StopOnSameNote); w->writeC(song.brokenPortaArp); w->writeC(song.snNoLowPeriods); - for (int i=0; i<6; i++) { + w->writeC(song.delayBehavior); + for (int i=0; i<5; i++) { w->writeC(0); } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 63203ab5..fbd9e8db 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -361,7 +361,9 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xed: // delay if (effectVal!=0) { - if (effectVal<=nextSpeed) { + bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectVal%d",effectVal,nextSpeed); chan[i].delayLocked=false; } } diff --git a/src/engine/song.h b/src/engine/song.h index 30f5ef24..83509efb 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -463,6 +463,11 @@ struct DivSong { // 1: fake reset on loop // 2: don't do anything on loop unsigned char loopModality; + // cut/delay effect behavior + // 0: strict (don't allow value higher than or equal to speed) + // 1: broken (don't allow value higher than speed) + // 2: lax (allow value higher than speed) + unsigned char delayBehavior; bool properNoiseLayout; bool waveDutyIsVol; bool resetMacroOnPorta; @@ -565,6 +570,7 @@ struct DivSong { linearPitch(2), pitchSlideSpeed(4), loopModality(0), + delayBehavior(2), properNoiseLayout(true), waveDutyIsVol(false), resetMacroOnPorta(false), diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index e6d0aed8..74d493e7 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -193,6 +193,26 @@ void FurnaceGUI::drawCompatFlags() { ImGui::SetTooltip("select to not reset channels on loop."); } + ImGui::Text("Cut/delay effect policy:"); + if (ImGui::RadioButton("Strict",e->song.delayBehavior==0)) { + e->song.delayBehavior=0; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only when time is less than speed (like DefleMask/ProTracker)"); + } + if (ImGui::RadioButton("Strict (old)",e->song.delayBehavior==1)) { + e->song.delayBehavior=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("only when time is less than or equal to speed (original buggy behavior)"); + } + if (ImGui::RadioButton("Lax",e->song.delayBehavior==2)) { + e->song.delayBehavior=2; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("no checks (like FamiTracker)"); + } + ImGui::Separator(); ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions."); From 629cca9df19560e34af4586337e9f1207fe1214e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 00:01:21 -0500 Subject: [PATCH 4/9] ECxx --- src/engine/playback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fbd9e8db..8c8fa572 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -707,7 +707,7 @@ void DivEngine::processRow(int i, bool afterDelay) { dispatchCmd(DivCommand(DIV_CMD_SAMPLE_BANK,i,effectVal)); break; case 0xec: // delayed note cut - if (effectVal>0 && effectVal0 && (song.delayBehavior==2 || effectVal Date: Mon, 22 Aug 2022 00:20:40 -0500 Subject: [PATCH 5/9] allow it --- src/engine/playback.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8c8fa572..f4c4968d 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -382,6 +382,8 @@ void DivEngine::processRow(int i, bool afterDelay) { } } if (returnAfterPre) return; + } else { + logV("honoring delay at position %d",whatRow); } if (chan[i].delayLocked) return; @@ -903,7 +905,9 @@ void DivEngine::nextRow() { prevRow=curRow; for (int i=0; i Date: Mon, 22 Aug 2022 13:11:29 +0700 Subject: [PATCH 6/9] new demo song.. --- demos/rule2.fur | Bin 0 -> 2179 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/rule2.fur diff --git a/demos/rule2.fur b/demos/rule2.fur new file mode 100644 index 0000000000000000000000000000000000000000..aa6375916934671667382ca2232272e3c6d3f3f8 GIT binary patch literal 2179 zcmV-}2z>W=ob6m)Y#h}UK6hqzcKuV9kUzI|vXhpdB;?m24L=Xw#lbjD;-5GM3@LQt zY{|lU*Ilm(RwdR7s#2;5@qiFQP}+yKLMlJv0U@MT8|8rqr1k-Vc;F$1_MuW~snk?e za6FtlbH{UcJ=Z(etRsfbalZAPGv|Ki-gEBknYruD_TH&d!5qsPQc{)Q18!_d99 z3SdVEz^fYpR^JHl$~J)RTL3QH0g&qf_}_kj@w))bUH}X6Odr6e9|F925TNHUzz6*R z*+GE+4gs7Q2Iv?;j(Y%ZzYpNOQGjC)0DN`~;E4wTl0OFcwF$6$%pHvbMdgpYmj6+$ zU}sg+VtPDI6vByb0B5>k!888T+>j`?`Z@e@WAwRtZ zj-JdKN3v!IDJnk*0+nPuZdae4gj0RSP8LfiLS25!0yEHqNviy;sMt-7O3Hw&!arPkl zSTR2}o(=WA#8-Kg{at{5(W7j5eaZF>yEHqNviy;sMt-9DW7nTktp5CTDwi$)-@rA^wi| zE8-&JW5h>@_Yr?VyoY!faUSs}#5;($5N{%0MZALeE#fzbmk`e*o<%%^IEy%gcoI=T z{0wmlQ39F-fJYENL70diAx04+h#|xwL?2>5BF*MYH+bnLF5RT18?khQm2RTaO;WlM zN~)bR*I)UG?#ZHW|a~OSW&=rP;BR<&XR{@)K2AyUISz9`eTW#fi{XS(-jg zz!fAh^rN_T*B0-&Cuf}+;P%MSELeXcOrJe)b-$9b3a%kreJu7+=Rps#dlI&mZAUvB;7ChGJb)OmmA$X)O`t;7Ez@Q2f$PpYf;`Du6O{P|g{dmi)LIZvwe@Eqx! z{}iiql^Qr}p<3Ik<|?ZVUQ&39KjZP)&d<+wcUI5MQs)HbaHZO#!WU>J_ z!#$g!bEf~t$AA;)Th+yZrn>q`lWDkAu><`EnIBG9dZruEO@$}`kUzq8QaOGt(v97m0KXcof4^rvD3!TT_x7J<+xHsK?$+GUf zFgFud*IXRT96j zj2lCcgw*Q&`FVSO%s~?3&m-m+B*f`(f?Ewdf!9_AdL@882-?l!S5}z+DvaMti1!vB z>IwPqQ}JtG4IBR}grB=o+jbM;mJ#|^LqP2O>)zHwK7KACZVd_dgjPBsswBVkc-(}z z+ktH%Pe^OX$Im5%L5r zCB(h$)$qqL3PPYW`+9vspl=oE#cvV*_H6=vyN`YrGQznKoVg#5D$vW?>yq|dLYy04 zKZmn$r>}mgz{mz(l)z>z1Ui1%l`6XsMD}sXd2tC**%d-_=T6#d^ZMF>c=|T3O^cbI zy~^o%8&zPh32ZchJ Date: Mon, 22 Aug 2022 02:13:33 -0500 Subject: [PATCH 7/9] dev111 - many macro changes - max macro length is now 255 - loop/rel pos is now unsigned (255 = no) - prepare for macro speed/delay --- papers/format.md | 96 ++++++++++++++++++- src/engine/engine.h | 4 +- src/engine/fileOps.cpp | 24 ++--- src/engine/instrument.cpp | 190 +++++++++++++++++++++++++++++++++++++- src/engine/instrument.h | 11 +-- src/engine/macroInt.cpp | 8 +- src/gui/gui.cpp | 14 +-- src/gui/gui.h | 4 +- src/gui/insEdit.cpp | 37 ++++---- 9 files changed, 333 insertions(+), 55 deletions(-) diff --git a/papers/format.md b/papers/format.md index 7bd3bba7..4d9c15a2 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,9 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 111: Furnace dev111 +- 110: Furnace dev110 +- 109: Furnace dev109 - 108: Furnace dev108 - 107: Furnace dev107 - 106: Furnace dev106 @@ -333,7 +336,8 @@ size | description 1 | E1xy and E2xy stop on same note (>=100) or reserved 1 | broken initial position of porta after arp (>=101) or reserved 1 | SN periods under 8 are treated as 1 (>=108) or reserved - 6 | reserved + 1 | cut/delay effect policy (>=110) or reserved + 5 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved @@ -868,6 +872,96 @@ size | description 1 | K2 ramp 1 | K1 slow 1 | K2 slow + --- | **SNES data** (>=109) + 1 | use envelope + 1 | gain mode + 1 | gain + 1 | attack + 1 | decay + 1 | sustain + 1 | release + --- | **macro speeds/delays** (>=111) + 1 | volume macro speed + 1 | arp macro speed + 1 | duty macro speed + 1 | wave macro speed + 1 | pitch macro speed + 1 | extra 1 macro speed + 1 | extra 2 macro speed + 1 | extra 3 macro speed + 1 | alg macro speed + 1 | fb macro speed + 1 | fms macro speed + 1 | ams macro speed + 1 | left panning macro speed + 1 | right panning macro speed + 1 | phase reset macro speed + 1 | extra 4 macro speed + 1 | extra 5 macro speed + 1 | extra 6 macro speed + 1 | extra 7 macro speed + 1 | extra 8 macro speed + 1 | volume macro delay + 1 | arp macro delay + 1 | duty macro delay + 1 | wave macro delay + 1 | pitch macro delay + 1 | extra 1 macro delay + 1 | extra 2 macro delay + 1 | extra 3 macro delay + 1 | alg macro delay + 1 | fb macro delay + 1 | fms macro delay + 1 | ams macro delay + 1 | left panning macro delay + 1 | right panning macro delay + 1 | phase reset macro delay + 1 | extra 4 macro delay + 1 | extra 5 macro delay + 1 | extra 6 macro delay + 1 | extra 7 macro delay + 1 | extra 8 macro delay + --- | **operator macro speeds/delay** × 4 (>=111) + 1 | AM macro speed + 1 | AR macro speed + 1 | DR macro speed + 1 | MULT macro speed + 1 | RR macro speed + 1 | SL macro speed + 1 | TL macro speed + 1 | DT2 macro speed + 1 | RS macro speed + 1 | DT macro speed + 1 | D2R macro speed + 1 | SSG-EG macro speed + 1 | DAM macro speed + 1 | DVB macro speed + 1 | EGT macro speed + 1 | KSL macro speed + 1 | SUS macro speed + 1 | VIB macro speed + 1 | WS macro speed + 1 | KSR macro speed + 1 | AM macro delay + 1 | AR macro delay + 1 | DR macro delay + 1 | MULT macro delay + 1 | RR macro delay + 1 | SL macro delay + 1 | TL macro delay + 1 | DT2 macro delay + 1 | RS macro delay + 1 | DT macro delay + 1 | D2R macro delay + 1 | SSG-EG macro delay + 1 | DAM macro delay + 1 | DVB macro delay + 1 | EGT macro delay + 1 | KSL macro delay + 1 | SUS macro delay + 1 | VIB macro delay + 1 | WS macro delay + 1 | KSR macro delay ``` # wavetable diff --git a/src/engine/engine.h b/src/engine/engine.h index d379540c..363210ab 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev110" -#define DIV_ENGINE_VERSION 110 +#define DIV_VERSION "dev111" +#define DIV_ENGINE_VERSION 111 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index e64e02a0..32b98d2e 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2843,9 +2843,9 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // TODO: <= or std.volMacro.val[ins->std.volMacro.len]=lastVal; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } - if (ins->std.volMacro.len>=128) break; + if (ins->std.volMacro.len>=255) break; } else if (m.val[j]==0xe9 || m.val[j]==0xea) { // volume slide if (++j>=64) break; signed char slideStep=m.val[j]; @@ -2864,16 +2864,16 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { } } ins->std.volMacro.val[ins->std.volMacro.len]=lastVal; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } } else { // TODO: replace with upcoming macro speed for (int k=0; kstd.volMacro.val[ins->std.volMacro.len]=m.val[j]; lastVal=m.val[j]; - if (++ins->std.volMacro.len>=128) break; + if (++ins->std.volMacro.len>=255) break; } - if (ins->std.volMacro.len>=128) break; + if (ins->std.volMacro.len>=255) break; } } @@ -2902,7 +2902,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=wave-10; ins->std.waveMacro.open=true; lastVal=wave; - //if (++ins->std.arpMacro.len>=128) break; + //if (++ins->std.arpMacro.len>=255) break; } } else if (fm.val[j]==0xe0) { if (++j>=64) break; @@ -2932,8 +2932,8 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { ins->std.waveMacro.val[ins->std.waveMacro.len]=lastVal-10; } ins->std.arpMacro.open=true; - if (++ins->std.arpMacro.len>=128) break; - if (++ins->std.waveMacro.len>=128) break; + if (++ins->std.arpMacro.len>=255) break; + if (++ins->std.waveMacro.len>=255) break; } } } @@ -2946,7 +2946,7 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { // vibrato for (int j=0; j<=vibDelay; j++) { ins->std.pitchMacro.val[ins->std.pitchMacro.len]=0; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } int vibPos=0; ins->std.pitchMacro.loop=ins->std.pitchMacro.len; @@ -2954,19 +2954,19 @@ bool DivEngine::loadFC(unsigned char* file, size_t len) { vibPos+=vibSpeed; if (vibPos>vibDepth) vibPos=vibDepth; ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPosstd.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPos>-vibDepth); do { vibPos+=vibSpeed; if (vibPos>0) vibPos=0; ins->std.pitchMacro.val[ins->std.pitchMacro.len]=vibPos*32; - if (++ins->std.pitchMacro.len>=128) break; + if (++ins->std.pitchMacro.len>=255) break; } while (vibPos<0); ds.ins.push_back(ins); diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 9f1f5fff..b2203ebf 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -564,6 +564,96 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(snes.s); w->writeC(snes.r); + // macro speed/delay + w->writeC(std.volMacro.speed); + w->writeC(std.arpMacro.speed); + w->writeC(std.dutyMacro.speed); + w->writeC(std.waveMacro.speed); + w->writeC(std.pitchMacro.speed); + w->writeC(std.ex1Macro.speed); + w->writeC(std.ex2Macro.speed); + w->writeC(std.ex3Macro.speed); + w->writeC(std.algMacro.speed); + w->writeC(std.fbMacro.speed); + w->writeC(std.fmsMacro.speed); + w->writeC(std.amsMacro.speed); + w->writeC(std.panLMacro.speed); + w->writeC(std.panRMacro.speed); + w->writeC(std.phaseResetMacro.speed); + w->writeC(std.ex4Macro.speed); + w->writeC(std.ex5Macro.speed); + w->writeC(std.ex6Macro.speed); + w->writeC(std.ex7Macro.speed); + w->writeC(std.ex8Macro.speed); + + w->writeC(std.volMacro.delay); + w->writeC(std.arpMacro.delay); + w->writeC(std.dutyMacro.delay); + w->writeC(std.waveMacro.delay); + w->writeC(std.pitchMacro.delay); + w->writeC(std.ex1Macro.delay); + w->writeC(std.ex2Macro.delay); + w->writeC(std.ex3Macro.delay); + w->writeC(std.algMacro.delay); + w->writeC(std.fbMacro.delay); + w->writeC(std.fmsMacro.delay); + w->writeC(std.amsMacro.delay); + w->writeC(std.panLMacro.delay); + w->writeC(std.panRMacro.delay); + w->writeC(std.phaseResetMacro.delay); + w->writeC(std.ex4Macro.delay); + w->writeC(std.ex5Macro.delay); + w->writeC(std.ex6Macro.delay); + w->writeC(std.ex7Macro.delay); + w->writeC(std.ex8Macro.delay); + + // op macro speed/delay + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + w->writeC(op.amMacro.speed); + w->writeC(op.arMacro.speed); + w->writeC(op.drMacro.speed); + w->writeC(op.multMacro.speed); + w->writeC(op.rrMacro.speed); + w->writeC(op.slMacro.speed); + w->writeC(op.tlMacro.speed); + w->writeC(op.dt2Macro.speed); + w->writeC(op.rsMacro.speed); + w->writeC(op.dtMacro.speed); + w->writeC(op.d2rMacro.speed); + w->writeC(op.ssgMacro.speed); + w->writeC(op.damMacro.speed); + w->writeC(op.dvbMacro.speed); + w->writeC(op.egtMacro.speed); + w->writeC(op.kslMacro.speed); + w->writeC(op.susMacro.speed); + w->writeC(op.vibMacro.speed); + w->writeC(op.wsMacro.speed); + w->writeC(op.ksrMacro.speed); + + w->writeC(op.amMacro.delay); + w->writeC(op.arMacro.delay); + w->writeC(op.drMacro.delay); + w->writeC(op.multMacro.delay); + w->writeC(op.rrMacro.delay); + w->writeC(op.slMacro.delay); + w->writeC(op.tlMacro.delay); + w->writeC(op.dt2Macro.delay); + w->writeC(op.rsMacro.delay); + w->writeC(op.dtMacro.delay); + w->writeC(op.d2rMacro.delay); + w->writeC(op.ssgMacro.delay); + w->writeC(op.damMacro.delay); + w->writeC(op.dvbMacro.delay); + w->writeC(op.egtMacro.delay); + w->writeC(op.kslMacro.delay); + w->writeC(op.susMacro.delay); + w->writeC(op.vibMacro.delay); + w->writeC(op.wsMacro.delay); + w->writeC(op.ksrMacro.delay); + } + blockEndSeek=w->tell(); w->seek(blockStartSeek,SEEK_SET); w->writeI(blockEndSeek-blockStartSeek-4); @@ -960,15 +1050,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { // clear noise macro if PCE instrument and version<63 if (version<63 && type==DIV_INS_PCE) { std.dutyMacro.len=0; - std.dutyMacro.loop=-1; - std.dutyMacro.rel=-1; + std.dutyMacro.loop=255; + std.dutyMacro.rel=255; } // clear wave macro if OPLL instrument and version<70 if (version<70 && type==DIV_INS_OPLL) { std.waveMacro.len=0; - std.waveMacro.loop=-1; - std.waveMacro.rel=-1; + std.waveMacro.loop=255; + std.waveMacro.rel=255; } // sample map @@ -1160,6 +1250,98 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { snes.r=reader.readC(); } + // macro speed/delay + if (version>=111) { + std.volMacro.speed=reader.readC(); + std.arpMacro.speed=reader.readC(); + std.dutyMacro.speed=reader.readC(); + std.waveMacro.speed=reader.readC(); + std.pitchMacro.speed=reader.readC(); + std.ex1Macro.speed=reader.readC(); + std.ex2Macro.speed=reader.readC(); + std.ex3Macro.speed=reader.readC(); + std.algMacro.speed=reader.readC(); + std.fbMacro.speed=reader.readC(); + std.fmsMacro.speed=reader.readC(); + std.amsMacro.speed=reader.readC(); + std.panLMacro.speed=reader.readC(); + std.panRMacro.speed=reader.readC(); + std.phaseResetMacro.speed=reader.readC(); + std.ex4Macro.speed=reader.readC(); + std.ex5Macro.speed=reader.readC(); + std.ex6Macro.speed=reader.readC(); + std.ex7Macro.speed=reader.readC(); + std.ex8Macro.speed=reader.readC(); + + std.volMacro.delay=reader.readC(); + std.arpMacro.delay=reader.readC(); + std.dutyMacro.delay=reader.readC(); + std.waveMacro.delay=reader.readC(); + std.pitchMacro.delay=reader.readC(); + std.ex1Macro.delay=reader.readC(); + std.ex2Macro.delay=reader.readC(); + std.ex3Macro.delay=reader.readC(); + std.algMacro.delay=reader.readC(); + std.fbMacro.delay=reader.readC(); + std.fmsMacro.delay=reader.readC(); + std.amsMacro.delay=reader.readC(); + std.panLMacro.delay=reader.readC(); + std.panRMacro.delay=reader.readC(); + std.phaseResetMacro.delay=reader.readC(); + std.ex4Macro.delay=reader.readC(); + std.ex5Macro.delay=reader.readC(); + std.ex6Macro.delay=reader.readC(); + std.ex7Macro.delay=reader.readC(); + std.ex8Macro.delay=reader.readC(); + + // op macro speed/delay + for (int i=0; i<4; i++) { + DivInstrumentSTD::OpMacro& op=std.opMacros[i]; + + op.amMacro.speed=reader.readC(); + op.arMacro.speed=reader.readC(); + op.drMacro.speed=reader.readC(); + op.multMacro.speed=reader.readC(); + op.rrMacro.speed=reader.readC(); + op.slMacro.speed=reader.readC(); + op.tlMacro.speed=reader.readC(); + op.dt2Macro.speed=reader.readC(); + op.rsMacro.speed=reader.readC(); + op.dtMacro.speed=reader.readC(); + op.d2rMacro.speed=reader.readC(); + op.ssgMacro.speed=reader.readC(); + op.damMacro.speed=reader.readC(); + op.dvbMacro.speed=reader.readC(); + op.egtMacro.speed=reader.readC(); + op.kslMacro.speed=reader.readC(); + op.susMacro.speed=reader.readC(); + op.vibMacro.speed=reader.readC(); + op.wsMacro.speed=reader.readC(); + op.ksrMacro.speed=reader.readC(); + + op.amMacro.delay=reader.readC(); + op.arMacro.delay=reader.readC(); + op.drMacro.delay=reader.readC(); + op.multMacro.delay=reader.readC(); + op.rrMacro.delay=reader.readC(); + op.slMacro.delay=reader.readC(); + op.tlMacro.delay=reader.readC(); + op.dt2Macro.delay=reader.readC(); + op.rsMacro.delay=reader.readC(); + op.dtMacro.delay=reader.readC(); + op.d2rMacro.delay=reader.readC(); + op.ssgMacro.delay=reader.readC(); + op.damMacro.delay=reader.readC(); + op.dvbMacro.delay=reader.readC(); + op.egtMacro.delay=reader.readC(); + op.kslMacro.delay=reader.readC(); + op.susMacro.delay=reader.readC(); + op.vibMacro.delay=reader.readC(); + op.wsMacro.delay=reader.readC(); + op.ksrMacro.delay=reader.readC(); + } + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/instrument.h b/src/engine/instrument.h index da6d0841..e5372933 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -165,21 +165,20 @@ struct DivInstrumentMacro { int val[256]; unsigned int mode; bool open; - unsigned char len; - signed char loop; - signed char rel; + unsigned char len, delay, speed, loop, rel; // the following variables are used by the GUI and not saved in the file int vScroll, vZoom; - explicit DivInstrumentMacro(const String& n, bool initOpen=false): name(n), mode(0), open(initOpen), len(0), - loop(-1), - rel(-1), + delay(0), + speed(1), + loop(255), + rel(255), vScroll(0), vZoom(-1) { memset(val,0,256*sizeof(int)); diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 83ad906f..1566b943 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -43,15 +43,15 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic if (has) { lastPos=pos; val=source.val[pos++]; - if (source.rel>=0 && pos>source.rel && !released) { - if (source.loop=0 && source.loopsource.rel && !released) { + if (source.loop=source.len) { - if (source.loop=0 && (source.loop>=source.rel || source.rel>=source.len)) { + if (source.loop=source.rel || source.rel>=source.len)) { pos=source.loop; } else if (linger) { pos--; @@ -240,7 +240,7 @@ void DivMacroInt::init(DivInstrument* which) { for (size_t i=0; iprepare(*macroSource[i],e); - hasRelease=(macroSource[i]->rel>=0 && macroSource[i]->rellen); + hasRelease=(macroSource[i]->rellen); } else { hasRelease=false; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 9189618d..b5ccbd7b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -276,13 +276,13 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma } } -void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel) { +void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel) { int buf=0; bool negaBuf=false; bool hasVal=false; macroLen=0; - macroLoop=-1; - macroRel=-1; + macroLoop=255; + macroRel=255; for (char& i: source) { switch (i) { case '0': case '1': case '2': case '3': case '4': @@ -318,7 +318,7 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe macroLen++; buf=0; } - if (macroLoop==-1) { + if (macroLoop==255) { macroLoop=macroLen; } break; @@ -332,14 +332,14 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe macroLen++; buf=0; } - if (macroRel==-1) { + if (macroRel==255) { macroRel=macroLen; } break; } - if (macroLen>=128) break; + if (macroLen>=255) break; } - if (hasVal && macroLen<128) { + if (hasVal && macroLen<255) { hasVal=false; macro[macroLen]=negaBuf?-buf:buf; negaBuf=false; diff --git a/src/gui/gui.h b/src/gui/gui.h index 8a3548f2..f7b13b07 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1406,7 +1406,7 @@ class FurnaceGUI { ImVec2 macroLoopDragStart; ImVec2 macroLoopDragAreaSize; - signed char* macroLoopDragTarget; + unsigned char* macroLoopDragTarget; int macroLoopDragLen; bool macroLoopDragActive; @@ -1687,7 +1687,7 @@ class FurnaceGUI { void initSystemPresets(); void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false); - void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel); + void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel); void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex=false); String encodeKeyMap(std::map& map); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index dc239fcd..2a97744f 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1215,14 +1215,14 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } ImGui::TableNextColumn(); float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; - int totalFit=MIN(128,availableWidth/MAX(1,macroPointSize*dpiScale)); - if (macroDragScroll>128-totalFit) { - macroDragScroll=128-totalFit; + int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale)); + if (macroDragScroll>255-totalFit) { + macroDragScroll=255-totalFit; } ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; } // draw macros @@ -1239,8 +1239,11 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } if (i.macro->open) { ImGui::SetNextItemWidth(lenAvail); - if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&i.macro->len,&_ONE,&_THREE)) { MARK_MODIFIED - if (i.macro->len>128) i.macro->len=128; + int macroLen=i.macro->len; + if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED + if (macroLen<0) macroLen=0; + if (macroLen>255) macroLen=255; + i.macro->len=macroLen; } // do not change this! // anything other than a checkbox will look ugly! @@ -1267,7 +1270,7 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->looprel)) { loopIndicator[j]=0; } else { - loopIndicator[j]=((i.macro->loop!=-1 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=-1 && (j+macroDragScroll)==i.macro->rel)<<1); + loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1); } } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f)); @@ -1414,9 +1417,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) { - i.macro->rel=-1; + i.macro->rel=255; } else { - i.macro->loop=-1; + i.macro->loop=255; } } ImGui::SetNextItemWidth(availableWidth); @@ -1437,9 +1440,9 @@ void FurnaceGUI::drawMacros(std::vector& macros) { ImGui::TableNextColumn(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(availableWidth); - if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { + if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) { if (macroDragScroll<0) macroDragScroll=0; - if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; + if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit; } ImGui::EndTable(); } @@ -4311,8 +4314,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::Separator(); if (ImGui::MenuItem("clear")) { lastMacroDesc.macro->len=0; - lastMacroDesc.macro->loop=-1; - lastMacroDesc.macro->rel=-1; + lastMacroDesc.macro->loop=255; + lastMacroDesc.macro->rel=255; for (int i=0; i<256; i++) { lastMacroDesc.macro->val[i]=0; } @@ -4341,15 +4344,15 @@ void FurnaceGUI::drawInsEdit() { lastMacroDesc.macro->val[i]=val; } - if (lastMacroDesc.macro->loop>=0 && lastMacroDesc.macro->looplen) { + if (lastMacroDesc.macro->looplen) { lastMacroDesc.macro->loop+=macroOffX; } else { - lastMacroDesc.macro->loop=-1; + lastMacroDesc.macro->loop=255; } if ((lastMacroDesc.macro->rel+macroOffX)>=0 && (lastMacroDesc.macro->rel+macroOffX)len) { lastMacroDesc.macro->rel+=macroOffX; } else { - lastMacroDesc.macro->rel=-1; + lastMacroDesc.macro->rel=255; } ImGui::CloseCurrentPopup(); From 3b6fa212b849aa83f5222cf5768f2d6286b384eb Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 03:52:32 -0500 Subject: [PATCH 8/9] implement macro speed/delay --- src/engine/macroInt.cpp | 12 ++++++++++++ src/engine/macroInt.h | 10 +++++++--- src/gui/insEdit.cpp | 21 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 1566b943..36850818 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -32,6 +32,18 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic had=false; return; } + if (delay>0) { + delay--; + return; + } + if (began && source.delay>0) { + delay=source.delay; + } else { + delay=source.speed-1; + } + if (began) { + began=false; + } if (finished) { finished=false; } diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 8569dce4..ad761ba5 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -25,21 +25,24 @@ class DivEngine; struct DivMacroStruct { - int pos, lastPos; + int pos, lastPos, delay; int val; - bool has, had, actualHad, finished, will, linger; + bool has, had, actualHad, finished, will, linger, began; unsigned int mode; void doMacro(DivInstrumentMacro& source, bool released, bool tick); void init() { - pos=lastPos=mode=0; + pos=lastPos=mode=delay=0; has=had=actualHad=will=false; linger=false; + began=true; // TODO: test whether this breaks anything? val=0; } void prepare(DivInstrumentMacro& source, DivEngine* e); DivMacroStruct(): pos(0), + lastPos(0), + delay(0), val(0), has(false), had(false), @@ -47,6 +50,7 @@ struct DivMacroStruct { finished(false), will(false), linger(false), + began(false), mode(0) {} }; diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 2a97744f..f7e80c53 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1245,6 +1245,27 @@ void FurnaceGUI::drawMacros(std::vector& macros) { if (macroLen>255) macroLen=255; i.macro->len=macroLen; } + if (ImGui::Button(ICON_FA_BAR_CHART "##IMacroType")) { + + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Coming soon!"); + } + ImGui::SameLine(); + ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Delay/Step Length"); + } + if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { + if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { + if (i.macro->speed<1) i.macro->speed=1; + MARK_MODIFIED; + } + if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { + MARK_MODIFIED; + } + ImGui::EndPopup(); + } // do not change this! // anything other than a checkbox will look ugly! // if you really need more than two macro modes please tell me. From 6e87bc5dd6c5ad3255e0c2662c6eec640309c338 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 22 Aug 2022 04:38:46 -0500 Subject: [PATCH 9/9] update format.md --- papers/format.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/papers/format.md b/papers/format.md index 4d9c15a2..cfe159ed 100644 --- a/papers/format.md +++ b/papers/format.md @@ -972,9 +972,9 @@ size | description 4 | "WAVE" block ID 4 | size of this block STR | wavetable name - 4 | wavetable size - 4 | wavetable min - 4 | wavetable max + 4 | wavetable width + 4 | reserved + 4 | wavetable height 4?? | wavetable data ```