From e246697928c76f9a22814d15bde5c9cc88025295 Mon Sep 17 00:00:00 2001 From: cam900 Date: Sun, 1 May 2022 21:26:10 +0900 Subject: [PATCH] Prepare for per-channel osc view, ES550X core update --- src/engine/platform/es5506.cpp | 34 +++++++++++++++++++-- src/engine/platform/es5506.h | 9 +++++- src/engine/platform/sound/es550x/es5504.cpp | 10 +++++- src/engine/platform/sound/es550x/es5504.hpp | 9 ++++++ src/engine/platform/sound/es550x/es5505.cpp | 8 ++++- src/engine/platform/sound/es550x/es5505.hpp | 10 ++++++ src/engine/platform/sound/es550x/es5506.cpp | 8 ++++- src/engine/platform/sound/es550x/es5506.hpp | 10 ++++++ src/engine/platform/sound/es550x/es550x.cpp | 2 ++ src/engine/platform/sound/es550x/es550x.hpp | 15 +++++++++ src/gui/debug.cpp | 3 ++ 11 files changed, 112 insertions(+), 6 deletions(-) diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index 248bc24bf..180c0d3fb 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -162,14 +162,34 @@ void DivPlatformES5506::acquire(short* bufL, short* bufR, size_t start, size_t l } hostIntf32.pop(); } + prevChanCycle=es5506.voice_cycle(); es5506.tick_perf(); bufL[h]=es5506.lout(0); bufR[h]=es5506.rout(0); + for (int i=0; i<32; i++) { + oscBuf[i]->data[oscBuf[i]->needle++]=chan[i].oscOut; + } } } void DivPlatformES5506::e_pin(bool state) { + // get channel outputs + if (es5506.e_falling_edge()) { + if (es5506.voice_update()) { + chan[prevChanCycle].lOut=es5506.voice_lout(prevChanCycle); + chan[prevChanCycle].rOut=es5506.voice_rout(prevChanCycle); + chan[prevChanCycle].oscOut=(chan[prevChanCycle].lOut+chan[prevChanCycle].rOut)>>5; + if (es5506.voice_end()) { + if (prevChanCycle<31) { + for (int c=31; c>prevChanCycle; c--) { + chan[c].lOut=chan[c].rOut=chan[c].oscOut=0; + } + } + } + } + } + // host interface if (es5506.e_rising_edge()) { if (cycle) { // wait until delay cycle--; @@ -803,6 +823,7 @@ void DivPlatformES5506::reset() { isMasked=false; isReaded=false; irqTrigger=false; + prevChanCycle=0; chanMax=initChanMax; pageWriteMask(0x00,0x60,0x0b,chanMax); @@ -855,6 +876,10 @@ void DivPlatformES5506::poke(std::vector& wlist) { for (DivRegWrite& i: wlist) immWrite(i.addr,i.val); } +DivDispatchOscBuffer* DivPlatformES5506::getOscBuffer(int ch) { + return oscBuf[ch]; +} + unsigned char* DivPlatformES5506::getRegisterPool() { unsigned char* regPoolPtr = regPool; for (unsigned char p=0; p<128; p++) { @@ -877,16 +902,21 @@ int DivPlatformES5506::init(DivEngine* p, int channels, int sugRate, unsigned in dumpWrites=false; skipRegisterWrites=false; + chipClock=16000000; + rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice for (int i=0; i<32; i++) { isMuted[i]=false; + oscBuf[i]=new DivDispatchOscBuffer; + oscBuf[i]->rate=rate; } setFlags(flags); - chipClock=16000000; - rate=chipClock/16; // 2 E clock tick (16 CLKIN tick) per voice reset(); return 32; } void DivPlatformES5506::quit() { + for (int i=0; i<32; i++) { + delete oscBuf[i]; + } } diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 7066f06cd..d57a8234d 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -108,6 +108,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned int vol, lVol, rVol; unsigned int outVol, outLVol, outRVol; unsigned int resLVol, resRVol; + signed int lOut, rOut, oscOut; DivInstrumentES5506::Filter filter; DivInstrumentES5506::Envelope envelope; DivMacroInt std; @@ -148,9 +149,13 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { outLVol(0xffff), outRVol(0xffff), resLVol(0xffff), - resRVol(0xffff) {} + resRVol(0xffff), + lOut(0), + rOut(0), + oscOut(0) {} }; Channel chan[32]; + DivDispatchOscBuffer* oscBuf[32]; bool isMuted[32]; struct QueuedHostIntf { unsigned char step; @@ -184,6 +189,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { unsigned int irqv; bool isMasked, isReaded; bool irqTrigger; + unsigned char prevChanCycle; unsigned char initChanMax, chanMax; @@ -204,6 +210,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override; virtual int dispatch(DivCommand c) override; virtual void* getChanState(int chan) override; + virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; virtual unsigned char* getRegisterPool() override; virtual int getRegisterPoolSize() override; virtual void reset() override; diff --git a/src/engine/platform/sound/es550x/es5504.cpp b/src/engine/platform/sound/es550x/es5504.cpp index 00707d4f7..b7b808ac5 100644 --- a/src/engine/platform/sound/es550x/es5504.cpp +++ b/src/engine/platform/sound/es550x/es5504.cpp @@ -13,6 +13,8 @@ // Internal functions void es5504_core::tick() { + m_voice_update = false; + m_voice_end = false; // /CAS, E if (m_clkin.falling_edge()) // falling edge triggers /CAS, E clock { @@ -74,6 +76,8 @@ void es5504_core::tick() // less cycle accurate, but less CPU heavy routine void es5504_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // update // falling edge m_e.m_edge.set(false); @@ -102,7 +106,8 @@ void es5504_core::tick_perf() void es5504_core::voice_tick() { // Voice updates every 2 E clock cycle (= 1 CHSTRB cycle or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -111,7 +116,10 @@ void es5504_core::voice_tick() m_ch[m_voice[m_voice_cycle].m_cr.ca] = m_voice[m_voice_cycle].m_ch; if ((++m_voice_cycle) > std::min(24, m_active)) // ~ 25 voices + { + m_voice_end = true; m_voice_cycle = 0; + } m_voice_fetch = 0; } diff --git a/src/engine/platform/sound/es550x/es5504.hpp b/src/engine/platform/sound/es550x/es5504.hpp index f6743e18b..b9423dfc0 100644 --- a/src/engine/platform/sound/es550x/es5504.hpp +++ b/src/engine/platform/sound/es550x/es5504.hpp @@ -43,6 +43,12 @@ public: // 16 analog output channels s32 out(u8 ch) { return m_ch[ch & 0xf]; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u16 read(u8 address, bool cpu_access = false); void write(u8 address, u16 data, bool cpu_access = false); @@ -52,6 +58,9 @@ public: u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + // per-voice outputs + s32 voice_out(u8 voice) { return (voice < 25) ? m_voice[voice].m_ch : 0; } + protected: virtual inline u8 max_voices() override { return 25; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es5505.cpp b/src/engine/platform/sound/es550x/es5505.cpp index 0b460f773..7ab2321ea 100644 --- a/src/engine/platform/sound/es550x/es5505.cpp +++ b/src/engine/platform/sound/es550x/es5505.cpp @@ -13,6 +13,8 @@ // Internal functions void es5505_core::tick() { + m_voice_update = false; + m_voice_end = false; // CLKIN if (m_clkin.tick()) { @@ -131,6 +133,8 @@ void es5505_core::tick() // less cycle accurate, but less CPU heavy routine void es5505_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // output for (int c = 0; c < 4; c++) { @@ -166,7 +170,8 @@ void es5505_core::tick_perf() void es5505_core::voice_tick() { // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -174,6 +179,7 @@ void es5505_core::voice_tick() // Refresh output if ((++m_voice_cycle) > clamp(m_active, 7, 31)) // 8 ~ 32 voices { + m_voice_end = true; m_voice_cycle = 0; for (auto & elem : m_ch) elem.reset(); diff --git a/src/engine/platform/sound/es550x/es5505.hpp b/src/engine/platform/sound/es550x/es5505.hpp index 1803e7d8d..25c06beeb 100644 --- a/src/engine/platform/sound/es550x/es5505.hpp +++ b/src/engine/platform/sound/es550x/es5505.hpp @@ -52,6 +52,12 @@ public: s32 lout(u8 ch) { return m_ch[ch & 0x3].m_left; } s32 rout(u8 ch) { return m_ch[ch & 0x3].m_right; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u16 read(u8 address, bool cpu_access = false); void write(u8 address, u16 data, bool cpu_access = false); @@ -61,6 +67,10 @@ public: u16 regs_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u16 ret = read(address, false); m_page = prev; return ret; } + // per-voice outputs + s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } + s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } + protected: virtual inline u8 max_voices() override { return 32; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es5506.cpp b/src/engine/platform/sound/es550x/es5506.cpp index 85245f408..41f62b317 100644 --- a/src/engine/platform/sound/es550x/es5506.cpp +++ b/src/engine/platform/sound/es550x/es5506.cpp @@ -13,6 +13,8 @@ // Internal functions void es5506_core::tick() { + m_voice_update = false; + m_voice_end = false; // CLKIN if (m_clkin.tick()) { @@ -165,6 +167,8 @@ void es5506_core::tick() // less cycle accurate, but less CPU heavy routine void es5506_core::tick_perf() { + m_voice_update = false; + m_voice_end = false; // output if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.wclk_en)) && (m_w_st < m_w_end)) { @@ -215,7 +219,8 @@ void es5506_core::tick_perf() void es5506_core::voice_tick() { // Voice updates every 2 E clock cycle (or 4 BCLK clock cycle) - if (bitfield(m_voice_fetch++, 0)) + m_voice_update = bitfield(m_voice_fetch++, 0); + if (m_voice_update) { // Update voice m_voice[m_voice_cycle].tick(m_voice_cycle); @@ -223,6 +228,7 @@ void es5506_core::voice_tick() // Refresh output if ((++m_voice_cycle) > clamp(m_active, 4, 31)) // 5 ~ 32 voices { + m_voice_end = true; m_voice_cycle = 0; for (auto & elem : m_ch) elem.reset(); diff --git a/src/engine/platform/sound/es550x/es5506.hpp b/src/engine/platform/sound/es550x/es5506.hpp index f46941ed5..3940fea49 100644 --- a/src/engine/platform/sound/es550x/es5506.hpp +++ b/src/engine/platform/sound/es550x/es5506.hpp @@ -48,6 +48,12 @@ public: s32 lout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_left; } s32 rout(u8 ch) { return m_output[std::min(5, ch & 0x7)].m_right; } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + // bypass chips host interface for debug purpose only u8 read(u8 address, bool cpu_access = false); void write(u8 address, u8 data, bool cpu_access = false); @@ -58,6 +64,10 @@ public: u8 regs8_r(u8 page, u8 address) { u8 prev = m_page; m_page = page; u8 ret = read(address, false); m_page = prev; return ret; } void set_mute(u8 ch, bool mute) { m_voice[ch & 0x1f].m_mute = mute; } + // per-voice outputs + s32 voice_lout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_left : 0; } + s32 voice_rout(u8 voice) { return (voice < 32) ? m_voice[voice].m_ch.m_right : 0; } + protected: virtual inline u8 max_voices() override { return 32; } virtual void voice_tick() override; diff --git a/src/engine/platform/sound/es550x/es550x.cpp b/src/engine/platform/sound/es550x/es550x.cpp index 8047e1706..c65a1ea69 100644 --- a/src/engine/platform/sound/es550x/es550x.cpp +++ b/src/engine/platform/sound/es550x/es550x.cpp @@ -62,6 +62,8 @@ void es550x_shared_core::reset() m_active = max_voices() - 1; m_voice_cycle = 0; m_voice_fetch = 0; + m_voice_update = false; + m_voice_end = false; m_clkin.reset(); m_cas.reset(); m_e.reset(); diff --git a/src/engine/platform/sound/es550x/es550x.hpp b/src/engine/platform/sound/es550x/es550x.hpp index d1dae9e3d..52aba0f82 100644 --- a/src/engine/platform/sound/es550x/es550x.hpp +++ b/src/engine/platform/sound/es550x/es550x.hpp @@ -181,6 +181,19 @@ public: bool e_rising_edge() { return m_e.rising_edge(); } bool e_falling_edge() { return m_e.falling_edge(); } +//----------------------------------------------------------------- +// +// for preview/debug purpose only, not for serious emulators +// +//----------------------------------------------------------------- + + // voice cycle + u8 voice_cycle() { return m_voice_cycle; } + + // voice update flag + bool voice_update() { return m_voice_update; } + bool voice_end() { return m_voice_end; } + protected: // Constants virtual inline u8 max_voices() { return 32; } @@ -385,6 +398,8 @@ protected: u8 m_active = max_voices() - 1; // Activated voices (-1, ~25 for ES5504, ~32 for ES5505/ES5506) u8 m_voice_cycle = 0; // Voice cycle u8 m_voice_fetch = 0; // Voice fetch cycle + bool m_voice_update = false; // Voice update flag + bool m_voice_end = false; // End of one voice cycle flag es550x_intf &m_intf; // es550x specific memory interface clock_pulse_t m_clkin; // CLKIN clock clock_pulse_t m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index a3bcf4117..79fb1f397 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -375,6 +375,9 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- outRVol: %.2x",ch->outRVol); ImGui::Text("- ResLVol: %.2x",ch->resLVol); ImGui::Text("- ResRVol: %.2x",ch->resRVol); + ImGui::Text("- LOut: %d",ch->lOut); + ImGui::Text("- ROut: %d",ch->rOut); + ImGui::Text("- oscOut: %d",ch->oscOut); ImGui::TextColored(ch->active?colorOn:colorOff,">> Active"); ImGui::TextColored(ch->insChanged?colorOn:colorOff,">> InsChanged"); ImGui::TextColored(ch->freqChanged?colorOn:colorOff,">> FreqChanged");