From 1070fb5d10b48b538b3555e78c9f63e08164c74c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 7 Mar 2025 03:07:52 -0500 Subject: [PATCH] MMC5: acquireDirect(), part 1 no samples also fixed chan osc --- src/engine/platform/mmc5.cpp | 38 +++++++++-- src/engine/platform/mmc5.h | 10 ++- src/engine/platform/sound/nes/apu.cpp | 14 ++-- src/engine/platform/sound/nes/mmc5.cpp | 93 +++++++++++++++++++++----- src/engine/platform/sound/nes/mmc5.h | 15 ++--- 5 files changed, 133 insertions(+), 37 deletions(-) diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 506ba3be4..894965b50 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -24,7 +24,7 @@ #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[]={ "S0Volume", "5000", @@ -43,12 +43,27 @@ const char** DivPlatformMMC5::getRegisterSheet() { 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++) { 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=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); + + extcl_apu_tick_MMC5(mmc5,len); + break; + /* if (mmc5->clocked) { 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[1]->putSample(i,isMuted[1]?0:((mmc5->S4.output)<<11)); oscBuf[2]->putSample(i,isMuted[2]?0:((mmc5->pcm.output)<<7)); - } + }*/ } for (int i=0; i<3; i++) { @@ -364,6 +381,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { void DivPlatformMMC5::muteChannel(int ch, bool mute) { isMuted[ch]=mute; + mmc5->muted[ch]=mute; } void DivPlatformMMC5::forceIns() { @@ -415,6 +433,10 @@ void DivPlatformMMC5::reset() { map_init_MMC5(mmc5); memset(regPool,0,128); + mmc5->muted[0]=isMuted[0]; + mmc5->muted[1]=isMuted[1]; + mmc5->muted[2]=isMuted[2]; + rWrite(0x5015,0x03); rWrite(0x5010,0x00); } @@ -423,6 +445,10 @@ bool DivPlatformMMC5::keyOffAffectsArp(int ch) { return true; } +bool DivPlatformMMC5::hasAcquireDirect() { + return true; +} + void DivPlatformMMC5::setFlags(const DivConfig& flags) { int clockSel=flags.getInt("clockSel",0); if (clockSel==2) { // Dendy diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 8ee22fd2f..57e396c06 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -39,6 +39,13 @@ class DivPlatformMMC5: public DivDispatch { Channel chan[5]; DivDispatchOscBuffer* oscBuf[3]; 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 writes; int dacPeriod, dacRate; unsigned int dacPos; int dacSample; @@ -51,7 +58,7 @@ class DivPlatformMMC5: public DivDispatch { friend void putDispatchChan(void*,int,int); public: - void acquire(short** buf, size_t len); + void acquireDirect(blip_buffer_t** bb, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); @@ -63,6 +70,7 @@ class DivPlatformMMC5: public DivDispatch { void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); + bool hasAcquireDirect(); float getPostAmp(); void setFlags(const DivConfig& flags); void notifyInsDeletion(void* ins); diff --git a/src/engine/platform/sound/nes/apu.cpp b/src/engine/platform/sound/nes/apu.cpp index 1417df0f6..4f77b22af 100644 --- a/src/engine/platform/sound/nes/apu.cpp +++ b/src/engine/platform/sound/nes/apu.cpp @@ -60,6 +60,8 @@ void apu_tick(struct NESAPU* a, int len) { } if (advance<1) advance=1; + int postTS=a->timestamp+advance-1; + /* sottraggo il numero di cicli eseguiti */ a->apu.cycles-=advance; /* @@ -220,7 +222,7 @@ void apu_tick(struct NESAPU* a, int len) { square_output(a->S1, 0) a->S1.frequency = (a->S1.timer + 1) << 1; 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 @@ -228,7 +230,7 @@ void apu_tick(struct NESAPU* a, int len) { square_output(a->S2, 0) a->S2.frequency = (a->S2.timer + 1) << 1; 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 @@ -237,7 +239,7 @@ void apu_tick(struct NESAPU* a, int len) { if (a->TR.length.value && a->TR.linear.value) { a->TR.sequencer = (a->TR.sequencer + 1) & 0x1F; 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; noise_output() 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 @@ -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->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) { BYTE tick = 4; @@ -323,7 +325,7 @@ void apu_tick(struct NESAPU* a, int len) { } // output sample - a->timestamp+=advance-1; + a->timestamp=postTS; int sample=(pulse_output(a)+tnd_output(a))<<6; if (sample!=a->lastSample) { blip_add_delta(a->bb,a->timestamp,sample-a->lastSample); diff --git a/src/engine/platform/sound/nes/mmc5.cpp b/src/engine/platform/sound/nes/mmc5.cpp index 9838498f6..a8d78dc82 100644 --- a/src/engine/platform/sound/nes/mmc5.cpp +++ b/src/engine/platform/sound/nes/mmc5.cpp @@ -35,12 +35,21 @@ void map_init_MMC5(struct _mmc5* mmc5) { mmc5->S3.length.value = 0; mmc5->S4.length.enabled = 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) { return; } + extcl_apu_tick_MMC5(mmc5,ts); + switch (address) { case 0x5000: 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; if (mmc5->pcm.enabled) { 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; case 0x5011: mmc5->pcm.amp = value; mmc5->pcm.output = 0; if (mmc5->pcm.enabled) { 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; case 0x5015: 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->S4) } -void extcl_apu_tick_MMC5(struct _mmc5* mmc5) { - // SQUARE 3 TICK - if (!(--mmc5->S3.frequency)) { - square_output(mmc5->S3, 0) - mmc5->S3.frequency = (mmc5->S3.timer + 1) << 1; - mmc5->S3.sequencer = (mmc5->S3.sequencer + 1) & 0x07; - mmc5->clocked = TRUE; +void extcl_apu_tick_MMC5(struct _mmc5* mmc5, int len) { + if (len<=mmc5->timestamp) return; + + int rem=len-mmc5->timestamp; + if (rem>1) { + // output now just in case + 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 - if (!(--mmc5->S4.frequency)) { - square_output(mmc5->S4, 0) - mmc5->S4.frequency = (mmc5->S4.timer + 1) << 1; - mmc5->S4.sequencer = (mmc5->S4.sequencer + 1) & 0x07; - mmc5->clocked = TRUE; + while (rem>0) { + // predict advance + int advance=rem; + if (advance>mmc5->S3.frequency) { + advance=mmc5->S3.frequency; + } + 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; } diff --git a/src/engine/platform/sound/nes/mmc5.h b/src/engine/platform/sound/nes/mmc5.h index 68f3fb637..2d7223fe8 100644 --- a/src/engine/platform/sound/nes/mmc5.h +++ b/src/engine/platform/sound/nes/mmc5.h @@ -54,19 +54,18 @@ struct _mmc5 { BYTE output; BYTE amp; } pcm; - BYTE filler[50]; + int timestamp; + int lastSample; + BYTE muted[3]; - /* ------------------------------------------------------- */ - /* questi valori non e' necessario salvarli nei savestates */ - /* ------------------------------------------------------- */ - /* */ BYTE clocked; /* */ - /* ------------------------------------------------------- */ + blip_buffer_t* bb; + DivDispatchOscBuffer* oscBuf[5]; }; 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_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_ */