From c9695caf35cc12797846bfa774eb4548fdc6250d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 8 Mar 2025 18:42:19 -0500 Subject: [PATCH] NDS: acquireDirect() it took a while master volume may not work --- src/engine/platform/nds.cpp | 39 ++++++--- src/engine/platform/nds.h | 4 +- src/engine/platform/sound/nds.cpp | 141 +++++++++++++++++++++++------- src/engine/platform/sound/nds.hpp | 76 +++++++++++++--- 4 files changed, 204 insertions(+), 56 deletions(-) diff --git a/src/engine/platform/nds.cpp b/src/engine/platform/nds.cpp index 98611ad62..91acdc38a 100644 --- a/src/engine/platform/nds.cpp +++ b/src/engine/platform/nds.cpp @@ -68,26 +68,39 @@ const char** DivPlatformNDS::getRegisterSheet() { 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++) { 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(int)(len-h)) advance=len-h; + + h+=advance-1; + int lout=((nds.loutput()-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 (rout>32767) rout=32767; - if (rout<-32768) rout=-32768; - buf[0][h]=lout; - buf[1][h]=rout; + + if (lastOut[0]!=lout) { + blip_add_delta(bb[0],h,lout-lastOut[0]); + lastOut[0]=lout; + } + if (lastOut[1]!=rout) { + blip_add_delta(bb[1],h,rout-lastOut[1]); + lastOut[1]=rout; + } for (int i=0; i<16; i++) { oscBuf[i]->putSample(h,(nds.chan_lout(i)+nds.chan_rout(i))>>1); } - } + }*/ for (int i=0; i<16; i++) { oscBuf[i]->end(len); @@ -453,6 +466,8 @@ void DivPlatformNDS::reset() { memset(regPool,0,288); nds.reset(); globalVolume=0x7f; + lastOut[0]=0; + lastOut[1]=0; rWrite32(0x100,0x8000|globalVolume); // enable keyon rWrite32(0x104,0x200); // initialize bias for (int i=0; i<16; i++) { @@ -466,6 +481,10 @@ int DivPlatformNDS::getOutputCount() { return 2; } +bool DivPlatformNDS::hasAcquireDirect() { + return true; +} + void DivPlatformNDS::notifyInsChange(int ins) { for (int i=0; i<16; i++) { if (chan[i].ins==ins) { @@ -570,7 +589,7 @@ void DivPlatformNDS::renderSamples(int sysID) { void DivPlatformNDS::setFlags(const DivConfig& flags) { isDSi=flags.getBool("chipType",0); chipClock=33513982; - rate=chipClock/2/coreQuality; + rate=chipClock/2; for (int i=0; i<16; i++) { oscBuf[i]->setRate(rate); } diff --git a/src/engine/platform/nds.h b/src/engine/platform/nds.h index bb44ffb87..48ff95dab 100644 --- a/src/engine/platform/nds.h +++ b/src/engine/platform/nds.h @@ -49,6 +49,7 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf { bool isMuted[16]; bool isDSi; int globalVolume; + int lastOut[2]; unsigned int sampleOff[256]; bool sampleLoaded[256]; @@ -65,7 +66,7 @@ class DivPlatformNDS: public DivDispatch, public nds_sound_intf { virtual u8 read_byte(u32 addr) 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 void* getChanState(int chan) 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 float getPostAmp() override; virtual int getOutputCount() override; + virtual bool hasAcquireDirect() override; virtual void notifyInsChange(int ins) override; virtual void notifyWaveChange(int wave) override; virtual void notifyInsDeletion(void* ins) override; diff --git a/src/engine/platform/sound/nds.cpp b/src/engine/platform/sound/nds.cpp index 75fbaf925..b95cd9314 100644 --- a/src/engine/platform/sound/nds.cpp +++ b/src/engine/platform/sound/nds.cpp @@ -5,6 +5,17 @@ NDS sound emulator 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. ============================================================================ @@ -64,6 +75,25 @@ namespace nds_sound_emu 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) { m_loutput = m_routput = (m_bias & 0x3ff); @@ -76,14 +106,18 @@ namespace nds_sound_emu { channel_t &channel = m_channel[i]; channel.update(cycle); + /* // bypass mixer if (((i == 1) && (mix_ch1())) || ((i == 3) && (mix_ch3()))) continue; lmix += channel.loutput(); rmix += channel.routput(); + */ } + return; // don't care about the rest + // send mixer output to capture m_capture[0].update(lmix, cycle); m_capture[1].update(rmix, cycle); @@ -231,6 +265,15 @@ namespace nds_sound_emu m_loopstart = 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_adpcm_out = 0; m_adpcm_index = 0; @@ -256,15 +299,26 @@ namespace nds_sound_emu { case 0: // Control/Status 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 (busy()) + if (m_ctl_busy) keyon(); - else if (!busy()) + else if (!m_ctl_busy) keyoff(); } // reset hold flag - if (!m_playing && !hold()) + if (!m_playing && !m_ctl_hold) { m_sample = m_lfsr_out = 0; m_output = m_loutput = m_routput = 0; @@ -292,9 +346,9 @@ namespace nds_sound_emu if (!m_playing) { 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_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_sample = 0; m_lfsr_out = 0x7fff; @@ -307,9 +361,11 @@ namespace nds_sound_emu { if (m_playing) { - if (busy()) + if (m_ctl_busy) { m_control &= ~(1 << 31); - if (!hold()) + m_ctl_busy = false; + } + if (!m_ctl_hold) { m_sample = m_lfsr_out = 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) + { + for (s32 i=m_lastts; itimestamp-i) cycle=timestamp-i; + if (cycle<1) cycle=1; + + // get output + m_counter -= cycle; + while (m_counter <= m_freq) { - if (m_playing) - { - // get output - fetch(); - m_counter -= cycle; - while (m_counter <= m_freq) - { - // advance - advance(); - m_counter += 0x10000 - m_freq; - } - m_output = (m_sample * volume()) >> (7 + voldiv()); - m_loutput = (m_output * lvol()) >> 7; - m_routput = (m_output * rvol()) >> 7; - } + // advance + fetch(); + advance(); + m_counter += 0x10000 - m_freq; } + m_output = (m_sample * m_ctl_volume) >> (7 + m_ctl_voldiv); + const s32 loutput = (m_output * lvol()) >> 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() { if (!m_playing) return INT32_MAX; + if (!(m_ctl_volume)) return INT32_MAX; return m_counter-m_freq; } @@ -348,7 +425,7 @@ namespace nds_sound_emu if (m_playing) { // fetch samples - switch (format()) + switch (m_ctl_format) { case 0: // PCM8 m_sample = s16(m_host.m_intf.read_byte(addr()) << 8); @@ -362,7 +439,7 @@ namespace nds_sound_emu case 3: // PSG or Noise m_sample = 0; 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 m_sample = m_lfsr_out; break; @@ -370,7 +447,7 @@ namespace nds_sound_emu } // apply delay - if (format() != 3 && m_delay > 0) + if (m_ctl_format != 3 && m_delay > 0) m_sample = 0; } @@ -379,7 +456,7 @@ namespace nds_sound_emu if (m_playing) { // advance bit address - switch (format()) + switch (m_ctl_format) { case 0: // PCM8 m_cur_bitaddr += 8; @@ -425,7 +502,7 @@ namespace nds_sound_emu } // address update - if (format() != 3) + if (m_ctl_format != 3) { // adjust delay m_delay--; @@ -434,7 +511,7 @@ namespace nds_sound_emu while (m_cur_bitaddr >= 32) { // 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; } @@ -443,7 +520,7 @@ namespace nds_sound_emu { m_cur_state = STATE_POST_LOOP; m_cur_addr = 0; - if (format() == 2) + if (m_ctl_format == 2) { m_prev_adpcm_out = m_adpcm_out; 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) { - switch (repeat()) + switch (m_ctl_repeat) { case 0: // manual; not correct? case 2: // one-shot @@ -459,7 +536,7 @@ namespace nds_sound_emu keyoff(); break; case 1: // loop infinitely - if (format() == 2) + if (m_ctl_format == 2) { if (m_loopstart == 0) // reload ADPCM { diff --git a/src/engine/platform/sound/nds.hpp b/src/engine/platform/sound/nds.hpp index 0ffa045ab..afe019a9a 100644 --- a/src/engine/platform/sound/nds.hpp +++ b/src/engine/platform/sound/nds.hpp @@ -5,6 +5,17 @@ NDS sound emulator 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. ============================================================================ @@ -40,6 +51,10 @@ Tech info: https://problemkaputt.de/gbatek.htm #ifndef NDS_SOUND_EMU_H #define NDS_SOUND_EMU_H +#include +#include "blip_buf.h" +#include "../../dispatch.h" + namespace nds_sound_emu { using u8 = unsigned char; @@ -116,12 +131,16 @@ namespace nds_sound_emu , m_bias(0) , m_loutput(0) , m_routput(0) + , m_lastts(0) { } void reset(); + void resetTS(u32 what); 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 u32 read32(u32 addr); @@ -178,11 +197,22 @@ namespace nds_sound_emu , m_psg(psg) , m_noise(noise) + , m_bb{NULL,NULL} + , m_oscBuf(NULL) + , m_control(0) , m_sourceaddr(0) , m_freq(0) , m_loopstart(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_adpcm_out(0) , m_adpcm_index(0) @@ -199,6 +229,7 @@ namespace nds_sound_emu , m_output(0) , m_loutput(0) , m_routput(0) + , m_lastts(0) { } @@ -206,7 +237,10 @@ namespace nds_sound_emu void write(u32 offset, u32 data, u32 mask = ~0); void update(s32 cycle); - s32 predict(); + 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(); // getters // control word @@ -223,18 +257,18 @@ namespace nds_sound_emu const u8 m_voldiv_shift[4] = {0, 1, 2, 4}; // control bits - s32 volume() const { return bitfield(m_control, 0, 7); } // global volume - u32 voldiv() const { return m_voldiv_shift[bitfield(m_control, 8, 2)]; } // volume shift - bool hold() const { return bitfield(m_control, 15); } // hold bit - u32 pan() const { return bitfield(m_control, 16, 7); } // panning (0...127, 0 = left, 127 = right, 64 = half) - u32 duty() const { return bitfield(m_control, 24, 3); } // PSG duty - u32 repeat() const { return bitfield(m_control, 27, 2); } // 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) - bool busy() const { return bitfield(m_control, 31); } // Busy flag + s32 volume() const { return m_ctl_volume; } // global volume + u32 voldiv() const { return m_ctl_voldiv; } // volume shift + bool hold() const { return m_ctl_hold; } // hold bit + u32 pan() const { return m_ctl_pan; } // panning (0...127, 0 = left, 127 = right, 64 = half) + u32 duty() const { return m_ctl_duty; } // PSG duty + u32 repeat() const { return m_ctl_repeat; } // Repeat mode (Manual, Loop infinitely, One-shot) + u32 format() const { return m_ctl_format; } // Sound Format (PCM8, PCM16, ADPCM, PSG/Noise when exists) + bool busy() const { return m_ctl_busy; } // Busy flag // calculated values - s32 lvol() const { return (pan() == 0x7f) ? 0 : 128 - pan(); } // calculated left volume - s32 rvol() const { return (pan() == 0x7f) ? 128 : pan(); } // calculated right volume + s32 lvol() const { return (m_ctl_pan == 0x7f) ? 0 : 128 - m_ctl_pan; } // calculated left volume + s32 rvol() const { return (m_ctl_pan == 0x7f) ? 128 : m_ctl_pan; } // calculated right volume // 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)); } @@ -251,6 +285,10 @@ namespace nds_sound_emu bool m_psg = false; // PSG Enable bool m_noise = false; // Noise Enable + // blip_buf + blip_buffer_t* m_bb[2]; + DivDispatchOscBuffer* m_oscBuf; + // registers u32 m_control = 0; // Control u32 m_sourceaddr = 0; // Source Address @@ -258,6 +296,16 @@ namespace nds_sound_emu u16 m_loopstart = 0; // Loop Start 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 bool m_playing = false; // playing flag 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_loutput = 0; // current left output s32 m_routput = 0; // current right output + u32 m_lastts = 0; // running timestamp }; class capture_t @@ -411,7 +460,8 @@ namespace nds_sound_emu u32 m_bias = 0; // output bias s32 m_loutput = 0; // left output s32 m_routput = 0; // right output + u32 m_lastts = 0; // running timestamp }; }; // namespace nds_sound_emu -#endif // NDS_SOUND_EMU_H \ No newline at end of file +#endif // NDS_SOUND_EMU_H