From 8bc0781f5977db6db3ad4d48ca91f7a8cd8ac42b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 30 Apr 2023 13:46:09 -0500 Subject: [PATCH] implement 05xy/06xy issue #1044 --- src/engine/engine.cpp | 4 +++ src/engine/engine.h | 4 ++- src/engine/playback.cpp | 72 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 12fe249f..0eb603b7 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -55,6 +55,10 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul return "03xx: Portamento"; case 0x04: return "04xy: Vibrato (x: speed; y: depth)"; + case 0x05: + return "05xy: Volume slide + vibrato (compatibility only!)"; + case 0x06: + return "06xy: Volume slide + portamento (compatibility only!)"; case 0x07: return "07xy: Tremolo (x: speed; y: depth)"; case 0x08: diff --git a/src/engine/engine.h b/src/engine/engine.h index d31de903..7705b259 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -105,7 +105,7 @@ struct DivChannelState { int delayOrder, delayRow, retrigSpeed, retrigTick; int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine; int tremoloDepth, tremoloRate, tremoloPos; - unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR; + unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp; bool wentThroughNote, goneThroughNote; @@ -146,6 +146,8 @@ struct DivChannelState { panR(255), panRL(0), panRR(0), + lastVibrato(0), + lastPorta(0), doNote(false), legato(false), portaStop(false), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fbbd1302..8cc2f825 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -680,6 +680,7 @@ void DivEngine::processRow(int i, bool afterDelay) { chan[i].inPorta=false; dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); } else { + chan[i].lastPorta=effectVal; calledPorta=true; if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) { chan[i].portaNote=chan[i].note; @@ -700,11 +701,78 @@ void DivEngine::processRow(int i, bool afterDelay) { } break; case 0x04: // vibrato + if (effectVal) chan[i].lastVibrato=effectVal; chan[i].vibratoDepth=effectVal&15; chan[i].vibratoRate=effectVal>>4; dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); break; + case 0x05: // vol slide + vibrato + if (effectVal==0) { + chan[i].vibratoDepth=0; + chan[i].vibratoRate=0; + } else { + chan[i].vibratoDepth=chan[i].lastVibrato&15; + chan[i].vibratoRate=chan[i].lastVibrato>>4; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); + dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); + // TODO: non-0x-or-x0 value should be treated as 00 + if (effectVal!=0) { + if ((effectVal&15)!=0) { + chan[i].volSpeed=-(effectVal&15)*64; + } else { + chan[i].volSpeed=(effectVal>>4)*64; + } + // tremolo and vol slides are incompatible + chan[i].tremoloDepth=0; + chan[i].tremoloRate=0; + } else { + chan[i].volSpeed=0; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); + break; + case 0x06: // vol slide + porta + if (effectVal==0 || chan[i].lastPorta==0) { + chan[i].portaNote=-1; + chan[i].portaSpeed=-1; + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0))); + chan[i].inPorta=false; + dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0)); + } else { + calledPorta=true; + if (chan[i].note==chan[i].oldNote && !chan[i].inPorta && song.buggyPortaAfterSlide) { + chan[i].portaNote=chan[i].note; + chan[i].portaSpeed=-1; + } else { + chan[i].portaNote=chan[i].note; + chan[i].portaSpeed=chan[i].lastPorta; + chan[i].inPorta=true; + chan[i].wasShorthandPorta=false; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0))); + chan[i].portaStop=true; + if (chan[i].keyOn) chan[i].doNote=false; + chan[i].stopOnOff=song.stopPortaOnNoteOff; // what?! + chan[i].scheduledSlideReset=false; + dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,true,1)); + lastSlide=0x1337; // i hate this so much + } + // TODO: non-0x-or-x0 value should be treated as 00 + if (effectVal!=0) { + if ((effectVal&15)!=0) { + chan[i].volSpeed=-(effectVal&15)*64; + } else { + chan[i].volSpeed=(effectVal>>4)*64; + } + // tremolo and vol slides are incompatible + chan[i].tremoloDepth=0; + chan[i].tremoloRate=0; + } else { + chan[i].volSpeed=0; + } + dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); + break; case 0x07: // tremolo // TODO // this effect is really weird. i thought it would alter the tremolo depth but turns out it's completely different @@ -1148,6 +1216,10 @@ void DivEngine::nextRow() { doPrepareCut=false; break; } + if (pat->data[curRow][4+(j<<1)]==0x06) { + doPrepareCut=false; + break; + } if (pat->data[curRow][4+(j<<1)]==0xea) { if (pat->data[curRow][5+(j<<1)]>0) { doPrepareCut=false;