VRC6: acquireDirect()

to-do: check for regressions? I need to sleep
This commit is contained in:
tildearrow 2025-03-07 06:28:03 -05:00
parent 0efe232ae8
commit 229003c597
4 changed files with 83 additions and 34 deletions

View file

@ -8,15 +8,27 @@
#include "vrcvi.hpp" #include "vrcvi.hpp"
void vrcvi_core::tick() int vrcvi_core::predict() {
const int p0=m_pulse[0].predict();
const int p1=m_pulse[1].predict();
const int s=m_sawtooth.predict();
int ret=p0;
if (p1<ret) ret=p1;
if (s<ret) ret=s;
if (ret<1) ret=1;
return ret;
}
void vrcvi_core::tick(int cycles)
{ {
m_out = 0; m_out = 0;
if (!m_control.m_halt) // Halt flag if (!m_control.m_halt) // Halt flag
{ {
// tick per each clock // tick per each clock
m_out += m_pulse[0].get_output(); // add 4 bit pulse output m_out += m_pulse[0].get_output(cycles); // add 4 bit pulse output
m_out += m_pulse[1].get_output(); m_out += m_pulse[1].get_output(cycles);
m_out += m_sawtooth.get_output(); // add 5 bit sawtooth output m_out += m_sawtooth.get_output(cycles); // add 5 bit sawtooth output
} }
} }
@ -30,7 +42,18 @@ void vrcvi_core::reset()
m_out = 0; m_out = 0;
} }
bool vrcvi_core::alu_t::tick() int vrcvi_core::alu_t::predict() {
if (!m_divider.m_enable) return 65535;
if (m_host.m_control.m_shift&2) {
return bitfield(m_counter, 8, 4);
} else if (m_host.m_control.m_shift&1) {
return bitfield(m_counter, 4, 8);
}
return m_counter&0xfff;
}
bool vrcvi_core::alu_t::tick(int cycles)
{ {
if (m_divider.m_enable) if (m_divider.m_enable)
{ {
@ -38,8 +61,8 @@ bool vrcvi_core::alu_t::tick()
// post decrement // post decrement
if (m_host.m_control.m_shift&2) if (m_host.m_control.m_shift&2)
{ {
m_counter = (m_counter & 0x0ff) | (bitfield(bitfield(m_counter, 8, 4) - 1, 0, 4) << 8); m_counter = (m_counter & 0x0ff) | (bitfield(bitfield(m_counter, 8, 4) - cycles, 0, 4) << 8);
m_counter = (m_counter & 0xf00) | (bitfield(bitfield(m_counter, 0, 8) - 1, 0, 8) << 0); m_counter = (m_counter & 0xf00) | (bitfield(bitfield(m_counter, 0, 8) - cycles, 0, 8) << 0);
if (bitfield(temp, 8, 4) == 0) if (bitfield(temp, 8, 4) == 0)
{ {
@ -49,8 +72,8 @@ bool vrcvi_core::alu_t::tick()
} }
else if (m_host.m_control.m_shift&1) else if (m_host.m_control.m_shift&1)
{ {
m_counter = (m_counter & 0x00f) | (bitfield(bitfield(m_counter, 4, 8) - 1, 0, 8) << 4); m_counter = (m_counter & 0x00f) | (bitfield(bitfield(m_counter, 4, 8) - cycles, 0, 8) << 4);
m_counter = (m_counter & 0xff0) | (bitfield(bitfield(m_counter, 0, 4) - 1, 0, 4) << 0); m_counter = (m_counter & 0xff0) | (bitfield(bitfield(m_counter, 0, 4) - cycles, 0, 4) << 0);
if (bitfield(temp, 4, 8) == 0) if (bitfield(temp, 4, 8) == 0)
{ {
@ -60,7 +83,7 @@ bool vrcvi_core::alu_t::tick()
} }
else else
{ {
m_counter = (m_counter-1)&0xfff; //bitfield(bitfield(m_counter, 0, 12) - 1, 0, 12); m_counter = (m_counter-cycles)&0xfff; //bitfield(bitfield(m_counter, 0, 12) - 1, 0, 12);
if (!(temp&0xfff)) { if (!(temp&0xfff)) {
m_counter = m_divider.m_divider; m_counter = m_divider.m_divider;
return true; return true;
@ -72,14 +95,14 @@ bool vrcvi_core::alu_t::tick()
return false; return false;
} }
bool vrcvi_core::pulse_t::tick() bool vrcvi_core::pulse_t::tick(int cycles)
{ {
if (!m_divider.m_enable) if (!m_divider.m_enable)
{ {
return false; return false;
} }
if (vrcvi_core::alu_t::tick()) if (vrcvi_core::alu_t::tick(cycles))
{ {
m_cycle = (m_cycle+1)&15; m_cycle = (m_cycle+1)&15;
} }
@ -87,14 +110,14 @@ bool vrcvi_core::pulse_t::tick()
return m_control.m_mode ? true : ((m_cycle > m_control.m_duty) ? true : false); return m_control.m_mode ? true : ((m_cycle > m_control.m_duty) ? true : false);
} }
bool vrcvi_core::sawtooth_t::tick() bool vrcvi_core::sawtooth_t::tick(int cycles)
{ {
if (!m_divider.m_enable) if (!m_divider.m_enable)
{ {
return false; return false;
} }
if (vrcvi_core::alu_t::tick()) if (vrcvi_core::alu_t::tick(cycles))
{ {
if ((m_cycle++)&1) if ((m_cycle++)&1)
{ // Even step only { // Even step only
@ -109,23 +132,24 @@ bool vrcvi_core::sawtooth_t::tick()
return (m_accum != 0); return (m_accum != 0);
} }
s8 vrcvi_core::pulse_t::get_output() s8 vrcvi_core::pulse_t::get_output(int cycles)
{ {
// add 4 bit pulse output // add 4 bit pulse output
m_out = tick() ? m_control.m_volume : 0; m_out = tick(cycles) ? m_control.m_volume : 0;
return m_out; return m_out;
} }
s8 vrcvi_core::sawtooth_t::get_output() s8 vrcvi_core::sawtooth_t::get_output(int cycles)
{ {
// add 5 bit sawtooth output // add 5 bit sawtooth output
m_out = tick() ? ((m_accum>>3)&31) : 0; m_out = tick(cycles) ? ((m_accum>>3)&31) : 0;
return m_out; return m_out;
} }
void vrcvi_core::alu_t::reset() void vrcvi_core::alu_t::reset()
{ {
m_divider.reset(); m_divider.reset();
m_divider.m_divider = 1023;
m_counter = 0; m_counter = 0;
m_cycle = 0; m_cycle = 0;
m_out = 0; m_out = 0;
@ -135,6 +159,7 @@ void vrcvi_core::pulse_t::reset()
{ {
vrcvi_core::alu_t::reset(); vrcvi_core::alu_t::reset();
m_control.reset(); m_control.reset();
m_divider.m_divider = 1023;
} }
void vrcvi_core::sawtooth_t::reset() void vrcvi_core::sawtooth_t::reset()
@ -142,6 +167,7 @@ void vrcvi_core::sawtooth_t::reset()
vrcvi_core::alu_t::reset(); vrcvi_core::alu_t::reset();
m_rate = 0; m_rate = 0;
m_accum = 0; m_accum = 0;
m_divider.m_divider = 1023;
} }
bool vrcvi_core::timer_t::tick() bool vrcvi_core::timer_t::tick()

View file

@ -47,7 +47,7 @@ class vrcvi_core : public vgsound_emu_core
void reset() void reset()
{ {
m_divider = 0; m_divider = 1023;
m_enable = 0; m_enable = 0;
} }
@ -75,9 +75,10 @@ class vrcvi_core : public vgsound_emu_core
} }
virtual void reset(); virtual void reset();
virtual bool tick(); virtual bool tick(int cycles);
virtual int predict();
virtual s8 get_output() virtual s8 get_output(int cycles)
{ {
m_out = 0; m_out = 0;
return 0; return 0;
@ -155,8 +156,8 @@ class vrcvi_core : public vgsound_emu_core
} }
virtual void reset() override; virtual void reset() override;
virtual bool tick() override; virtual bool tick(int cycles) override;
virtual s8 get_output() override; virtual s8 get_output(int cycles) override;
// getters // getters
pulse_control_t &control() { return m_control; } pulse_control_t &control() { return m_control; }
@ -177,8 +178,8 @@ class vrcvi_core : public vgsound_emu_core
} }
virtual void reset() override; virtual void reset() override;
virtual bool tick() override; virtual bool tick(int cycles) override;
virtual s8 get_output() override; virtual s8 get_output(int cycles) override;
// accessors // accessors
inline void clear_accum() { m_accum = 0; } inline void clear_accum() { m_accum = 0; }
@ -385,7 +386,8 @@ class vrcvi_core : public vgsound_emu_core
// internal state // internal state
void reset(); void reset();
void tick(); int predict();
void tick(int cycles=1);
// 6 bit output // 6 bit output
inline s8 out() { return m_out; } inline s8 out() { return m_out; }

View file

@ -46,16 +46,28 @@ const char** DivPlatformVRC6::getRegisterSheet() {
return regCheatSheetVRC6; return regCheatSheetVRC6;
} }
void DivPlatformVRC6::acquire(short** buf, size_t len) { void DivPlatformVRC6::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);
} }
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
// running heuristic
int advance=vrc6.predict();
if ((int)(len-h)<advance) advance=len-h;
for (int i=0; i<2; i++) {
if (chan[i].pcm && chan[i].dacSample!=-1) {
if (chan[i].dacRate<=0) continue;
int remainTime=(rate-chan[i].dacPeriod+chan[i].dacRate-1)/chan[i].dacRate;
if (remainTime<advance) advance=remainTime;
if (remainTime<1) advance=1;
}
}
// PCM part // PCM part
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
if (chan[i].pcm && chan[i].dacSample!=-1) { if (chan[i].pcm && chan[i].dacSample!=-1) {
chan[i].dacPeriod+=chan[i].dacRate; chan[i].dacPeriod+=chan[i].dacRate*advance;
if (chan[i].dacPeriod>rate) { if (chan[i].dacPeriod>rate) {
DivSample* s=parent->getSample(chan[i].dacSample); DivSample* s=parent->getSample(chan[i].dacSample);
if (s->samples<=0 || chan[i].dacPos>=s->samples) { if (s->samples<=0 || chan[i].dacPos>=s->samples) {
@ -81,11 +93,13 @@ void DivPlatformVRC6::acquire(short** buf, size_t len) {
} }
// VRC6 part // VRC6 part
vrc6.tick(); vrc6.tick(advance);
h+=advance-1;
int sample=vrc6.out()<<9; // scale to 16 bit int sample=vrc6.out()<<9; // scale to 16 bit
if (sample>32767) sample=32767; if (sample!=prevSample) {
if (sample<-32768) sample=-32768; blip_add_delta(bb[0],h,sample-prevSample);
buf[0][h]=sample; prevSample=sample;
}
// Oscilloscope buffer part // Oscilloscope buffer part
if (++writeOscBuf>=32) { if (++writeOscBuf>=32) {
@ -96,7 +110,7 @@ void DivPlatformVRC6::acquire(short** buf, size_t len) {
oscBuf[2]->putSample(h,vrc6.sawtooth_out()<<10); oscBuf[2]->putSample(h,vrc6.sawtooth_out()<<10);
} }
// Command part // Command part (what the heck why at the END?!)
while (!writes.empty()) { while (!writes.empty()) {
QueuedWrite w=writes.front(); QueuedWrite w=writes.front();
switch (w.addr&0xf000) { switch (w.addr&0xf000) {
@ -523,6 +537,7 @@ void DivPlatformVRC6::reset() {
} }
sampleBank=0; sampleBank=0;
prevSample=0;
vrc6.reset(); vrc6.reset();
// Initialize control register // Initialize control register
@ -537,6 +552,10 @@ bool DivPlatformVRC6::keyOffAffectsArp(int ch) {
return true; return true;
} }
bool DivPlatformVRC6::hasAcquireDirect() {
return true;
}
void DivPlatformVRC6::setFlags(const DivConfig& flags) { void DivPlatformVRC6::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

@ -57,13 +57,14 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf {
unsigned char sampleBank; unsigned char sampleBank;
unsigned char writeOscBuf; unsigned char writeOscBuf;
vrcvi_core vrc6; vrcvi_core vrc6;
int prevSample;
unsigned char regPool[13]; unsigned char regPool[13];
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
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);
@ -76,6 +77,7 @@ class DivPlatformVRC6: public DivDispatch, public vrcvi_intf {
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();
void setFlags(const DivConfig& flags); void setFlags(const DivConfig& flags);
void notifyInsDeletion(void* ins); void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val); void poke(unsigned int addr, unsigned short val);