ES5506: fix NOTE_ON and NOTE_PORTA in same tick

issue #2690
let's hope this doesn't break anything else
This commit is contained in:
tildearrow 2026-01-13 02:13:58 -05:00
parent 68a0203cba
commit 9008fb46cc
2 changed files with 122 additions and 116 deletions

View file

@ -338,6 +338,125 @@ void DivPlatformES5506::updateNoteChangesAsNeeded(int ch) {
}
}
void DivPlatformES5506::updatePCMChanges(int i) {
if (chan[i].pcmChanged.changed) {
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_ES5506);
if (chan[i].pcmChanged.index) {
const int next=chan[i].pcm.next;
bool sampleValid=false;
if (((ins->amiga.useNoteMap) && (next>=0 && next<120)) ||
((!ins->amiga.useNoteMap) && (next>=0 && next<parent->song.sampleLen))) {
DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next];
int sample=next;
if (ins->amiga.useNoteMap) {
sample=noteMapind.map;
}
if (sample>=0 && sample<parent->song.sampleLen) {
const unsigned int offES5506=sampleOffES5506[sample];
sampleValid=true;
chan[i].pcm.index=sample;
chan[i].pcm.isNoteMap=ins->amiga.useNoteMap;
DivSample* s=parent->getSample(sample);
// get frequency offset
double off=1.0;
double center=(double)s->centerRate;
if (center<1) {
off=1.0;
} else {
off=(double)center/parent->getCenterRate();
}
if (ins->amiga.useNoteMap) {
//chan[i].pcm.note=next;
}
// get loop mode
DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX;
const unsigned int start=offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const unsigned int nextBank=(offES5506>>22)&3;
const double nextFreqOffs=((amigaPitch && !parent->song.compatFlags.linearPitch)?16:PITCH_OFFSET)*off;
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcm.start=start;
chan[i].pcm.end=end;
chan[i].pcm.length=length;
if ((chan[i].pcm.loopMode!=loopMode) || (chan[i].pcm.bank!=nextBank)) {
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcmChanged.loopBank=1;
}
if (chan[i].pcm.nextFreqOffs!=nextFreqOffs) {
chan[i].pcm.nextFreqOffs=nextFreqOffs;
chan[i].noteChanged.offs=1;
}
}
}
if (sampleValid) {
if (!chan[i].keyOn) {
pageWrite(0x20|i,0x03,(chan[i].pcm.direction)?chan[i].pcm.end:chan[i].pcm.start);
}
chan[i].pcmChanged.slice=1;
}
chan[i].pcmChanged.index=0;
}
if (chan[i].pcmChanged.slice) {
if (!chan[i].keyOn) {
if (chan[i].pcm.index>=0 && chan[i].pcm.index<parent->song.sampleLen) {
// get loop mode
DivSample* s=parent->getSample(chan[i].pcm.index);
const unsigned int start=sampleOffES5506[chan[i].pcm.index]<<10;
const unsigned int nextLoopStart=(start+(s->loopStart<<11))&0xfffff800;
const unsigned int nextLoopEnd=(start+((s->loopEnd)<<11))&0xffffff80;
if ((chan[i].pcm.loopStart!=nextLoopStart) || (chan[i].pcm.loopEnd!=nextLoopEnd)) {
chan[i].pcm.loopStart=nextLoopStart;
chan[i].pcm.loopEnd=nextLoopEnd;
chan[i].pcmChanged.position=1;
}
}
}
chan[i].pcmChanged.slice=0;
}
if (chan[i].pcmChanged.position) {
if (!chan[i].keyOn) {
pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart);
pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd);
}
chan[i].pcmChanged.position=0;
}
if (chan[i].pcmChanged.loopBank) {
if (!chan[i].keyOn) {
unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.direction?0x0040:0x0000);
chan[i].isReverseLoop=false;
switch (chan[i].pcm.loopMode) {
case DIV_SAMPLE_LOOP_FORWARD: // Forward loop
loopFlag|=0x0008;
break;
/*
case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable
loopFlag|=0x0038;
chan[i].isReverseLoop=true;
break;
*/
case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support
loopFlag|=0x0018;
break;
case DIV_SAMPLE_LOOP_MAX: // no loop
default:
break;
}
// Set loop mode & Bank
chan[i].crDirVal=(chan[i].crDirVal&~0x0040)|(chan[i].pcm.direction?0x0040:0x0000);
chan[i].crWriteVal=(chan[i].crWriteVal&~0x41)|chan[i].crDirVal;
chan[i].crWriteVal=(chan[i].crWriteVal&~0xe0fd)|loopFlag;
chan[i].crDirValChanged=true;
chan[i].crChanged=true;
}
chan[i].pcmChanged.loopBank=0;
}
chan[i].pcmChanged.dummy=0;
}
}
void DivPlatformES5506::tick(bool sysTick) {
for (int i=0; i<=chanMax; i++) {
if (chan[i].crDirValInit) {
@ -348,7 +467,6 @@ void DivPlatformES5506::tick(bool sysTick) {
chan[i].crDirVal=es5506.regs_r(i,0,false)&0x41;
}
chan[i].std.next();
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_ES5506);
signed int k1=chan[i].k1Prev,k2=chan[i].k2Prev;
// volume/panning macros
if (chan[i].std.vol.had) {
@ -569,121 +687,7 @@ void DivPlatformES5506::tick(bool sysTick) {
}
chan[i].volChanged.changed=0;
}
if (chan[i].pcmChanged.changed) {
if (chan[i].pcmChanged.index) {
const int next=chan[i].pcm.next;
bool sampleValid=false;
if (((ins->amiga.useNoteMap) && (next>=0 && next<120)) ||
((!ins->amiga.useNoteMap) && (next>=0 && next<parent->song.sampleLen))) {
DivInstrumentAmiga::SampleMap& noteMapind=ins->amiga.noteMap[next];
int sample=next;
if (ins->amiga.useNoteMap) {
sample=noteMapind.map;
}
if (sample>=0 && sample<parent->song.sampleLen) {
const unsigned int offES5506=sampleOffES5506[sample];
sampleValid=true;
chan[i].pcm.index=sample;
chan[i].pcm.isNoteMap=ins->amiga.useNoteMap;
DivSample* s=parent->getSample(sample);
// get frequency offset
double off=1.0;
double center=(double)s->centerRate;
if (center<1) {
off=1.0;
} else {
off=(double)center/parent->getCenterRate();
}
if (ins->amiga.useNoteMap) {
//chan[i].pcm.note=next;
}
// get loop mode
DivSampleLoopMode loopMode=s->isLoopable()?s->loopMode:DIV_SAMPLE_LOOP_MAX;
const unsigned int start=offES5506<<10;
const unsigned int length=s->samples-1;
const unsigned int end=start+(length<<11);
const unsigned int nextBank=(offES5506>>22)&3;
const double nextFreqOffs=((amigaPitch && !parent->song.compatFlags.linearPitch)?16:PITCH_OFFSET)*off;
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcm.start=start;
chan[i].pcm.end=end;
chan[i].pcm.length=length;
if ((chan[i].pcm.loopMode!=loopMode) || (chan[i].pcm.bank!=nextBank)) {
chan[i].pcm.loopMode=loopMode;
chan[i].pcm.bank=nextBank;
chan[i].pcmChanged.loopBank=1;
}
if (chan[i].pcm.nextFreqOffs!=nextFreqOffs) {
chan[i].pcm.nextFreqOffs=nextFreqOffs;
chan[i].noteChanged.offs=1;
}
}
}
if (sampleValid) {
if (!chan[i].keyOn) {
pageWrite(0x20|i,0x03,(chan[i].pcm.direction)?chan[i].pcm.end:chan[i].pcm.start);
}
chan[i].pcmChanged.slice=1;
}
chan[i].pcmChanged.index=0;
}
if (chan[i].pcmChanged.slice) {
if (!chan[i].keyOn) {
if (chan[i].pcm.index>=0 && chan[i].pcm.index<parent->song.sampleLen) {
// get loop mode
DivSample* s=parent->getSample(chan[i].pcm.index);
const unsigned int start=sampleOffES5506[chan[i].pcm.index]<<10;
const unsigned int nextLoopStart=(start+(s->loopStart<<11))&0xfffff800;
const unsigned int nextLoopEnd=(start+((s->loopEnd)<<11))&0xffffff80;
if ((chan[i].pcm.loopStart!=nextLoopStart) || (chan[i].pcm.loopEnd!=nextLoopEnd)) {
chan[i].pcm.loopStart=nextLoopStart;
chan[i].pcm.loopEnd=nextLoopEnd;
chan[i].pcmChanged.position=1;
}
}
}
chan[i].pcmChanged.slice=0;
}
if (chan[i].pcmChanged.position) {
if (!chan[i].keyOn) {
pageWrite(0x20|i,0x01,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.start:chan[i].pcm.loopStart);
pageWrite(0x20|i,0x02,(chan[i].pcm.loopMode==DIV_SAMPLE_LOOP_MAX)?chan[i].pcm.end:chan[i].pcm.loopEnd);
}
chan[i].pcmChanged.position=0;
}
if (chan[i].pcmChanged.loopBank) {
if (!chan[i].keyOn) {
unsigned int loopFlag=(chan[i].pcm.bank<<14)|(chan[i].pcm.direction?0x0040:0x0000);
chan[i].isReverseLoop=false;
switch (chan[i].pcm.loopMode) {
case DIV_SAMPLE_LOOP_FORWARD: // Forward loop
loopFlag|=0x0008;
break;
/*
case DIV_SAMPLE_LOOP_BACKWARD: // Backward loop: IRQ enable
loopFlag|=0x0038;
chan[i].isReverseLoop=true;
break;
*/
case DIV_SAMPLE_LOOP_PINGPONG: // Pingpong loop: Hardware support
loopFlag|=0x0018;
break;
case DIV_SAMPLE_LOOP_MAX: // no loop
default:
break;
}
// Set loop mode & Bank
chan[i].crDirVal=(chan[i].crDirVal&~0x0040)|(chan[i].pcm.direction?0x0040:0x0000);
chan[i].crWriteVal=(chan[i].crWriteVal&~0x41)|chan[i].crDirVal;
chan[i].crWriteVal=(chan[i].crWriteVal&~0xe0fd)|loopFlag;
chan[i].crDirValChanged=true;
chan[i].crChanged=true;
}
chan[i].pcmChanged.loopBank=0;
}
chan[i].pcmChanged.dummy=0;
}
updatePCMChanges(i);
if (chan[i].filterChanged.changed) {
if (!chan[i].keyOn) {
if (chan[i].filterChanged.mode) {
@ -960,6 +964,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
chan[c.chan].pcmChanged.changed=0xff;
chan[c.chan].noteChanged.changed=0xff;
chan[c.chan].volChanged.changed=0xff;
updatePCMChanges(c.chan);
updateNoteChangesAsNeeded(c.chan);
}
if (!chan[c.chan].std.vol.will) {

View file

@ -281,6 +281,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
DivMemoryComposition memCompo;
unsigned char regPool[4*16*128]; // 7 bit page x 16 registers per page x 32 bit per registers
void updatePCMChanges(int ch);
void updateNoteChangesAsNeeded(int ch);
friend void putDispatchChip(void*,int);