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) { inline void urgentWrite(unsigned short a, unsigned char v) {
if (!skipRegisterWrites && !flushFirst) { if (!skipRegisterWrites && !flushFirst) {
if (writes.empty()) { if (!writes.empty()) {
writes.push_back(QueuedWrite(a,v)); // check for hard reset
} else if ((writes.size()>16 && writes.front().addr!=0xf0) || writes.front().addrOrVal) { if (writes.front().addr==0xf0) {
// $f0 is used by OPN hard reset // replace hard reset with DAC write
writes.push_back(QueuedWrite(a,v)); writes.pop_front();
} else {
writes.push_front(QueuedWrite(a,v));
} }
}
writes.push_front(QueuedWrite(a,v));
if (dumpWrites) { if (dumpWrites) {
addWrite(a,v); addWrite(a,v);
} }

View file

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

View file

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

View file

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