fix retrigger implementation

no longer broken
This commit is contained in:
tildearrow 2022-01-19 00:01:34 -05:00
parent 1642f29df8
commit e87239f8ce
19 changed files with 105 additions and 54 deletions

View file

@ -6,6 +6,8 @@
#define ONE_SEMITONE 2200 #define ONE_SEMITONE 2200
#define DIV_NOTE_NULL 0x7fffffff
#define addWrite(a,v) regWrites.push_back(DivRegWrite(a,v)); #define addWrite(a,v) regWrites.push_back(DivRegWrite(a,v));
enum DivDispatchCmds { enum DivDispatchCmds {

View file

@ -34,7 +34,7 @@ struct DivChannelState {
std::vector<DivDelayedCommand> delayed; std::vector<DivDelayedCommand> delayed;
int note, oldNote, pitch, portaSpeed, portaNote; int note, oldNote, pitch, portaSpeed, portaNote;
int volume, volSpeed, cut, rowDelay, volMax; int volume, volSpeed, cut, rowDelay, volMax;
int delayOrder, delayRow; int delayOrder, delayRow, retrigSpeed, retrigTick;
int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine; int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine;
int tremoloDepth, tremoloRate, tremoloPos; int tremoloDepth, tremoloRate, tremoloPos;
unsigned char arp, arpStage, arpTicks; unsigned char arp, arpStage, arpTicks;
@ -53,6 +53,8 @@ struct DivChannelState {
volMax(0), volMax(0),
delayOrder(0), delayOrder(0),
delayRow(0), delayRow(0),
retrigSpeed(0),
retrigTick(0),
vibratoDepth(0), vibratoDepth(0),
vibratoRate(0), vibratoRate(0),
vibratoPos(0), vibratoPos(0),

View file

@ -95,15 +95,19 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
}
chan[c.chan].sample=ins->amiga.initSample; chan[c.chan].sample=ins->amiga.initSample;
if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
chan[c.chan].sample=-1; chan[c.chan].sample=-1;
} }
chan[c.chan].audPos=0; chan[c.chan].audPos=0;
chan[c.chan].audSub=0; chan[c.chan].audSub=0;
chan[c.chan].freqChanged=true; if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);

View file

@ -249,8 +249,10 @@ int DivPlatformArcade::dispatch(DivCommand c) {
} }
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
chan[c.chan].baseFreq=c.value<<6; if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=c.value<<6;
chan[c.chan].freqChanged=true;
}
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].active=true; chan[c.chan].active=true;
break; break;

View file

@ -126,9 +126,11 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);

View file

@ -152,9 +152,11 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);

View file

@ -103,9 +103,11 @@ int DivPlatformC64::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(FREQ_BASE*pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(FREQ_BASE*pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacroLen>0) { if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacroLen>0) {

View file

@ -34,8 +34,10 @@ void DivPlatformDummy::tick() {
int DivPlatformDummy::dispatch(DivCommand c) { int DivPlatformDummy::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: case DIV_CMD_NOTE_ON:
chan[c.chan].baseFreq=65.6f*pow(2.0f,((float)c.value/12.0f)); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=65.6f*pow(2.0f,((float)c.value/12.0f));
chan[c.chan].freqChanged=true;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].amp=64; chan[c.chan].amp=64;
break; break;

View file

@ -176,13 +176,15 @@ void DivPlatformGB::muteChannel(int ch, bool mute) {
int DivPlatformGB::dispatch(DivCommand c) { int DivPlatformGB::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: case DIV_CMD_NOTE_ON:
if (c.chan==3) { // noise if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=c.value; if (c.chan==3) { // noise
} else { chan[c.chan].baseFreq=c.value;
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); } else {
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
}
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
} }
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));

View file

@ -209,8 +209,10 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
} }
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f));
chan[c.chan].freqChanged=true;
}
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].active=true; chan[c.chan].active=true;
break; break;

View file

@ -45,8 +45,10 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
} }
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
opChan[ch].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f)); if (c.value!=DIV_NOTE_NULL) {
opChan[ch].freqChanged=true; opChan[ch].baseFreq=644.0f*pow(2.0f,((float)c.value/12.0f));
opChan[ch].freqChanged=true;
}
opChan[ch].keyOn=true; opChan[ch].keyOn=true;
opChan[ch].active=true; opChan[ch].active=true;
break; break;

View file

@ -170,12 +170,18 @@ int DivPlatformNES::dispatch(DivCommand c) {
dacRate=parent->song.sample[dacSample]->rate; dacRate=parent->song.sample[dacSample]->rate;
break; break;
} else if (c.chan==3) { // noise } else if (c.chan==3) { // noise
chan[c.chan].baseFreq=c.value; if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=c.value;
}
} else { } else {
chan[c.chan].baseFreq=round(freqBase/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=round(freqBase/pow(2.0f,((float)c.value/12.0f)));
}
}
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
} }
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));

View file

@ -159,10 +159,12 @@ int DivPlatformPCE::dispatch(DivCommand c) {
chan[c.chan].dacRate=1789773/parent->song.sample[chan[c.chan].dacSample]->rate; chan[c.chan].dacRate=1789773/parent->song.sample[chan[c.chan].dacSample]->rate;
break; break;
} }
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chWrite(c.chan,0x07,chan[c.chan].noise?(0x80|noiseFreq[chan[c.chan].note%12]):0); chan[c.chan].note=c.value;
chWrite(c.chan,0x07,chan[c.chan].noise?(0x80|noiseFreq[chan[c.chan].note%12]):0);
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chWrite(c.chan,0x04,0x80|chan[c.chan].vol); chWrite(c.chan,0x04,0x80|chan[c.chan].vol);

View file

@ -123,9 +123,11 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);

View file

@ -90,9 +90,11 @@ void DivPlatformSMS::tick() {
int DivPlatformSMS::dispatch(DivCommand c) { int DivPlatformSMS::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: case DIV_CMD_NOTE_ON:
chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));

View file

@ -109,9 +109,11 @@ int DivPlatformTIA::dispatch(DivCommand c) {
switch (c.cmd) { switch (c.cmd) {
case DIV_CMD_NOTE_ON: { case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
chan[c.chan].baseFreq=c.value<<8; if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=c.value<<8;
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
rWrite(0x15+c.chan,chan[c.chan].shape); rWrite(0x15+c.chan,chan[c.chan].shape);

View file

@ -223,9 +223,11 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
DivInstrument* ins=parent->getIns(chan[c.chan].ins); DivInstrument* ins=parent->getIns(chan[c.chan].ins);
if (c.chan>3) { // PSG if (c.chan>3) { // PSG
chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f))); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=round(PSG_FREQ_BASE/pow(2.0f,((float)c.value/12.0f)));
chan[c.chan].note=c.value; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true; chan[c.chan].active=true;
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].std.init(ins); chan[c.chan].std.init(ins);
@ -264,8 +266,10 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
} }
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].freqChanged=true; chan[c.chan].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f));
chan[c.chan].freqChanged=true;
}
chan[c.chan].keyOn=true; chan[c.chan].keyOn=true;
chan[c.chan].active=true; chan[c.chan].active=true;
break; break;

View file

@ -45,8 +45,10 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
} }
opChan[ch].insChanged=false; opChan[ch].insChanged=false;
opChan[ch].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f)); if (c.value!=DIV_NOTE_NULL) {
opChan[ch].freqChanged=true; opChan[ch].baseFreq=FM_FREQ_BASE*pow(2.0f,((float)c.value/12.0f));
opChan[ch].freqChanged=true;
}
opChan[ch].keyOn=true; opChan[ch].keyOn=true;
opChan[ch].active=true; opChan[ch].active=true;
break; break;

View file

@ -468,6 +468,8 @@ void DivEngine::processRow(int i, bool afterDelay) {
} }
} }
chan[i].retrigSpeed=0;
// effects // effects
for (int j=0; j<song.pat[i].effectRows; j++) { for (int j=0; j<song.pat[i].effectRows; j++) {
short effect=pat->data[whatRow][4+(j<<1)]; short effect=pat->data[whatRow][4+(j<<1)];
@ -566,9 +568,8 @@ void DivEngine::processRow(int i, bool afterDelay) {
break; break;
case 0x0c: // retrigger case 0x0c: // retrigger
if (effectVal!=0) { if (effectVal!=0) {
chan[i].rowDelay=effectVal; // this was +1 before. what happened?! chan[i].retrigSpeed=effectVal;
chan[i].delayOrder=whatOrder; chan[i].retrigTick=0;
chan[i].delayRow=whatRow;
} }
break; break;
case 0xc0: case 0xc1: case 0xc2: case 0xc3: // set Hz case 0xc0: case 0xc1: case 0xc2: case 0xc3: // set Hz
@ -797,6 +798,12 @@ bool DivEngine::nextTick(bool noAccum) {
processRow(i,true); processRow(i,true);
} }
} }
if (chan[i].retrigSpeed) {
if (--chan[i].retrigTick<0) {
chan[i].retrigTick=chan[i].retrigSpeed-1;
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL));
}
}
if (chan[i].volSpeed!=0) { if (chan[i].volSpeed!=0) {
chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8); chan[i].volume=(chan[i].volume&0xff)|(dispatchCmd(DivCommand(DIV_CMD_GET_VOLUME,i))<<8);
chan[i].volume+=chan[i].volSpeed; chan[i].volume+=chan[i].volSpeed;