NES: fix Furnace-style DPCM

This commit is contained in:
tildearrow 2022-05-02 16:05:07 -05:00
parent ce40085d3b
commit 960048cf4b

View file

@ -313,8 +313,6 @@ void DivPlatformNES::tick(bool sysTick) {
if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq<0) chan[i].freq=0;
} }
if (chan[i].keyOn) { if (chan[i].keyOn) {
//rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
//rWrite(16+i*5+2,((chan[i].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3));
} }
if (chan[i].keyOff) { if (chan[i].keyOff) {
//rWrite(16+i*5+2,8); //rWrite(16+i*5+2,8);
@ -343,7 +341,7 @@ void DivPlatformNES::tick(bool sysTick) {
} }
// PCM // PCM
if (chan[4].freqChanged) { if (chan[4].freqChanged || chan[4].keyOn) {
chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,false); chan[4].freq=parent->calcFreq(chan[4].baseFreq,chan[4].pitch,false);
if (chan[4].furnaceDac) { if (chan[4].furnaceDac) {
double off=1.0; double off=1.0;
@ -352,11 +350,27 @@ void DivPlatformNES::tick(bool sysTick) {
off=(double)s->centerRate/8363.0; off=(double)s->centerRate/8363.0;
} }
dacRate=MIN(chan[4].freq*off,32000); dacRate=MIN(chan[4].freq*off,32000);
if (dpcmMode && !skipRegisterWrites) { if (chan[4].keyOn) {
rWrite(0x4010,calcDPCMRate(dacRate)); if (dpcmMode && !skipRegisterWrites && dacSample>=0 && dacSample<parent->song.sampleLen) {
unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM;
unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4;
if (dpcmLen>255) dpcmLen=255;
// write DPCM
rWrite(0x4015,15);
rWrite(0x4010,calcDPCMRate(dacRate));
rWrite(0x4012,(dpcmAddr>>6)&0xff);
rWrite(0x4013,dpcmLen&0xff);
rWrite(0x4015,31);
dpcmBank=dpcmAddr>>14;
}
} else {
if (dpcmMode) {
rWrite(0x4010,calcDPCMRate(dacRate));
}
} }
if (dumpWrites) addWrite(0xffff0001,dacRate); if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate);
} }
if (chan[4].keyOn) chan[4].keyOn=false;
chan[4].freqChanged=false; chan[4].freqChanged=false;
} }
} }
@ -378,25 +392,13 @@ int DivPlatformNES::dispatch(DivCommand c) {
dacPos=0; dacPos=0;
dacPeriod=0; dacPeriod=0;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=parent->song.tuning*pow(2.0f,((float)(c.value+3)/12.0f)); chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value,false);
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; 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].furnaceDac=true; chan[c.chan].furnaceDac=true;
if (dpcmMode && !skipRegisterWrites) {
unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM;
unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4;
if (dpcmLen>255) dpcmLen=255;
// write DPCM
rWrite(0x4015,15);
rWrite(0x4010,calcDPCMRate(chan[c.chan].baseFreq));
rWrite(0x4012,(dpcmAddr>>6)&0xff);
rWrite(0x4013,dpcmLen&0xff);
rWrite(0x4015,31);
dpcmBank=dpcmAddr>>14;
}
} else { } else {
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
@ -492,7 +494,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
break; break;
case DIV_CMD_NOTE_PORTA: { case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_PERIODIC(c.value2); int destFreq=(c.chan==4)?(parent->calcBaseFreq(1,1,c.value2,false)):(NOTE_PERIODIC(c.value2));
bool return2=false; bool return2=false;
if (destFreq>chan[c.chan].baseFreq) { if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value; chan[c.chan].baseFreq+=c.value;
@ -554,7 +556,11 @@ int DivPlatformNES::dispatch(DivCommand c) {
break; break;
case DIV_CMD_LEGATO: case DIV_CMD_LEGATO:
if (c.chan==3) break; if (c.chan==3) break;
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0))); if (c.chan==4) {
chan[c.chan].baseFreq=parent->calcBaseFreq(1,1,c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)),false);
} else {
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
}
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
break; break;