MMC5: acquireDirect(), part 1

no samples
also fixed chan osc
This commit is contained in:
tildearrow 2025-03-07 03:07:52 -05:00
parent 86fb92595a
commit 1070fb5d10
5 changed files with 133 additions and 37 deletions

View file

@ -24,7 +24,7 @@
#define CHIP_DIVIDER 16 #define CHIP_DIVIDER 16
#define rWrite(a,v) if (!skipRegisterWrites) {extcl_cpu_wr_mem_MMC5(mmc5,a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} } #define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite((a),v)); if (dumpWrites) {addWrite(a,v);} }
const char* regCheatSheetMMC5[]={ const char* regCheatSheetMMC5[]={
"S0Volume", "5000", "S0Volume", "5000",
@ -43,12 +43,27 @@ const char** DivPlatformMMC5::getRegisterSheet() {
return regCheatSheetMMC5; return regCheatSheetMMC5;
} }
void DivPlatformMMC5::acquire(short** buf, size_t len) { void DivPlatformMMC5::acquireDirect(blip_buffer_t** bb, size_t len) {
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
oscBuf[i]->begin(len); oscBuf[i]->begin(len);
mmc5->oscBuf[i]=oscBuf[i];
} }
mmc5->bb=bb[0];
mmc5->timestamp=0;
while (!writes.empty()) {
QueuedWrite w=writes.front();
regPool[(w.addr)&0x7f]=w.val;
extcl_cpu_wr_mem_MMC5(mmc5,0,w.addr,w.val);
writes.pop();
}
// TODO: does this matter?
extcl_envelope_clock_MMC5(mmc5);
extcl_length_clock_MMC5(mmc5);
for (size_t i=0; i<len; i++) { for (size_t i=0; i<len; i++) {
/*
if (dacSample!=-1) { if (dacSample!=-1) {
dacPeriod+=dacRate; dacPeriod+=dacRate;
if (dacPeriod>=rate) { if (dacPeriod>=rate) {
@ -69,10 +84,12 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
} }
} }
} }
*/
extcl_envelope_clock_MMC5(mmc5);
extcl_length_clock_MMC5(mmc5); extcl_apu_tick_MMC5(mmc5,len);
extcl_apu_tick_MMC5(mmc5); break;
/*
if (mmc5->clocked) { if (mmc5->clocked) {
mmc5->clocked=false; mmc5->clocked=false;
} }
@ -92,7 +109,7 @@ void DivPlatformMMC5::acquire(short** buf, size_t len) {
oscBuf[0]->putSample(i,isMuted[0]?0:((mmc5->S3.output)<<11)); oscBuf[0]->putSample(i,isMuted[0]?0:((mmc5->S3.output)<<11));
oscBuf[1]->putSample(i,isMuted[1]?0:((mmc5->S4.output)<<11)); oscBuf[1]->putSample(i,isMuted[1]?0:((mmc5->S4.output)<<11));
oscBuf[2]->putSample(i,isMuted[2]?0:((mmc5->pcm.output)<<7)); oscBuf[2]->putSample(i,isMuted[2]?0:((mmc5->pcm.output)<<7));
} }*/
} }
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
@ -364,6 +381,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
void DivPlatformMMC5::muteChannel(int ch, bool mute) { void DivPlatformMMC5::muteChannel(int ch, bool mute) {
isMuted[ch]=mute; isMuted[ch]=mute;
mmc5->muted[ch]=mute;
} }
void DivPlatformMMC5::forceIns() { void DivPlatformMMC5::forceIns() {
@ -415,6 +433,10 @@ void DivPlatformMMC5::reset() {
map_init_MMC5(mmc5); map_init_MMC5(mmc5);
memset(regPool,0,128); memset(regPool,0,128);
mmc5->muted[0]=isMuted[0];
mmc5->muted[1]=isMuted[1];
mmc5->muted[2]=isMuted[2];
rWrite(0x5015,0x03); rWrite(0x5015,0x03);
rWrite(0x5010,0x00); rWrite(0x5010,0x00);
} }
@ -423,6 +445,10 @@ bool DivPlatformMMC5::keyOffAffectsArp(int ch) {
return true; return true;
} }
bool DivPlatformMMC5::hasAcquireDirect() {
return true;
}
void DivPlatformMMC5::setFlags(const DivConfig& flags) { void DivPlatformMMC5::setFlags(const DivConfig& flags) {
int clockSel=flags.getInt("clockSel",0); int clockSel=flags.getInt("clockSel",0);
if (clockSel==2) { // Dendy if (clockSel==2) { // Dendy

View file

@ -39,6 +39,13 @@ class DivPlatformMMC5: public DivDispatch {
Channel chan[5]; Channel chan[5];
DivDispatchOscBuffer* oscBuf[3]; DivDispatchOscBuffer* oscBuf[3];
bool isMuted[5]; bool isMuted[5];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
QueuedWrite(): addr(0), val(0) {}
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
};
FixedQueue<QueuedWrite,128> writes;
int dacPeriod, dacRate; int dacPeriod, dacRate;
unsigned int dacPos; unsigned int dacPos;
int dacSample; int dacSample;
@ -51,7 +58,7 @@ class DivPlatformMMC5: public DivDispatch {
friend void putDispatchChan(void*,int,int); friend void putDispatchChan(void*,int,int);
public: public:
void acquire(short** buf, size_t len); void acquireDirect(blip_buffer_t** bb, size_t len);
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
@ -63,6 +70,7 @@ class DivPlatformMMC5: public DivDispatch {
void tick(bool sysTick=true); void tick(bool sysTick=true);
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool hasAcquireDirect();
float getPostAmp(); float getPostAmp();
void setFlags(const DivConfig& flags); void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);

View file

@ -60,6 +60,8 @@ void apu_tick(struct NESAPU* a, int len) {
} }
if (advance<1) advance=1; if (advance<1) advance=1;
int postTS=a->timestamp+advance-1;
/* sottraggo il numero di cicli eseguiti */ /* sottraggo il numero di cicli eseguiti */
a->apu.cycles-=advance; a->apu.cycles-=advance;
/* /*
@ -220,7 +222,7 @@ void apu_tick(struct NESAPU* a, int len) {
square_output(a->S1, 0) square_output(a->S1, 0)
a->S1.frequency = (a->S1.timer + 1) << 1; a->S1.frequency = (a->S1.timer + 1) << 1;
a->S1.sequencer = (a->S1.sequencer + 1) & 0x07; a->S1.sequencer = (a->S1.sequencer + 1) & 0x07;
a->oscBuf[0]->putSample(a->timestamp,a->muted[0]?0:(a->S1.output<<11)); a->oscBuf[0]->putSample(postTS,a->muted[0]?0:(a->S1.output<<11));
} }
// SQUARE 2 TICK // SQUARE 2 TICK
@ -228,7 +230,7 @@ void apu_tick(struct NESAPU* a, int len) {
square_output(a->S2, 0) square_output(a->S2, 0)
a->S2.frequency = (a->S2.timer + 1) << 1; a->S2.frequency = (a->S2.timer + 1) << 1;
a->S2.sequencer = (a->S2.sequencer + 1) & 0x07; a->S2.sequencer = (a->S2.sequencer + 1) & 0x07;
a->oscBuf[1]->putSample(a->timestamp,a->muted[1]?0:(a->S2.output<<11)); a->oscBuf[1]->putSample(postTS,a->muted[1]?0:(a->S2.output<<11));
} }
// TRIANGLE TICK // TRIANGLE TICK
@ -237,7 +239,7 @@ void apu_tick(struct NESAPU* a, int len) {
if (a->TR.length.value && a->TR.linear.value) { if (a->TR.length.value && a->TR.linear.value) {
a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F; a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F;
triangle_output() triangle_output()
a->oscBuf[2]->putSample(a->timestamp,a->muted[2]?0:(a->TR.output<<11)); a->oscBuf[2]->putSample(postTS,a->muted[2]?0:(a->TR.output<<11));
} }
} }
@ -251,7 +253,7 @@ void apu_tick(struct NESAPU* a, int len) {
a->NS.shift &= 0x7FFF; a->NS.shift &= 0x7FFF;
noise_output() noise_output()
a->NS.frequency = noise_timer[a->apu.type][a->NS.timer]; a->NS.frequency = noise_timer[a->apu.type][a->NS.timer];
a->oscBuf[3]->putSample(a->timestamp,a->muted[3]?0:(a->NS.output<<11)); a->oscBuf[3]->putSample(postTS,a->muted[3]?0:(a->NS.output<<11));
} }
// DMC TICK // DMC TICK
@ -280,7 +282,7 @@ void apu_tick(struct NESAPU* a, int len) {
} }
} }
a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index]; a->DMC.frequency = dmc_rate[a->apu.type][a->DMC.rate_index];
a->oscBuf[4]->putSample(a->timestamp,a->muted[4]?0:(a->DMC.output<<8)); a->oscBuf[4]->putSample(postTS,a->muted[4]?0:(a->DMC.output<<8));
} }
if (a->DMC.empty && a->DMC.remain) { if (a->DMC.empty && a->DMC.remain) {
BYTE tick = 4; BYTE tick = 4;
@ -323,7 +325,7 @@ void apu_tick(struct NESAPU* a, int len) {
} }
// output sample // output sample
a->timestamp+=advance-1; a->timestamp=postTS;
int sample=(pulse_output(a)+tnd_output(a))<<6; int sample=(pulse_output(a)+tnd_output(a))<<6;
if (sample!=a->lastSample) { if (sample!=a->lastSample) {
blip_add_delta(a->bb,a->timestamp,sample-a->lastSample); blip_add_delta(a->bb,a->timestamp,sample-a->lastSample);

View file

@ -35,12 +35,21 @@ void map_init_MMC5(struct _mmc5* mmc5) {
mmc5->S3.length.value = 0; mmc5->S3.length.value = 0;
mmc5->S4.length.enabled = 0; mmc5->S4.length.enabled = 0;
mmc5->S4.length.value = 0; mmc5->S4.length.value = 0;
mmc5->timestamp = 0;
mmc5->lastSample = 0;
mmc5->bb = NULL;
mmc5->oscBuf[0] = NULL;
mmc5->oscBuf[1] = NULL;
mmc5->oscBuf[2] = NULL;
} }
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value) { void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, int ts, WORD address, BYTE value) {
if (address < 0x5000) { if (address < 0x5000) {
return; return;
} }
extcl_apu_tick_MMC5(mmc5,ts);
switch (address) { switch (address) {
case 0x5000: case 0x5000:
square_reg0(mmc5->S3); square_reg0(mmc5->S3);
@ -71,16 +80,18 @@ void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value) {
mmc5->pcm.output = 0; mmc5->pcm.output = 0;
if (mmc5->pcm.enabled) { if (mmc5->pcm.enabled) {
mmc5->pcm.output = mmc5->pcm.amp; mmc5->pcm.output = mmc5->pcm.amp;
mmc5->oscBuf[2]->putSample(mmc5->timestamp,mmc5->muted[2]?0:(mmc5->pcm.output<<7));
} }
mmc5->clocked = TRUE; //mmc5->clocked = TRUE;
return; return;
case 0x5011: case 0x5011:
mmc5->pcm.amp = value; mmc5->pcm.amp = value;
mmc5->pcm.output = 0; mmc5->pcm.output = 0;
if (mmc5->pcm.enabled) { if (mmc5->pcm.enabled) {
mmc5->pcm.output = mmc5->pcm.amp; mmc5->pcm.output = mmc5->pcm.amp;
mmc5->oscBuf[2]->putSample(mmc5->timestamp,mmc5->muted[2]?0:(mmc5->pcm.output<<7));
} }
mmc5->clocked = TRUE; //mmc5->clocked = TRUE;
return; return;
case 0x5015: case 0x5015:
if (!(mmc5->S3.length.enabled = value & 0x01)) { if (!(mmc5->S3.length.enabled = value & 0x01)) {
@ -100,20 +111,70 @@ void extcl_envelope_clock_MMC5(struct _mmc5* mmc5) {
envelope_run(mmc5->S3) envelope_run(mmc5->S3)
envelope_run(mmc5->S4) envelope_run(mmc5->S4)
} }
void extcl_apu_tick_MMC5(struct _mmc5* mmc5) { void extcl_apu_tick_MMC5(struct _mmc5* mmc5, int len) {
// SQUARE 3 TICK if (len<=mmc5->timestamp) return;
if (!(--mmc5->S3.frequency)) {
square_output(mmc5->S3, 0) int rem=len-mmc5->timestamp;
mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1; if (rem>1) {
mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07; // output now just in case
mmc5->clocked = TRUE; int sample=mmc5->muted[0]?0:(mmc5->S3.output*10);
if (!mmc5->muted[1]) {
sample+=mmc5->S4.output*10;
}
if (!mmc5->muted[2]) {
sample+=mmc5->pcm.output*2;
}
if (sample!=mmc5->lastSample) {
blip_add_delta(mmc5->bb,mmc5->timestamp,sample-mmc5->lastSample);
mmc5->lastSample=sample;
}
} }
// SQUARE 4 TICK while (rem>0) {
if (!(--mmc5->S4.frequency)) { // predict advance
square_output(mmc5->S4, 0) int advance=rem;
mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1; if (advance>mmc5->S3.frequency) {
mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07; advance=mmc5->S3.frequency;
mmc5->clocked = TRUE; }
if (advance>mmc5->S4.frequency) {
advance=mmc5->S4.frequency;
}
if (advance<1) advance=1;
int postTS=mmc5->timestamp+advance-1;
// SQUARE 3 TICK
if (!(mmc5->S3.frequency-=advance)) {
square_output(mmc5->S3, 0)
mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1;
mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07;
mmc5->oscBuf[0]->putSample(postTS,mmc5->muted[0]?0:(mmc5->S3.output<<11));
}
// SQUARE 4 TICK
if (!(mmc5->S4.frequency-=advance)) {
square_output(mmc5->S4, 0)
mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1;
mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07;
mmc5->oscBuf[1]->putSample(postTS,mmc5->muted[1]?0:(mmc5->S4.output<<11));
}
// output sample
mmc5->timestamp=postTS;
int sample=mmc5->muted[0]?0:(mmc5->S3.output*10);
if (!mmc5->muted[1]) {
sample+=mmc5->S4.output*10;
}
if (!mmc5->muted[2]) {
sample+=mmc5->pcm.output*2;
}
if (sample!=mmc5->lastSample) {
blip_add_delta(mmc5->bb,mmc5->timestamp,sample-mmc5->lastSample);
mmc5->lastSample=sample;
}
rem-=advance;
mmc5->timestamp++;
} }
mmc5->timestamp=len;
} }

View file

@ -54,19 +54,18 @@ struct _mmc5 {
BYTE output; BYTE output;
BYTE amp; BYTE amp;
} pcm; } pcm;
BYTE filler[50]; int timestamp;
int lastSample;
BYTE muted[3];
/* ------------------------------------------------------- */ blip_buffer_t* bb;
/* questi valori non e' necessario salvarli nei savestates */ DivDispatchOscBuffer* oscBuf[5];
/* ------------------------------------------------------- */
/* */ BYTE clocked; /* */
/* ------------------------------------------------------- */
}; };
void map_init_MMC5(struct _mmc5* mmc5); void map_init_MMC5(struct _mmc5* mmc5);
void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, WORD address, BYTE value); void extcl_cpu_wr_mem_MMC5(struct _mmc5* mmc5, int ts, WORD address, BYTE value);
void extcl_length_clock_MMC5(struct _mmc5* mmc5); void extcl_length_clock_MMC5(struct _mmc5* mmc5);
void extcl_envelope_clock_MMC5(struct _mmc5* mmc5); void extcl_envelope_clock_MMC5(struct _mmc5* mmc5);
void extcl_apu_tick_MMC5(struct _mmc5* mmc5); void extcl_apu_tick_MMC5(struct _mmc5* mmc5, int len);
#endif /* MAPPER_MMC5_H_ */ #endif /* MAPPER_MMC5_H_ */