Made a dedicated read string function, messed a bit with the TFM

effects.

Added a compatibility flag that resets the effects after a row
change/new note
This commit is contained in:
techmetx11 2024-04-12 21:36:27 +00:00
parent 7a051b4486
commit 4bc4bfac32
No known key found for this signature in database
GPG key ID: 20E0C88A0E7E5AF2
4 changed files with 60 additions and 17 deletions

View file

@ -104,7 +104,7 @@ struct DivChannelState {
int delayOrder, delayRow, retrigSpeed, retrigTick; int delayOrder, delayRow, retrigSpeed, retrigTick;
int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine; int vibratoDepth, vibratoRate, vibratoPos, vibratoPosGiant, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos; int tremoloDepth, tremoloRate, tremoloPos;
unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType; unsigned char arp, arpStage, arpTicks, panL, panR, panRL, panRR, lastVibrato, lastPorta, cutType, lastArp, lastVibrato2, lastPorta2;
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing; bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff, releasing;
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp; bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, wasShorthandPorta, noteOnInhibit, resetArp;
bool wentThroughNote, goneThroughNote; bool wentThroughNote, goneThroughNote;
@ -150,6 +150,9 @@ struct DivChannelState {
lastVibrato(0), lastVibrato(0),
lastPorta(0), lastPorta(0),
cutType(0), cutType(0),
lastArp(0),
lastVibrato2(0),
lastPorta2(0),
doNote(false), doNote(false),
legato(false), legato(false),
portaStop(false), portaStop(false),

View file

@ -134,6 +134,14 @@ public:
return ret; return ret;
} }
String readString(size_t l) {
String ret;
ret.reserve(l);
while (l--) {
ret += readC();
}
return ret;
}
void skip(size_t l) { void skip(size_t l) {
// quick and dirty // quick and dirty
while (l--) { while (l--) {
@ -157,12 +165,13 @@ bool DivEngine::loadTFM(unsigned char* file, size_t len) {
DivSong ds; DivSong ds;
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.system[0]=DIV_SYSTEM_YM2612; ds.system[0]=DIV_SYSTEM_YM2612;
unsigned char magic[8]={0}; unsigned char magic[8]={0};
reader.readNoRLE(magic, 8); reader.readNoRLE(magic,8);
if (memcmp(magic,DIV_TFM_MAGIC,8)!=0) throw InvalidHeaderException(); if (memcmp(magic,DIV_TFM_MAGIC,8)!=0) throw InvalidHeaderException();
unsigned char speedEven=reader.readCNoRLE(); unsigned char speedEven=reader.readCNoRLE();
@ -197,24 +206,17 @@ bool DivEngine::loadTFM(unsigned char* file, size_t len) {
// TODO: use this for something, number of saves // TODO: use this for something, number of saves
(void)reader.readSNoRLE(); (void)reader.readSNoRLE();
unsigned char buffer[384];
// author // author
logD("parsing author"); logD("parsing author");
reader.read(buffer,64); ds.author=reader.readString(64);
ds.author=String((const char*)buffer,strnlen((const char*)buffer,64));
memset(buffer, 0, 64);
// name // name
logD("parsing name"); logD("parsing name");
reader.read(buffer,64); ds.name=reader.readString(64);
ds.name=String((const char*)buffer,strnlen((const char*)buffer,64));
memset(buffer, 0, 64);
// notes // notes
logD("parsing notes"); logD("parsing notes");
reader.read(buffer,384); String notes=reader.readString(384);
String notes((const char*)buffer,strnlen((const char*)buffer,384));
// fix \r\n to \n // fix \r\n to \n
for (auto& c : notes) { for (auto& c : notes) {
@ -398,9 +400,12 @@ bool DivEngine::loadTFM(unsigned char* file, size_t len) {
pat->data[k][5]=effectVal[k]; pat->data[k][5]=effectVal[k];
break; break;
case 1: case 1:
// pitch slide up // note slide up
case 2: case 2:
// pitch slide down // note slide down
pat->data[k][4]=0xF0|effectNum[k];
pat->data[k][5]=effectVal[k];
break;
case 3: case 3:
// portamento // portamento
case 4: case 4:

View file

@ -740,6 +740,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
break; break;
case 0x03: // portamento case 0x03: // portamento
chan[i].lastPorta2=effectVal;
if (effectVal==0) { if (effectVal==0) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;
@ -768,6 +769,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
break; break;
case 0x04: // vibrato case 0x04: // vibrato
chan[i].lastVibrato2=effectVal;
if (effectVal) chan[i].lastVibrato=effectVal; if (effectVal) chan[i].lastVibrato=effectVal;
chan[i].vibratoDepth=effectVal&15; chan[i].vibratoDepth=effectVal&15;
chan[i].vibratoRate=effectVal>>4; chan[i].vibratoRate=effectVal>>4;
@ -775,6 +777,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
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)));
break; break;
case 0x05: // vol slide + vibrato case 0x05: // vol slide + vibrato
chan[i].lastVibrato2=effectVal;
if (effectVal==0) { if (effectVal==0) {
chan[i].vibratoDepth=0; chan[i].vibratoDepth=0;
chan[i].vibratoRate=0; chan[i].vibratoRate=0;
@ -782,6 +785,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
chan[i].vibratoDepth=chan[i].lastVibrato&15; chan[i].vibratoDepth=chan[i].lastVibrato&15;
chan[i].vibratoRate=chan[i].lastVibrato>>4; chan[i].vibratoRate=chan[i].lastVibrato>>4;
} }
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));
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)));
// TODO: non-0x-or-x0 value should be treated as 00 // TODO: non-0x-or-x0 value should be treated as 00
@ -800,6 +804,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed));
break; break;
case 0x06: // vol slide + porta case 0x06: // vol slide + porta
chan[i].lastPorta2=effectVal;
if (effectVal==0 || chan[i].lastPorta==0) { if (effectVal==0 || chan[i].lastPorta==0) {
chan[i].portaNote=-1; chan[i].portaNote=-1;
chan[i].portaSpeed=-1; chan[i].portaSpeed=-1;
@ -870,6 +875,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed)); dispatchCmd(DivCommand(DIV_CMD_HINT_VOL_SLIDE,i,chan[i].volSpeed));
break; break;
case 0x00: // arpeggio case 0x00: // arpeggio
chan[i].lastArp=effectVal;
chan[i].arp=effectVal; chan[i].arp=effectVal;
if (chan[i].arp==0 && song.arp0Reset) { if (chan[i].arp==0 && song.arp0Reset) {
chan[i].resetArp=true; chan[i].resetArp=true;
@ -1110,6 +1116,33 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
} }
if (song.resetEffectsOnNewNote) {
if (chan[i].lastArp) {
chan[i].lastArp=0;
} else {
chan[i].arp=0;
dispatchCmd(DivCommand(DIV_CMD_HINT_ARPEGGIO,i,chan[i].arp));
}
if (chan[i].lastVibrato2) {
chan[i].lastVibrato2=0;
} else {
chan[i].vibratoDepth=0;
chan[i].vibratoRate=0;
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) { if (panChanged) {
dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR)); dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR));
} }
@ -1146,7 +1179,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8)); dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,chan[i].note,chan[i].volume>>8));
chan[i].releasing=false; chan[i].releasing=false;
if (song.resetArpPhaseOnNewNote) { if (song.resetArpPhaseOnNewNote) {
chan[i].arpStage=-1; chan[i].arpStage=-1;
} }
chan[i].goneThroughNote=true; chan[i].goneThroughNote=true;
chan[i].wentThroughNote=true; chan[i].wentThroughNote=true;

View file

@ -331,6 +331,7 @@ struct DivSong {
bool resetArpPhaseOnNewNote; bool resetArpPhaseOnNewNote;
bool ceilVolumeScaling; bool ceilVolumeScaling;
bool oldAlwaysSetVolume; bool oldAlwaysSetVolume;
bool resetEffectsOnNewNote;
std::vector<DivInstrument*> ins; std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave; std::vector<DivWavetable*> wave;
@ -454,7 +455,8 @@ struct DivSong {
oldDPCM(false), oldDPCM(false),
resetArpPhaseOnNewNote(false), resetArpPhaseOnNewNote(false),
ceilVolumeScaling(false), ceilVolumeScaling(false),
oldAlwaysSetVolume(false) { oldAlwaysSetVolume(false),
resetEffectsOnNewNote(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;