Replicated TFM's single-row pitch slide

This commit is contained in:
techmetx11 2024-04-13 17:45:12 +00:00
parent d6fd63f813
commit 50f1cf163a
No known key found for this signature in database
GPG key ID: 20E0C88A0E7E5AF2
4 changed files with 46 additions and 31 deletions

View file

@ -246,6 +246,7 @@ void TFMparsePattern(struct TFMparsePatternInfo info) {
info.reader->read(effectNum,256); info.reader->read(effectNum,256);
info.reader->read(effectVal,256); info.reader->read(effectVal,256);
unsigned short lastSlide=0;
for (int k=0; k<256; k++) { for (int k=0; k<256; k++) {
switch (effectNum[k]) { switch (effectNum[k]) {
case 0: case 0:
@ -258,6 +259,14 @@ void TFMparsePattern(struct TFMparsePatternInfo info) {
// pitch slide up // pitch slide up
case 2: case 2:
// pitch slide down // pitch slide down
pat->data[k][4]=effectNum[k];
if (effectVal[k]) {
lastSlide=effectVal[k];
pat->data[k][5]=effectVal[k];
} else {
pat->data[k][5]=lastSlide;
}
break;
case 3: case 3:
// portamento // portamento
case 4: case 4:
@ -297,7 +306,7 @@ bool DivEngine::loadTFMv1(unsigned char* file, size_t len) {
ds.systemName="Sega Genesis/Mega Drive or TurboSound FM"; ds.systemName="Sega Genesis/Mega Drive or TurboSound FM";
ds.subsong[0]->hz=50; ds.subsong[0]->hz=50;
ds.systemLen=1; ds.systemLen=1;
ds.resetEffectsOnNewNote=true; ds.resetEffectsOnRowChange=true;
ds.system[0]=DIV_SYSTEM_YM2612; ds.system[0]=DIV_SYSTEM_YM2612;
@ -483,7 +492,7 @@ bool DivEngine::loadTFMv2(unsigned char* file, size_t len) {
ds.systemName="Sega Genesis/Mega Drive or TurboSound FM"; ds.systemName="Sega Genesis/Mega Drive or TurboSound FM";
ds.subsong[0]->hz=50; ds.subsong[0]->hz=50;
ds.systemLen=1; ds.systemLen=1;
ds.resetEffectsOnNewNote=true; ds.resetEffectsOnRowChange=true;
ds.system[0]=DIV_SYSTEM_YM2612; ds.system[0]=DIV_SYSTEM_YM2612;
unsigned char magic[8]={0}; unsigned char magic[8]={0};

View file

@ -653,6 +653,14 @@ void DivEngine::processRow(int i, bool afterDelay) {
bool surroundPanChanged=false; bool surroundPanChanged=false;
// effects // effects
if (song.resetEffectsOnRowChange) {
chan[i].portaSpeed=-1;
chan[i].portaNote=-1;
dispatchCmd(DivCommand(DIV_CMD_HINT_PORTA,i,CLAMP(chan[i].portaNote,-128,127),MAX(chan[i].portaSpeed,0)));
chan[i].inPorta=false;
if (!song.arpNonPorta) dispatchCmd(DivCommand(DIV_CMD_PRE_PORTA,i,false,0));
}
for (int j=0; j<curPat[i].effectCols; j++) { for (int j=0; j<curPat[i].effectCols; j++) {
short effect=pat->data[whatRow][4+(j<<1)]; short effect=pat->data[whatRow][4+(j<<1)];
short effectVal=pat->data[whatRow][5+(j<<1)]; short effectVal=pat->data[whatRow][5+(j<<1)];
@ -697,6 +705,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
break; break;
case 0x01: // ramp up case 0x01: // ramp up
if (song.ignoreDuplicateSlides && (lastSlide==0x01 || lastSlide==0x1337)) break; if (song.ignoreDuplicateSlides && (lastSlide==0x01 || lastSlide==0x1337)) break;
chan[i].lastPorta2=effectVal;
lastSlide=0x01; lastSlide=0x01;
if (effectVal==0) { if (effectVal==0) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
@ -719,6 +728,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
break; break;
case 0x02: // ramp down case 0x02: // ramp down
if (song.ignoreDuplicateSlides && (lastSlide==0x02 || lastSlide==0x1337)) break; if (song.ignoreDuplicateSlides && (lastSlide==0x02 || lastSlide==0x1337)) break;
chan[i].lastPorta2=effectVal;
lastSlide=0x02; lastSlide=0x02;
if (effectVal==0) { if (effectVal==0) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
@ -1116,7 +1126,19 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
} }
if (song.resetEffectsOnNewNote) { if (panChanged) {
dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR));
}
if (surroundPanChanged) {
dispatchCmd(DivCommand(DIV_CMD_SURROUND_PANNING,i,2,chan[i].panRL));
dispatchCmd(DivCommand(DIV_CMD_SURROUND_PANNING,i,3,chan[i].panRR));
}
if (insChanged && (chan[i].inPorta || calledPorta) && song.newInsTriggersInPorta) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL));
}
if (song.resetEffectsOnRowChange) {
if (chan[i].lastArp) { if (chan[i].lastArp) {
chan[i].lastArp=0; chan[i].lastArp=0;
} else { } else {
@ -1131,34 +1153,13 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].vibratoRate=0; chan[i].vibratoRate=0;
dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate)); dispatchCmd(DivCommand(DIV_CMD_HINT_VIBRATO,i,chan[i].vibratoDepth,chan[i].vibratoRate));
} }
if (chan[i].lastPorta2) {
chan[i].lastPorta2=0;
} else {
chan[i].portaSpeed=-1;
chan[i].portaNote=-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));
}
}
if (panChanged) {
dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR));
}
if (surroundPanChanged) {
dispatchCmd(DivCommand(DIV_CMD_SURROUND_PANNING,i,2,chan[i].panRL));
dispatchCmd(DivCommand(DIV_CMD_SURROUND_PANNING,i,3,chan[i].panRR));
}
if (insChanged && (chan[i].inPorta || calledPorta) && song.newInsTriggersInPorta) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL));
} }
if (chan[i].doNote) { if (chan[i].doNote) {
if (!song.continuousVibrato) { if (!song.continuousVibrato) {
chan[i].vibratoPos=0; chan[i].vibratoPos=0;
} }
dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15))); dispatchCmd(DivCommand(DIV_CMD_PITCH,i,chan[i].pitch+(((chan[i].vibratoDepth*vibTable[chan[i].vibratoPos]*chan[i].vibratoFine)>>4)/15)));
if (chan[i].legato && (!chan[i].inPorta || song.brokenPortaLegato)) { if (chan[i].legato && (!chan[i].inPorta || song.brokenPortaLegato)) {
dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note)); dispatchCmd(DivCommand(DIV_CMD_LEGATO,i,chan[i].note));
@ -1187,6 +1188,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
} }
chan[i].doNote=false; chan[i].doNote=false;
if (!chan[i].keyOn && chan[i].scheduledSlideReset) { if (!chan[i].keyOn && chan[i].scheduledSlideReset) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;

View file

@ -331,7 +331,7 @@ struct DivSong {
bool resetArpPhaseOnNewNote; bool resetArpPhaseOnNewNote;
bool ceilVolumeScaling; bool ceilVolumeScaling;
bool oldAlwaysSetVolume; bool oldAlwaysSetVolume;
bool resetEffectsOnNewNote; bool resetEffectsOnRowChange;
std::vector<DivInstrument*> ins; std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave; std::vector<DivWavetable*> wave;
@ -456,7 +456,7 @@ struct DivSong {
resetArpPhaseOnNewNote(false), resetArpPhaseOnNewNote(false),
ceilVolumeScaling(false), ceilVolumeScaling(false),
oldAlwaysSetVolume(false), oldAlwaysSetVolume(false),
resetEffectsOnNewNote(false) { resetEffectsOnRowChange(false) {
for (int i=0; i<DIV_MAX_CHIPS; i++) { for (int i=0; i<DIV_MAX_CHIPS; i++) {
system[i]=DIV_SYSTEM_NULL; system[i]=DIV_SYSTEM_NULL;
systemVol[i]=1.0; systemVol[i]=1.0;

View file

@ -344,6 +344,10 @@ void FurnaceGUI::drawCompatFlags() {
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, volume macros round up when applied\nthis prevents volume scaling from causing vol=0, which is silent on some chips\n\nineffective on logarithmic channels"); ImGui::SetTooltip("when enabled, volume macros round up when applied\nthis prevents volume scaling from causing vol=0, which is silent on some chips\n\nineffective on logarithmic channels");
} }
ImGui::Checkbox("Reset effects on row change",&e->song.resetEffectsOnRowChange);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, effects in a row will be canceled after the row changes");
}
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
ImGui::EndTabBar(); ImGui::EndTabBar();