From f0a3e3f590c4b35b8745f5abd1d8aedcb1ff31e1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 3 Mar 2025 20:27:35 -0500 Subject: [PATCH 1/6] PCE: Mednafen is wonderful the PSG emulator already comes with heuristics... I stripped them off for Furnace but now that we have acquireDirect() we can give it our blip_buf and handle everything there from 40-70% to 10% CPU usage on my phone, and highest quality! TODO: - PCM - chan osc (should be very easy) --- src/engine/platform/pce.cpp | 52 +++++++++++++-------------- src/engine/platform/pce.h | 4 +-- src/engine/platform/sound/pce_psg.cpp | 31 +++------------- src/engine/platform/sound/pce_psg.h | 7 ++-- 4 files changed, 37 insertions(+), 57 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 858546738..692c12354 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -34,7 +34,7 @@ rWrite(a,v); \ } -#define CHIP_DIVIDER 32 +#define CHIP_DIVIDER 64 const char* regCheatSheetPCE[]={ "Select", "0", @@ -55,12 +55,20 @@ const char** DivPlatformPCE::getRegisterSheet() { } void DivPlatformPCE::acquire(short** buf, size_t len) { +} + +void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { for (int i=0; i<6; i++) { oscBuf[i]->begin(len); } + pce->bb[0]=bb[0]; + pce->bb[1]=bb[1]; + + size_t pos=off; for (size_t h=0; hResetTS(pos); while (!writes.empty()) { QueuedWrite w=writes.front(); - pce->Write(0,w.addr,w.val); + pce->Write(pos,w.addr,w.val); regPool[w.addr&0x0f]=w.val; writes.pop(); } - tempL[0]=0; - tempR[0]=0; - pce->Update(coreQuality); - pce->ResetTS(0); + pce->Update(len+pos); + break; + /* for (int i=0; i<6; i++) { oscBuf[i]->putSample(h,CLAMP(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1],-32768,32767)); - } - - tempL[0]=(tempL[0]>>1)+(tempL[0]>>2); - tempR[0]=(tempR[0]>>1)+(tempR[0]>>2); - - if (tempL[0]<-32768) tempL[0]=-32768; - if (tempL[0]>32767) tempL[0]=32767; - if (tempR[0]<-32768) tempR[0]=-32768; - if (tempR[0]>32767) tempR[0]=32767; - - //printf("tempL: %d tempR: %d\n",tempL,tempR); - buf[0][h]=tempL[0]; - buf[1][h]=tempR[0]; + }*/ + pos++; } for (int i=0; i<6; i++) { @@ -614,8 +612,6 @@ void DivPlatformPCE::reset() { } pce->Power(0); lastPan=0xff; - memset(tempL,0,32*sizeof(int)); - memset(tempR,0,32*sizeof(int)); curChan=-1; sampleBank=0; lfoMode=0; @@ -639,6 +635,10 @@ bool DivPlatformPCE::keyOffAffectsArp(int ch) { return true; } +bool DivPlatformPCE::hasAcquireDirect() { + return true; +} + void DivPlatformPCE::notifyWaveChange(int wave) { for (int i=0; i<6; i++) { if (chan[i].wave==wave) { @@ -656,13 +656,13 @@ void DivPlatformPCE::notifyInsDeletion(void* ins) { void DivPlatformPCE::setFlags(const DivConfig& flags) { if (flags.getInt("clockSel",0)) { // technically there is no PAL PC Engine but oh well... - chipClock=COLOR_PAL*4.0/5.0; + chipClock=COLOR_PAL*8.0/5.0; } else { - chipClock=COLOR_NTSC; + chipClock=COLOR_NTSC*2.0; } CHECK_CUSTOM_CLOCK; antiClickEnabled=!flags.getBool("noAntiClick",false); - rate=chipClock/(coreQuality>>1); + rate=chipClock; for (int i=0; i<6; i++) { oscBuf[i]->setRate(rate); } @@ -671,7 +671,7 @@ void DivPlatformPCE::setFlags(const DivConfig& flags) { delete pce; pce=NULL; } - pce=new PCE_PSG(tempL,tempR,flags.getInt("chipType",0)?PCE_PSG::REVISION_HUC6280A:PCE_PSG::REVISION_HUC6280); + pce=new PCE_PSG(flags.getInt("chipType",0)?PCE_PSG::REVISION_HUC6280A:PCE_PSG::REVISION_HUC6280); } void DivPlatformPCE::poke(unsigned int addr, unsigned short val) { diff --git a/src/engine/platform/pce.h b/src/engine/platform/pce.h index 6d5f0f5ae..4840c665e 100644 --- a/src/engine/platform/pce.h +++ b/src/engine/platform/pce.h @@ -70,8 +70,6 @@ class DivPlatformPCE: public DivDispatch { unsigned char lastPan; int curChan; - int tempL[32]; - int tempR[32]; unsigned char sampleBank, lfoMode, lfoSpeed; int coreQuality; PCE_PSG* pce; @@ -81,6 +79,7 @@ class DivPlatformPCE: public DivDispatch { friend void putDispatchChan(void*,int,int); public: void acquire(short** buf, size_t len); + void acquireDirect(blip_buffer_t** bb, size_t off, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); @@ -99,6 +98,7 @@ class DivPlatformPCE: public DivDispatch { void muteChannel(int ch, bool mute); int getOutputCount(); bool keyOffAffectsArp(int ch); + bool hasAcquireDirect(); void setCoreQuality(unsigned char q); void setFlags(const DivConfig& flags); void notifyWaveChange(int wave); diff --git a/src/engine/platform/sound/pce_psg.cpp b/src/engine/platform/sound/pce_psg.cpp index e9de06ecf..6801e0cfc 100644 --- a/src/engine/platform/sound/pce_psg.cpp +++ b/src/engine/platform/sound/pce_psg.cpp @@ -70,34 +70,13 @@ static const int scale_tab[] = inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, const int32_t samp0, const int32_t samp1) { - if (timestamp>0) return; - HRBufs[0][timestamp]+=samp0; - HRBufs[1][timestamp]+=samp1; - /* int32_t delta[2]; delta[0] = samp0 - ch->blip_prev_samp[0]; delta[1] = samp1 - ch->blip_prev_samp[1]; - const int16_t* c = Phase_Filter[(timestamp >> 1) & 1]; - const int32_t l = (timestamp >> 2) & 0xFFFF; - - HRBufs[0][l + 0] += delta[0] * c[0]; - HRBufs[0][l + 1] += delta[0] * c[1]; - HRBufs[0][l + 2] += delta[0] * c[2]; - HRBufs[0][l + 3] += delta[0] * c[3]; - HRBufs[0][l + 4] += delta[0] * c[4]; - HRBufs[0][l + 5] += delta[0] * c[5]; - HRBufs[0][l + 6] += delta[0] * c[6]; - - HRBufs[1][l + 0] += delta[1] * c[0]; - HRBufs[1][l + 1] += delta[1] * c[1]; - HRBufs[1][l + 2] += delta[1] * c[2]; - HRBufs[1][l + 3] += delta[1] * c[3]; - HRBufs[1][l + 4] += delta[1] * c[4]; - HRBufs[1][l + 5] += delta[1] * c[5]; - HRBufs[1][l + 6] += delta[1] * c[6]; - */ + blip_add_delta(bb[0],timestamp,delta[0]); + blip_add_delta(bb[1],timestamp,delta[1]); ch->blip_prev_samp[0] = samp0; ch->blip_prev_samp[1] = samp1; @@ -405,7 +384,7 @@ void PSG_SetRegister(const unsigned int id, const uint32_t value) } #endif -PCE_PSG::PCE_PSG(int32_t* hr_l, int32_t* hr_r, int want_revision) +PCE_PSG::PCE_PSG(int want_revision) { //printf("Test: %u, %u\n", sizeof(psg_channel), (uint8_t*)&channel[0].balance - (uint8_t*)&channel[0].waveform[0]); @@ -424,8 +403,8 @@ PCE_PSG::PCE_PSG(int32_t* hr_l, int32_t* hr_r, int want_revision) UpdateOutput_Accum = &PCE_PSG::UpdateOutput_Accum_HuC6280A; break; } - HRBufs[0] = hr_l; - HRBufs[1] = hr_r; + bb[0]=NULL; + bb[1]=NULL; lastts = 0; for(int ch = 0; ch < 6; ch++) diff --git a/src/engine/platform/sound/pce_psg.h b/src/engine/platform/sound/pce_psg.h index 08f7f88ce..cdc6e0c99 100644 --- a/src/engine/platform/sound/pce_psg.h +++ b/src/engine/platform/sound/pce_psg.h @@ -24,6 +24,7 @@ #define __MDFN_HW_SOUND_PCE_PSG_PCE_PSG_H #include +#include "../../blip_buf.h" class PCE_PSG; @@ -130,7 +131,7 @@ class PCE_PSG }; - PCE_PSG(int32_t* hr_l, int32_t* hr_r, int want_revision); + PCE_PSG(int want_revision); ~PCE_PSG(); void Power(const int32_t timestamp); @@ -150,6 +151,8 @@ class PCE_PSG psg_channel channel[6]; + blip_buffer_t* bb[2]; + private: void UpdateSubLFO(int32_t timestamp); @@ -183,8 +186,6 @@ class PCE_PSG int32_t lastts; int revision; - int32_t* HRBufs[2]; - int32_t dbtable_volonly[32]; int32_t dbtable[32][32]; From 5d3a22a502c4e37d13eb11a2e9122f4310535a8d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 4 Mar 2025 11:57:41 -0500 Subject: [PATCH 2/6] PCE: PCM might work again --- src/engine/platform/pce.cpp | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 692c12354..77dc22490 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -66,12 +66,31 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { pce->bb[1]=bb[1]; size_t pos=off; - for (size_t h=0; hResetTS(pos); + + while (!writes.empty()) { + QueuedWrite w=writes.front(); + pce->Write(pos,w.addr,w.val); + regPool[w.addr&0x0f]=w.val; + writes.pop(); + } + + for (size_t h=0; hrate) { DivSample* s=parent->getSample(chan[i].dacSample); if (s->samples<=0 || chan[i].dacPos>=s->samples) { @@ -97,25 +116,25 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { chan[i].dacPeriod-=rate; } } - }*/ + } // PCE part // WHAT????????? - pce->ResetTS(pos); + pos+=advance; + while (!writes.empty()) { QueuedWrite w=writes.front(); pce->Write(pos,w.addr,w.val); regPool[w.addr&0x0f]=w.val; writes.pop(); } - pce->Update(len+pos); - break; + pce->Update(pos); /* for (int i=0; i<6; i++) { oscBuf[i]->putSample(h,CLAMP(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1],-32768,32767)); }*/ - pos++; + h+=advance; } for (int i=0; i<6; i++) { From ec5aafb9adf03c5c4ae9d1ed1fc24bdef876536c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 4 Mar 2025 12:19:46 -0500 Subject: [PATCH 3/6] PCE: PCM works CPU usage increases though when it's in use :< --- src/engine/platform/pce.cpp | 7 ++++--- src/engine/vgmOps.cpp | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 77dc22490..5dc68fd8a 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -82,8 +82,9 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { for (int i=0; i<6; i++) { if (chan[i].pcm && chan[i].dacSample!=-1) { if (chan[i].dacRate<=0) continue; - remainTime=(rate-chan[i].dacPeriod)/chan[i].dacRate; + remainTime=(rate-chan[i].dacPeriod+chan[i].dacRate-1)/chan[i].dacRate; if (remainTimeUpdate(pos); /* for (int i=0; i<6; i++) { @@ -136,6 +136,7 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { }*/ h+=advance; } + pce->Update(pos); for (int i=0; i<6; i++) { oscBuf[i]->end(len); @@ -261,7 +262,7 @@ void DivPlatformPCE::tick(bool sysTick) { off=parent->getCenterRate()/(double)s->centerRate; } } - chan[i].dacRate=((double)chipClock/2)/MAX(1,off*chan[i].freq); + chan[i].dacRate=(double)chipClock/(4*MAX(1,off*chan[i].freq)); if (dumpWrites) addWrite(0xffff0001+(i<<8),chan[i].dacRate); } if (chan[i].freq<1) chan[i].freq=1; diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index 1d21a8092..13fbd9b2c 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1432,7 +1432,8 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p break; case DIV_SYSTEM_PCE: if (!hasPCE) { - hasPCE=disCont[i].dispatch->chipClock; + // the clock is halved in VGM... + hasPCE=disCont[i].dispatch->chipClock/2; CHIP_VOL(27,0.98); willExport[i]=true; writePCESamples=true; From 11c99f9f9629c0fb0df8e77761d4f4092a48ab4e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 4 Mar 2025 12:21:56 -0500 Subject: [PATCH 4/6] PCE: push it even further! now a bit faster --- src/engine/platform/sound/pce_psg.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/sound/pce_psg.cpp b/src/engine/platform/sound/pce_psg.cpp index 6801e0cfc..41cb72504 100644 --- a/src/engine/platform/sound/pce_psg.cpp +++ b/src/engine/platform/sound/pce_psg.cpp @@ -75,8 +75,8 @@ inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, c delta[0] = samp0 - ch->blip_prev_samp[0]; delta[1] = samp1 - ch->blip_prev_samp[1]; - blip_add_delta(bb[0],timestamp,delta[0]); - blip_add_delta(bb[1],timestamp,delta[1]); + if (delta[0]) blip_add_delta(bb[0],timestamp,delta[0]); + if (delta[1]) blip_add_delta(bb[1],timestamp,delta[1]); ch->blip_prev_samp[0] = samp0; ch->blip_prev_samp[1] = samp1; From ac8df480abe3cb3a144dd31158924fa55eb1eeec Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 4 Mar 2025 12:37:31 -0500 Subject: [PATCH 5/6] PCE: half working channel osc it doesn't look right --- src/engine/platform/pce.cpp | 5 +---- src/engine/platform/sound/pce_psg.cpp | 9 ++++++++- src/engine/platform/sound/pce_psg.h | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 5dc68fd8a..8924015b6 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -60,6 +60,7 @@ void DivPlatformPCE::acquire(short** buf, size_t len) { void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { for (int i=0; i<6; i++) { oscBuf[i]->begin(len); + pce->channel[i].oscBuf=oscBuf[i]; } pce->bb[0]=bb[0]; @@ -130,10 +131,6 @@ void DivPlatformPCE::acquireDirect(blip_buffer_t** bb, size_t off, size_t len) { writes.pop(); } - /* - for (int i=0; i<6; i++) { - oscBuf[i]->putSample(h,CLAMP(pce->channel[i].blip_prev_samp[0]+pce->channel[i].blip_prev_samp[1],-32768,32767)); - }*/ h+=advance; } pce->Update(pos); diff --git a/src/engine/platform/sound/pce_psg.cpp b/src/engine/platform/sound/pce_psg.cpp index 41cb72504..689e2275a 100644 --- a/src/engine/platform/sound/pce_psg.cpp +++ b/src/engine/platform/sound/pce_psg.cpp @@ -78,6 +78,8 @@ inline void PCE_PSG::UpdateOutputSub(const int32_t timestamp, psg_channel *ch, c if (delta[0]) blip_add_delta(bb[0],timestamp,delta[0]); if (delta[1]) blip_add_delta(bb[1],timestamp,delta[1]); + ch->oscBuf->putSample(timestamp-ch->lasttsbase,CLAMP(samp0+samp1,-32768,32767)); + ch->blip_prev_samp[0] = samp0; ch->blip_prev_samp[1] = samp1; @@ -407,11 +409,13 @@ PCE_PSG::PCE_PSG(int want_revision) bb[1]=NULL; lastts = 0; + lasttsbase = 0; for(int ch = 0; ch < 6; ch++) { channel[ch].blip_prev_samp[0] = 0; channel[ch].blip_prev_samp[1] = 0; channel[ch].lastts = 0; + channel[ch].lasttsbase = 0; } SetVolume(1.0); // Will build dbtable in the process. @@ -749,9 +753,12 @@ void PCE_PSG::Update(int32_t timestamp) void PCE_PSG::ResetTS(int32_t ts_base) { lastts = ts_base; + lasttsbase = ts_base; - for(int chc = 0; chc < 6; chc++) + for(int chc = 0; chc < 6; chc++) { channel[chc].lastts = ts_base; + channel[chc].lasttsbase = ts_base; + } } void PCE_PSG::Power(const int32_t timestamp) diff --git a/src/engine/platform/sound/pce_psg.h b/src/engine/platform/sound/pce_psg.h index cdc6e0c99..8c72a7f12 100644 --- a/src/engine/platform/sound/pce_psg.h +++ b/src/engine/platform/sound/pce_psg.h @@ -25,6 +25,7 @@ #include #include "../../blip_buf.h" +#include "../../dispatch.h" class PCE_PSG; @@ -41,6 +42,7 @@ struct psg_channel int32_t counter; void (PCE_PSG::*UpdateOutput)(const int32_t timestamp, psg_channel *ch); + DivDispatchOscBuffer* oscBuf; uint32_t freq_cache; uint32_t noise_freq_cache; // Channel 4,5 only @@ -50,6 +52,7 @@ struct psg_channel int32_t samp_accum; // The result of adding up all the samples in the waveform buffer(part of an optimization for high-frequency playback). int32_t blip_prev_samp[2]; int32_t lastts; + int32_t lasttsbase; uint16_t frequency; /* Channel frequency */ uint8_t balance; /* Channel balance */ @@ -184,6 +187,7 @@ class PCE_PSG bool vol_pending; int32_t lastts; + int32_t lasttsbase; int revision; int32_t dbtable_volonly[32]; From 6e40a6980b1bfa5bb1fd2d117f3b891a18293c08 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 4 Mar 2025 12:57:59 -0500 Subject: [PATCH 6/6] PCE: fix chan osc! ready to merge... --- src/engine/dispatch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index e633ac822..5a1aac9f5 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -459,7 +459,7 @@ struct DivDispatchOscBuffer { //lastSample=val; data[pos]=val; }*/ - inline void begin(unsigned short len) { + inline void begin(size_t len) { size_t calc=(len*rateMul); unsigned short start=needle>>16; unsigned short end=(needle+calc)>>16; @@ -476,7 +476,7 @@ struct DivDispatchOscBuffer { memset(&data[start],-1,(end-start)*sizeof(short)); //data[needle>>16]=lastSample; } - inline void end(unsigned short len) { + inline void end(size_t len) { size_t calc=len*rateMul; needle+=calc; //data[needle>>16]=lastSample;