NDS: acquireDirect()

it took a while

master volume may not work
This commit is contained in:
tildearrow 2025-03-08 18:42:19 -05:00
parent ce59a015e9
commit c9695caf35
4 changed files with 204 additions and 56 deletions

View file

@ -68,26 +68,39 @@ const char** DivPlatformNDS::getRegisterSheet() {
return regCheatSheetNDS; return regCheatSheetNDS;
} }
void DivPlatformNDS::acquire(short** buf, size_t len) { void DivPlatformNDS::acquireDirect(blip_buffer_t** bb, size_t len) {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
oscBuf[i]->begin(len); oscBuf[i]->begin(len);
} }
nds.set_bb(bb[0],bb[1]);
nds.set_oscbuf(oscBuf);
nds.resetTS(0);
nds.tick(len);
/*
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
nds.tick(coreQuality); int advance=len;//nds.predict();
//if (advance<1) advance=1;
//if (advance>(int)(len-h)) advance=len-h;
h+=advance-1;
int lout=((nds.loutput()-0x200)<<5); // scale to 16 bit int lout=((nds.loutput()-0x200)<<5); // scale to 16 bit
int rout=((nds.routput()-0x200)<<5); // scale to 16 bit int rout=((nds.routput()-0x200)<<5); // scale to 16 bit
if (lout>32767) lout=32767;
if (lout<-32768) lout=-32768; if (lastOut[0]!=lout) {
if (rout>32767) rout=32767; blip_add_delta(bb[0],h,lout-lastOut[0]);
if (rout<-32768) rout=-32768; lastOut[0]=lout;
buf[0][h]=lout; }
buf[1][h]=rout; if (lastOut[1]!=rout) {
blip_add_delta(bb[1],h,rout-lastOut[1]);
lastOut[1]=rout;
}
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
oscBuf[i]->putSample(h,(nds.chan_lout(i)+nds.chan_rout(i))>>1); oscBuf[i]->putSample(h,(nds.chan_lout(i)+nds.chan_rout(i))>>1);
} }
} }*/
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
oscBuf[i]->end(len); oscBuf[i]->end(len);
@ -453,6 +466,8 @@ void DivPlatformNDS::reset() {
memset(regPool,0,288); memset(regPool,0,288);
nds.reset(); nds.reset();
globalVolume=0x7f; globalVolume=0x7f;
lastOut[0]=0;
lastOut[1]=0;
rWrite32(0x100,0x8000|globalVolume); // enable keyon rWrite32(0x100,0x8000|globalVolume); // enable keyon
rWrite32(0x104,0x200); // initialize bias rWrite32(0x104,0x200); // initialize bias
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
@ -466,6 +481,10 @@ int DivPlatformNDS::getOutputCount() {
return 2; return 2;
} }
bool DivPlatformNDS::hasAcquireDirect() {
return true;
}
void DivPlatformNDS::notifyInsChange(int ins) { void DivPlatformNDS::notifyInsChange(int ins) {
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
if (chan[i].ins==ins) { if (chan[i].ins==ins) {
@ -570,7 +589,7 @@ void DivPlatformNDS::renderSamples(int sysID) {
void DivPlatformNDS::setFlags(const DivConfig& flags) { void DivPlatformNDS::setFlags(const DivConfig& flags) {
isDSi=flags.getBool("chipType",0); isDSi=flags.getBool("chipType",0);
chipClock=33513982; chipClock=33513982;
rate=chipClock/2/coreQuality; rate=chipClock/2;
for (int i=0; i<16; i++) { for (int i=0; i<16; i++) {
oscBuf[i]->setRate(rate); oscBuf[i]->setRate(rate);
} }

View file

@ -49,6 +49,7 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf {
bool isMuted[16]; bool isMuted[16];
bool isDSi; bool isDSi;
int globalVolume; int globalVolume;
int lastOut[2];
unsigned int sampleOff[256]; unsigned int sampleOff[256];
bool sampleLoaded[256]; bool sampleLoaded[256];
@ -65,7 +66,7 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf {
virtual u8 read_byte(u32 addr) override; virtual u8 read_byte(u32 addr) override;
virtual void write_byte(u32 addr, u8 data) override; virtual void write_byte(u32 addr, u8 data) override;
virtual void acquire(short** buf, size_t len) override; virtual void acquireDirect(blip_buffer_t** bb, size_t len) override;
virtual int dispatch(DivCommand c) override; virtual int dispatch(DivCommand c) override;
virtual void* getChanState(int chan) override; virtual void* getChanState(int chan) override;
virtual DivMacroInt* getChanMacroInt(int ch) override; virtual DivMacroInt* getChanMacroInt(int ch) override;
@ -79,6 +80,7 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf {
virtual void muteChannel(int ch, bool mute) override; virtual void muteChannel(int ch, bool mute) override;
virtual float getPostAmp() override; virtual float getPostAmp() override;
virtual int getOutputCount() override; virtual int getOutputCount() override;
virtual bool hasAcquireDirect() override;
virtual void notifyInsChange(int ins) override; virtual void notifyInsChange(int ins) override;
virtual void notifyWaveChange(int wave) override; virtual void notifyWaveChange(int wave) override;
virtual void notifyInsDeletion(void* ins) override; virtual void notifyInsDeletion(void* ins) override;

View file

@ -5,6 +5,17 @@
NDS sound emulator NDS sound emulator
by cam900 by cam900
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
making it SUPER CLEAR to comply with the license
this is NOT the original version! for the original version, git checkout
any commit from January 2025.
This file is licensed under zlib license. This file is licensed under zlib license.
============================================================================ ============================================================================
@ -64,6 +75,25 @@ namespace nds_sound_emu
return ret; return ret;
} }
void nds_sound_t::resetTS(u32 what) {
m_lastts = what;
for (u8 i = 0; i < 16; i++) {
m_channel[i].resetTS(m_lastts);
}
}
void nds_sound_t::set_bb(blip_buffer_t* bbLeft, blip_buffer_t* bbRight) {
for (u8 i = 0; i < 16; i++) {
m_channel[i].set_bb(bbLeft,bbRight);
}
}
void nds_sound_t::set_oscbuf(DivDispatchOscBuffer** oscBuf) {
for (u8 i = 0; i < 16; i++) {
m_channel[i].set_oscbuf(oscBuf[i]);
}
}
void nds_sound_t::tick(s32 cycle) void nds_sound_t::tick(s32 cycle)
{ {
m_loutput = m_routput = (m_bias & 0x3ff); m_loutput = m_routput = (m_bias & 0x3ff);
@ -76,14 +106,18 @@ namespace nds_sound_emu
{ {
channel_t &channel = m_channel[i]; channel_t &channel = m_channel[i];
channel.update(cycle); channel.update(cycle);
/*
// bypass mixer // bypass mixer
if (((i == 1) && (mix_ch1())) || ((i == 3) && (mix_ch3()))) if (((i == 1) && (mix_ch1())) || ((i == 3) && (mix_ch3())))
continue; continue;
lmix += channel.loutput(); lmix += channel.loutput();
rmix += channel.routput(); rmix += channel.routput();
*/
} }
return; // don't care about the rest
// send mixer output to capture // send mixer output to capture
m_capture[0].update(lmix, cycle); m_capture[0].update(lmix, cycle);
m_capture[1].update(rmix, cycle); m_capture[1].update(rmix, cycle);
@ -231,6 +265,15 @@ namespace nds_sound_emu
m_loopstart = 0; m_loopstart = 0;
m_length = 0; m_length = 0;
m_ctl_volume = 0;
m_ctl_voldiv = 0;
m_ctl_hold = 0;
m_ctl_pan = 0;
m_ctl_duty = 0;
m_ctl_repeat = 0;
m_ctl_format = 0;
m_ctl_busy = 0;
m_playing = false; m_playing = false;
m_adpcm_out = 0; m_adpcm_out = 0;
m_adpcm_index = 0; m_adpcm_index = 0;
@ -256,15 +299,26 @@ namespace nds_sound_emu
{ {
case 0: // Control/Status case 0: // Control/Status
m_control = (m_control & ~mask) | (data & mask); m_control = (m_control & ~mask) | (data & mask);
// explode this register
m_ctl_volume = bitfield(m_control, 0, 7);
m_ctl_voldiv = m_voldiv_shift[bitfield(m_control, 8, 2)];
m_ctl_hold = bitfield(m_control, 15);
m_ctl_pan = bitfield(m_control, 16, 7);
m_ctl_duty = bitfield(m_control, 24, 3);
m_ctl_repeat = bitfield(m_control, 27, 2);
m_ctl_format = bitfield(m_control, 29, 2);
m_ctl_busy = bitfield(m_control, 31);
if (bitfield(old ^ m_control, 31)) if (bitfield(old ^ m_control, 31))
{ {
if (busy()) if (m_ctl_busy)
keyon(); keyon();
else if (!busy()) else if (!m_ctl_busy)
keyoff(); keyoff();
} }
// reset hold flag // reset hold flag
if (!m_playing && !hold()) if (!m_playing && !m_ctl_hold)
{ {
m_sample = m_lfsr_out = 0; m_sample = m_lfsr_out = 0;
m_output = m_loutput = m_routput = 0; m_output = m_loutput = m_routput = 0;
@ -292,9 +346,9 @@ namespace nds_sound_emu
if (!m_playing) if (!m_playing)
{ {
m_playing = true; m_playing = true;
m_delay = format() == 2 ? 11 : 3; // 3 (11 for ADPCM) delay for playing sample m_delay = m_ctl_format == 2 ? 11 : 3; // 3 (11 for ADPCM) delay for playing sample
m_cur_bitaddr = m_cur_addr = 0; m_cur_bitaddr = m_cur_addr = 0;
m_cur_state = (format() == 2) ? STATE_ADPCM_LOAD : ((m_loopstart == 0) ? STATE_POST_LOOP : STATE_PRE_LOOP); m_cur_state = (m_ctl_format == 2) ? STATE_ADPCM_LOAD : ((m_loopstart == 0) ? STATE_POST_LOOP : STATE_PRE_LOOP);
m_counter = 0x10000; m_counter = 0x10000;
m_sample = 0; m_sample = 0;
m_lfsr_out = 0x7fff; m_lfsr_out = 0x7fff;
@ -307,9 +361,11 @@ namespace nds_sound_emu
{ {
if (m_playing) if (m_playing)
{ {
if (busy()) if (m_ctl_busy) {
m_control &= ~(1 << 31); m_control &= ~(1 << 31);
if (!hold()) m_ctl_busy = false;
}
if (!m_ctl_hold)
{ {
m_sample = m_lfsr_out = 0; m_sample = m_lfsr_out = 0;
m_output = m_loutput = m_routput = 0; m_output = m_loutput = m_routput = 0;
@ -319,27 +375,48 @@ namespace nds_sound_emu
} }
} }
void nds_sound_t::channel_t::update(s32 cycle) // sorry. I need my spaces back.
void nds_sound_t::channel_t::update(s32 timestamp)
{ {
if (m_playing) if (m_playing)
{ {
for (s32 i=m_lastts; i<timestamp; i++) {
int cycle = m_counter - m_freq;
if (cycle>timestamp-i) cycle=timestamp-i;
if (cycle<1) cycle=1;
// get output // get output
fetch();
m_counter -= cycle; m_counter -= cycle;
while (m_counter <= m_freq) while (m_counter <= m_freq)
{ {
// advance // advance
fetch();
advance(); advance();
m_counter += 0x10000 - m_freq; m_counter += 0x10000 - m_freq;
} }
m_output = (m_sample * volume()) >> (7 + voldiv()); m_output = (m_sample * m_ctl_volume) >> (7 + m_ctl_voldiv);
m_loutput = (m_output * lvol()) >> 7; const s32 loutput = (m_output * lvol()) >> 7;
m_routput = (m_output * rvol()) >> 7; const s32 routput = (m_output * rvol()) >> 7;
i+=cycle-1;
if (m_loutput!=loutput) {
blip_add_delta(m_bb[0],i,m_loutput-loutput);
m_loutput=loutput;
} }
if (m_routput!=routput) {
blip_add_delta(m_bb[1],i,m_routput-routput);
m_routput=routput;
}
m_oscBuf->putSample(i,(loutput+routput)>>1);
}
}
m_lastts = timestamp;
} }
s32 nds_sound_t::channel_t::predict() { s32 nds_sound_t::channel_t::predict() {
if (!m_playing) return INT32_MAX; if (!m_playing) return INT32_MAX;
if (!(m_ctl_volume)) return INT32_MAX;
return m_counter-m_freq; return m_counter-m_freq;
} }
@ -348,7 +425,7 @@ namespace nds_sound_emu
if (m_playing) if (m_playing)
{ {
// fetch samples // fetch samples
switch (format()) switch (m_ctl_format)
{ {
case 0: // PCM8 case 0: // PCM8
m_sample = s16(m_host.m_intf.read_byte(addr()) << 8); m_sample = s16(m_host.m_intf.read_byte(addr()) << 8);
@ -362,7 +439,7 @@ namespace nds_sound_emu
case 3: // PSG or Noise case 3: // PSG or Noise
m_sample = 0; m_sample = 0;
if (m_psg) // psg if (m_psg) // psg
m_sample = (duty() == 7) ? -0x7fff : ((m_cur_bitaddr < s32(u32(7) - duty())) ? -0x7fff : 0x7fff); m_sample = (m_ctl_duty == 7) ? -0x7fff : ((m_cur_bitaddr < s32(u32(7) - m_ctl_duty)) ? -0x7fff : 0x7fff);
else if (m_noise) // noise else if (m_noise) // noise
m_sample = m_lfsr_out; m_sample = m_lfsr_out;
break; break;
@ -370,7 +447,7 @@ namespace nds_sound_emu
} }
// apply delay // apply delay
if (format() != 3 && m_delay > 0) if (m_ctl_format != 3 && m_delay > 0)
m_sample = 0; m_sample = 0;
} }
@ -379,7 +456,7 @@ namespace nds_sound_emu
if (m_playing) if (m_playing)
{ {
// advance bit address // advance bit address
switch (format()) switch (m_ctl_format)
{ {
case 0: // PCM8 case 0: // PCM8
m_cur_bitaddr += 8; m_cur_bitaddr += 8;
@ -425,7 +502,7 @@ namespace nds_sound_emu
} }
// address update // address update
if (format() != 3) if (m_ctl_format != 3)
{ {
// adjust delay // adjust delay
m_delay--; m_delay--;
@ -434,7 +511,7 @@ namespace nds_sound_emu
while (m_cur_bitaddr >= 32) while (m_cur_bitaddr >= 32)
{ {
// already loaded? // already loaded?
if (format() == 2 && m_cur_state == STATE_ADPCM_LOAD) if (m_ctl_format == 2 && m_cur_state == STATE_ADPCM_LOAD)
{ {
m_cur_state = m_loopstart == 0 ? STATE_POST_LOOP : STATE_PRE_LOOP; m_cur_state = m_loopstart == 0 ? STATE_POST_LOOP : STATE_PRE_LOOP;
} }
@ -443,7 +520,7 @@ namespace nds_sound_emu
{ {
m_cur_state = STATE_POST_LOOP; m_cur_state = STATE_POST_LOOP;
m_cur_addr = 0; m_cur_addr = 0;
if (format() == 2) if (m_ctl_format == 2)
{ {
m_prev_adpcm_out = m_adpcm_out; m_prev_adpcm_out = m_adpcm_out;
m_prev_adpcm_index = m_adpcm_index; m_prev_adpcm_index = m_adpcm_index;
@ -451,7 +528,7 @@ namespace nds_sound_emu
} }
else if (m_cur_state == STATE_POST_LOOP && m_cur_addr >= m_length) else if (m_cur_state == STATE_POST_LOOP && m_cur_addr >= m_length)
{ {
switch (repeat()) switch (m_ctl_repeat)
{ {
case 0: // manual; not correct? case 0: // manual; not correct?
case 2: // one-shot case 2: // one-shot
@ -459,7 +536,7 @@ namespace nds_sound_emu
keyoff(); keyoff();
break; break;
case 1: // loop infinitely case 1: // loop infinitely
if (format() == 2) if (m_ctl_format == 2)
{ {
if (m_loopstart == 0) // reload ADPCM if (m_loopstart == 0) // reload ADPCM
{ {

View file

@ -5,6 +5,17 @@
NDS sound emulator NDS sound emulator
by cam900 by cam900
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
MODIFIED BY TILDEARROW!!!
making it SUPER CLEAR to comply with the license
this is NOT the original version! for the original version, git checkout
any commit from January 2025.
This file is licensed under zlib license. This file is licensed under zlib license.
============================================================================ ============================================================================
@ -40,6 +51,10 @@ Tech info: https://problemkaputt.de/gbatek.htm
#ifndef NDS_SOUND_EMU_H #ifndef NDS_SOUND_EMU_H
#define NDS_SOUND_EMU_H #define NDS_SOUND_EMU_H
#include <stdlib.h>
#include "blip_buf.h"
#include "../../dispatch.h"
namespace nds_sound_emu namespace nds_sound_emu
{ {
using u8 = unsigned char; using u8 = unsigned char;
@ -116,12 +131,16 @@ namespace nds_sound_emu
, m_bias(0) , m_bias(0)
, m_loutput(0) , m_loutput(0)
, m_routput(0) , m_routput(0)
, m_lastts(0)
{ {
} }
void reset(); void reset();
void resetTS(u32 what);
void tick(s32 cycle); void tick(s32 cycle);
s32 predict(); s32 predict();
void set_bb(blip_buffer_t* bbLeft, blip_buffer_t* bbRight);
void set_oscbuf(DivDispatchOscBuffer** oscBuf);
// host accesses // host accesses
u32 read32(u32 addr); u32 read32(u32 addr);
@ -178,11 +197,22 @@ namespace nds_sound_emu
, m_psg(psg) , m_psg(psg)
, m_noise(noise) , m_noise(noise)
, m_bb{NULL,NULL}
, m_oscBuf(NULL)
, m_control(0) , m_control(0)
, m_sourceaddr(0) , m_sourceaddr(0)
, m_freq(0) , m_freq(0)
, m_loopstart(0) , m_loopstart(0)
, m_length(0) , m_length(0)
, m_ctl_volume(0)
, m_ctl_voldiv(0)
, m_ctl_hold(0)
, m_ctl_pan(0)
, m_ctl_duty(0)
, m_ctl_repeat(0)
, m_ctl_format(0)
, m_ctl_busy(0)
, m_playing(false) , m_playing(false)
, m_adpcm_out(0) , m_adpcm_out(0)
, m_adpcm_index(0) , m_adpcm_index(0)
@ -199,6 +229,7 @@ namespace nds_sound_emu
, m_output(0) , m_output(0)
, m_loutput(0) , m_loutput(0)
, m_routput(0) , m_routput(0)
, m_lastts(0)
{ {
} }
@ -206,6 +237,9 @@ namespace nds_sound_emu
void write(u32 offset, u32 data, u32 mask = ~0); void write(u32 offset, u32 data, u32 mask = ~0);
void update(s32 cycle); void update(s32 cycle);
void set_bb(blip_buffer_t* bbLeft, blip_buffer_t* bbRight) { m_bb[0] = bbLeft; m_bb[1] = bbRight; }
void set_oscbuf(DivDispatchOscBuffer* oscBuf) { m_oscBuf = oscBuf; }
void resetTS(u32 what) { m_lastts = what; }
s32 predict(); s32 predict();
// getters // getters
@ -223,18 +257,18 @@ namespace nds_sound_emu
const u8 m_voldiv_shift[4] = {0, 1, 2, 4}; const u8 m_voldiv_shift[4] = {0, 1, 2, 4};
// control bits // control bits
s32 volume() const { return bitfield(m_control, 0, 7); } // global volume s32 volume() const { return m_ctl_volume; } // global volume
u32 voldiv() const { return m_voldiv_shift[bitfield(m_control, 8, 2)]; } // volume shift u32 voldiv() const { return m_ctl_voldiv; } // volume shift
bool hold() const { return bitfield(m_control, 15); } // hold bit bool hold() const { return m_ctl_hold; } // hold bit
u32 pan() const { return bitfield(m_control, 16, 7); } // panning (0...127, 0 = left, 127 = right, 64 = half) u32 pan() const { return m_ctl_pan; } // panning (0...127, 0 = left, 127 = right, 64 = half)
u32 duty() const { return bitfield(m_control, 24, 3); } // PSG duty u32 duty() const { return m_ctl_duty; } // PSG duty
u32 repeat() const { return bitfield(m_control, 27, 2); } // Repeat mode (Manual, Loop infinitely, One-shot) u32 repeat() const { return m_ctl_repeat; } // Repeat mode (Manual, Loop infinitely, One-shot)
u32 format() const { return bitfield(m_control, 29, 2); } // Sound Format (PCM8, PCM16, ADPCM, PSG/Noise when exists) u32 format() const { return m_ctl_format; } // Sound Format (PCM8, PCM16, ADPCM, PSG/Noise when exists)
bool busy() const { return bitfield(m_control, 31); } // Busy flag bool busy() const { return m_ctl_busy; } // Busy flag
// calculated values // calculated values
s32 lvol() const { return (pan() == 0x7f) ? 0 : 128 - pan(); } // calculated left volume s32 lvol() const { return (m_ctl_pan == 0x7f) ? 0 : 128 - m_ctl_pan; } // calculated left volume
s32 rvol() const { return (pan() == 0x7f) ? 128 : pan(); } // calculated right volume s32 rvol() const { return (m_ctl_pan == 0x7f) ? 128 : m_ctl_pan; } // calculated right volume
// calculated address // calculated address
u32 addr() const { return (m_sourceaddr & ~3) + (m_cur_bitaddr >> 3) + (m_cur_state == STATE_POST_LOOP ? ((m_loopstart + m_cur_addr) << 2) : (m_cur_addr << 2)); } u32 addr() const { return (m_sourceaddr & ~3) + (m_cur_bitaddr >> 3) + (m_cur_state == STATE_POST_LOOP ? ((m_loopstart + m_cur_addr) << 2) : (m_cur_addr << 2)); }
@ -251,6 +285,10 @@ namespace nds_sound_emu
bool m_psg = false; // PSG Enable bool m_psg = false; // PSG Enable
bool m_noise = false; // Noise Enable bool m_noise = false; // Noise Enable
// blip_buf
blip_buffer_t* m_bb[2];
DivDispatchOscBuffer* m_oscBuf;
// registers // registers
u32 m_control = 0; // Control u32 m_control = 0; // Control
u32 m_sourceaddr = 0; // Source Address u32 m_sourceaddr = 0; // Source Address
@ -258,6 +296,16 @@ namespace nds_sound_emu
u16 m_loopstart = 0; // Loop Start u16 m_loopstart = 0; // Loop Start
u32 m_length = 0; // Length u32 m_length = 0; // Length
// exploded control
s32 m_ctl_volume = 0; // Volume (0-6)
u32 m_ctl_voldiv = 0; // Volume Shift (8-9)
bool m_ctl_hold = 0; // Hold (15)
u32 m_ctl_pan = 0; // Panning (16-22)
u32 m_ctl_duty = 0; // Duty (24-26)
u32 m_ctl_repeat = 0; // Repeat Mode (27-28)
u32 m_ctl_format = 0; // Sound Format (29-30)
bool m_ctl_busy = 0; // Busy Flag (31)
// internal states // internal states
bool m_playing = false; // playing flag bool m_playing = false; // playing flag
s32 m_adpcm_out = 0; // current ADPCM sample value s32 m_adpcm_out = 0; // current ADPCM sample value
@ -275,6 +323,7 @@ namespace nds_sound_emu
s32 m_output = 0; // current output s32 m_output = 0; // current output
s32 m_loutput = 0; // current left output s32 m_loutput = 0; // current left output
s32 m_routput = 0; // current right output s32 m_routput = 0; // current right output
u32 m_lastts = 0; // running timestamp
}; };
class capture_t class capture_t
@ -411,6 +460,7 @@ namespace nds_sound_emu
u32 m_bias = 0; // output bias u32 m_bias = 0; // output bias
s32 m_loutput = 0; // left output s32 m_loutput = 0; // left output
s32 m_routput = 0; // right output s32 m_routput = 0; // right output
u32 m_lastts = 0; // running timestamp
}; };
}; // namespace nds_sound_emu }; // namespace nds_sound_emu