Prepare for per-channel osc view, ES550X core update

This commit is contained in:
cam900 2022-05-01 21:26:10 +09:00
parent 329048bf6c
commit e246697928
11 changed files with 112 additions and 6 deletions

View File

@ -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<DivRegWrite>& 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];
}
}

View File

@ -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;

View File

@ -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<u8>(24, m_active)) // ~ 25 voices
{
m_voice_end = true;
m_voice_cycle = 0;
}
m_voice_fetch = 0;
}

View File

@ -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;

View File

@ -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<u8>(m_active, 7, 31)) // 8 ~ 32 voices
{
m_voice_end = true;
m_voice_cycle = 0;
for (auto & elem : m_ch)
elem.reset();

View File

@ -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;

View File

@ -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<u8>(m_active, 4, 31)) // 5 ~ 32 voices
{
m_voice_end = true;
m_voice_cycle = 0;
for (auto & elem : m_ch)
elem.reset();

View File

@ -48,6 +48,12 @@ public:
s32 lout(u8 ch) { return m_output[std::min<u8>(5, ch & 0x7)].m_left; }
s32 rout(u8 ch) { return m_output[std::min<u8>(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;

View File

@ -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();

View File

@ -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<s8, 1, 0> m_clkin; // CLKIN clock
clock_pulse_t<s8, 2, 1> m_cas; // /CAS clock (CLKIN / 4), falling edge of CLKIN trigger this clock

View File

@ -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");