YM2612: better DAC write scheduling

issue #1300
This commit is contained in:
tildearrow 2023-08-04 17:35:39 -05:00
parent 297334e882
commit 77e708dc57
4 changed files with 58 additions and 49 deletions

View File

@ -105,16 +105,17 @@ class DivPlatformFMBase: public DivDispatch {
}
}
}
// only used by OPN2 for DAC writes
inline void urgentWrite(unsigned short a, unsigned char v) {
if (!skipRegisterWrites && !flushFirst) {
if (writes.empty()) {
writes.push_back(QueuedWrite(a,v));
} else if ((writes.size()>16 && writes.front().addr!=0xf0) || writes.front().addrOrVal) {
// $f0 is used by OPN hard reset
writes.push_back(QueuedWrite(a,v));
} else {
writes.push_front(QueuedWrite(a,v));
if (!writes.empty()) {
// check for hard reset
if (writes.front().addr==0xf0) {
// replace hard reset with DAC write
writes.pop_front();
}
}
writes.push_front(QueuedWrite(a,v));
if (dumpWrites) {
addWrite(a,v);
}

View File

@ -96,32 +96,22 @@ void DivPlatformGenesis::processDAC(int iRate) {
//sample>>=1;
if (sample<-128) sample=-128;
if (sample>127) sample=127;
urgentWrite(0x2a,(unsigned char)sample+0x80);
dacWrite=(unsigned char)(sample+0x80);
}
} else {
if (!chan[5].dacReady) {
chan[5].dacDelay+=32000;
if (chan[5].dacDelay>=iRate) {
chan[5].dacDelay-=iRate;
chan[5].dacReady=true;
}
}
if (chan[5].dacMode && chan[5].dacSample!=-1) {
chan[5].dacPeriod+=chan[5].dacRate;
if (chan[5].dacPeriod>=iRate) {
DivSample* s=parent->getSample(chan[5].dacSample);
if (s->samples>0 && chan[5].dacPos<s->samples) {
if (!isMuted[5]) {
if (chan[5].dacReady && writes.size()<16) {
int sample;
if (parent->song.noOPN2Vol) {
sample=s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos];
} else {
sample=(s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos]*dacVolTable[chan[5].outVol])>>7;
}
urgentWrite(0x2a,(unsigned char)sample+0x80);
chan[5].dacReady=false;
int sample;
if (parent->song.noOPN2Vol) {
sample=s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos];
} else {
sample=(s->data8[chan[5].dacDirection?(s->samples-chan[5].dacPos-1):chan[5].dacPos]*dacVolTable[chan[5].outVol])>>7;
}
dacWrite=(unsigned char)(sample+0x80);
}
chan[5].dacPos++;
if (!chan[5].dacDirection && (s->isLoopable() && chan[5].dacPos>=(unsigned int)s->loopEnd)) {
@ -151,24 +141,34 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
os[0]=0; os[1]=0;
for (int i=0; i<6; i++) {
if (!writes.empty()) {
if (--delay<0) {
delay=0;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
//logV("%.3x = %.2x",w.addr,w.val);
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
lastBusy=0;
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
} else {
lastBusy++;
if (fm.write_busy==0) {
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
QueuedWrite& w=writes.front();
if (w.addrOrVal) {
//logV("%.3x = %.2x",w.addr,w.val);
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
if (dacWrite>=0) {
if (!canWriteDAC) {
canWriteDAC=true;
} else {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
canWriteDAC=writes.empty();
}
}
} else {
if (fm.write_busy==0) {
OPN2_Write(&fm,0x0+((w.addr>>8)<<1),w.addr);
w.addrOrVal=true;
}
}
} else {
canWriteDAC=true;
if (dacWrite>=0) {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
}
flushFirst=false;
}
@ -227,8 +227,22 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop_front();
lastBusy=1;
if (dacWrite>=0) {
if (!canWriteDAC) {
canWriteDAC=true;
} else {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
canWriteDAC=writes.empty();
}
}
} else {
canWriteDAC=true;
if (dacWrite>=0) {
urgentWrite(0x2a,dacWrite);
dacWrite=-1;
}
flushFirst=false;
}
@ -1314,11 +1328,12 @@ void DivPlatformGenesis::reset() {
pendingWrites[i]=-1;
}
lastBusy=60;
lfoValue=8;
softPCMTimer=0;
extMode=false;
flushFirst=false;
dacWrite=-1;
canWriteDAC=true;
if (softPCM) {
chan[5].dacMode=true;
@ -1330,8 +1345,6 @@ void DivPlatformGenesis::reset() {
// LFO
immWrite(0x22,lfoValue);
delay=0;
}
int DivPlatformGenesis::getOutputCount() {

View File

@ -55,7 +55,6 @@ class DivPlatformGenesis: public DivPlatformOPN {
unsigned int dacPos;
int dacSample;
int dacDelay;
bool dacReady;
bool dacDirection;
bool setPos;
unsigned char sampleBank;
@ -69,7 +68,6 @@ class DivPlatformGenesis: public DivPlatformOPN {
dacPos(0),
dacSample(-1),
dacDelay(0),
dacReady(true),
dacDirection(false),
setPos(false),
sampleBank(0),
@ -86,8 +84,9 @@ class DivPlatformGenesis: public DivPlatformOPN {
int softPCMTimer;
bool extMode, softPCM, noExtMacros, useYMFM;
bool extMode, softPCM, noExtMacros, useYMFM, canWriteDAC;
unsigned char chipType;
short dacWrite;
unsigned char dacVolTable[128];

View File

@ -62,7 +62,6 @@
#define FM_CHIP_DEBUG \
COMMON_CHIP_DEBUG; \
ImGui::Text("- lastBusy: %d",ch->lastBusy); \
ImGui::Text("- delay: %d",ch->delay);
#define FM_OPN_CHIP_DEBUG \
@ -167,7 +166,6 @@
ImGui::TextColored(ch->hardReset?colorOn:colorOff,">> hardReset"); \
ImGui::TextColored(ch->opMaskChanged?colorOn:colorOff,">> opMaskChanged"); \
ImGui::TextColored(ch->dacMode?colorOn:colorOff,">> DACMode"); \
ImGui::TextColored(ch->dacReady?colorOn:colorOff,">> DACReady"); \
ImGui::TextColored(ch->dacDirection?colorOn:colorOff,">> DACDirection");
#define GENESIS_OPCHAN_DEBUG \
@ -381,7 +379,6 @@ void putDispatchChip(void* data, int type) {
ImGui::Text("- pcmR: %d",ch->pcmR);
ImGui::Text("- pcmCycles: %d",ch->pcmCycles);
ImGui::Text("- sampleBank: %d",ch->sampleBank);
ImGui::Text("- lastBusy: %d",ch->lastBusy);
COMMON_CHIP_DEBUG_BOOL;
break;
}
@ -389,7 +386,6 @@ void putDispatchChip(void* data, int type) {
DivPlatformAY8910* ch=(DivPlatformAY8910*)data;
ImGui::Text("> AY-3-8910");
COMMON_CHIP_DEBUG;
ImGui::Text("- lastBusy: %d",ch->lastBusy);
ImGui::Text("- sampleBank: %d",ch->sampleBank);
ImGui::Text("- stereoSep: %d",ch->stereoSep);
ImGui::Text("- delay: %d",ch->delay);