diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 54a667883..7b705929d 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -118,7 +118,9 @@ void DivPlatformSMS::acquire_nuked(short** buf, size_t len) { } } -void DivPlatformSMS::acquire_mame(short** buf, size_t len) { +void DivPlatformSMS::acquire_mame(blip_buffer_t** bb, size_t len) { + thread_local short outs[2]; + while (!writes.empty()) { QueuedWrite w=writes.front(); if (stereo && (w.addr==1)) @@ -137,11 +139,28 @@ void DivPlatformSMS::acquire_mame(short** buf, size_t len) { } for (size_t h=0; hsound_stream_update(outs,1); + // wahahaha heuristic... + int advance=len-h; + for (int i=0; i<4; i++) { + if (sn->m_count[i]m_count[i]; + } + if (advance<1) advance=1; + + sn->sound_stream_update(outs,advance); + + h+=advance-1; + + if (outs[0]!=lastOut[0]) { + blip_add_delta(bb[0],h,outs[0]-lastOut[0]); + lastOut[0]=outs[0]; + } + if (stereo) { + if (outs[1]!=lastOut[1]) { + blip_add_delta(bb[1],h,outs[1]-lastOut[1]); + lastOut[1]=outs[1]; + } + } + for (int i=0; i<4; i++) { if (isMuted[i]) { oscBuf[i]->putSample(h,0); @@ -159,11 +178,14 @@ void DivPlatformSMS::acquire_mame(short** buf, size_t len) { void DivPlatformSMS::acquire(short** buf, size_t len) { if (nuked) { acquire_nuked(buf,len); - } else { - acquire_mame(buf,len); } } +void DivPlatformSMS::acquireDirect(blip_buffer_t** bb, size_t len) { + if (nuked) return; + acquire_mame(bb,len); +} + double DivPlatformSMS::NOTE_SN(int ch, int note) { double CHIP_DIVIDER=toneDivider; if (ch==3) CHIP_DIVIDER=noiseDivider; @@ -522,6 +544,8 @@ void DivPlatformSMS::reset() { if (stereo) { rWrite(1,0xff); } + lastOut[0]=0; + lastOut[1]=0; } int DivPlatformSMS::getOutputCount() { @@ -536,6 +560,10 @@ bool DivPlatformSMS::keyOffAffectsPorta(int ch) { return true; } +bool DivPlatformSMS::hasAcquireDirect() { + return !nuked; +} + bool DivPlatformSMS::getLegacyAlwaysSetVolume() { return false; } @@ -597,7 +625,7 @@ void DivPlatformSMS::setFlags(const DivConfig& flags) { noiseDivider=60.0; // 64 for match to tone frequency on non-Sega PSG but compatibility break; case 2: // TI+Atari - sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 1/*8*/, false, true); + sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, false, true); isRealSN=true; stereo=false; noiseDivider=60.0; diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index 32b1912e0..437caf993 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -44,6 +44,7 @@ class DivPlatformSMS: public DivDispatch { unsigned char snNoiseMode; unsigned char regPool[16]; unsigned char chanLatch; + int lastOut[2]; int divider=16; double toneDivider=64.0; double noiseDivider=64.0; @@ -71,9 +72,10 @@ class DivPlatformSMS: public DivDispatch { void poolWrite(unsigned short a, unsigned char v); void acquire_nuked(short** buf, size_t len); - void acquire_mame(short** buf, size_t len); + void acquire_mame(blip_buffer_t** bb, size_t len); public: void acquire(short** buf, size_t len); + void acquireDirect(blip_buffer_t** bb, size_t len); int dispatch(DivCommand c); void* getChanState(int chan); DivMacroInt* getChanMacroInt(int ch); @@ -90,6 +92,7 @@ class DivPlatformSMS: public DivDispatch { int getOutputCount(); bool keyOffAffectsArp(int ch); bool keyOffAffectsPorta(int ch); + bool hasAcquireDirect(); bool getLegacyAlwaysSetVolume(); float getPostAmp(); int getPortaFloor(int ch); diff --git a/src/engine/platform/sound/sn76496.cpp b/src/engine/platform/sound/sn76496.cpp index e76b403f8..e868a348c 100644 --- a/src/engine/platform/sound/sn76496.cpp +++ b/src/engine/platform/sound/sn76496.cpp @@ -155,7 +155,6 @@ sn76496_base_device::sn76496_base_device( int noisetap2, bool negate, bool stereo, - int clockdivider, bool ncr, bool sega) : m_feedback_mask(feedbackmask) @@ -164,59 +163,58 @@ sn76496_base_device::sn76496_base_device( , m_whitenoise_tap2(noisetap2) , m_negate(negate) , m_stereo(stereo) - , m_clock_divider(clockdivider) , m_ncr_style_psg(ncr) , m_sega_style_psg(sega) { } sn76496_device::sn76496_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, false, true) { } y2404_device::y2404_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, false, true) { } sn76489_device::sn76489_device() - : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1/*8*/, false, true) + : sn76496_base_device(0x4000, 0x01, 0x02, true, false, false, true) { } sn76489a_device::sn76489a_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, false, true) { } sn76494_device::sn76494_device() - : sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1, false, true) + : sn76496_base_device(0x10000, 0x04, 0x08, false, false, false, true) { } sn94624_device::sn94624_device() - : sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1, false, true) + : sn76496_base_device(0x4000, 0x01, 0x02, true, false, false, true) { } ncr8496_device::ncr8496_device() - : sn76496_base_device(0x8000, 0x02, 0x20, true, false, 1/*8*/, true, true) + : sn76496_base_device(0x8000, 0x02, 0x20, true, false, true, true) { } pssj3_device::pssj3_device() - : sn76496_base_device(0x8000, 0x02, 0x20, false, false, 1/*8*/, true, true) + : sn76496_base_device(0x8000, 0x02, 0x20, false, false, true, true) { } gamegear_device::gamegear_device() - : sn76496_base_device(0x8000, 0x01, 0x08, true, true, 1/*8*/, false, false) + : sn76496_base_device(0x8000, 0x01, 0x08, true, true, false, false) { } segapsg_device::segapsg_device() - : sn76496_base_device(0x8000, 0x01, 0x08, true, false, 1/*8*/, false, false) + : sn76496_base_device(0x8000, 0x01, 0x08, true, false, false, false) { } @@ -246,7 +244,6 @@ void sn76496_base_device::device_start() m_output[3] = m_RNG & 1; m_stereo_mask = 0xFF; // all channels enabled - m_current_clock = m_clock_divider-1; // set gain gain = 0; @@ -337,81 +334,68 @@ inline bool sn76496_base_device::in_noise_mode() return ((m_register[6] & 4)!=0); } -void sn76496_base_device::sound_stream_update(short** outputs, int outLen) +void sn76496_base_device::sound_stream_update(short* outputs, int advance) { - int i; + int i; - int16_t out; - int16_t out2 = 0; + int16_t out; + int16_t out2 = 0; - for (int sampindex = 0; sampindex < outLen; sampindex++) - { - // clock chip once - if (m_current_clock > 0) // not ready for new divided clock - { - m_current_clock--; - } - else // ready for new divided clock, make a new sample - { - m_current_clock = m_clock_divider-1; + // handle channels 0,1,2 + for (i = 0; i < 3; i++) + { + m_count[i]-=advance; + if (m_count[i] <= 0) + { + m_output[i] ^= 1; + m_count[i] = m_period[i]; + } + } - // handle channels 0,1,2 - for (i = 0; i < 3; i++) - { - m_count[i]--; - if (m_count[i] <= 0) - { - m_output[i] ^= 1; - m_count[i] = m_period[i]; - } - } + // handle channel 3 + m_count[3]-=advance; + if (m_count[3] <= 0) + { + // if noisemode is 1, both taps are enabled + // if noisemode is 0, the lower tap, whitenoisetap2, is held at 0 + // The != was a bit-XOR (^) before + if (((m_RNG & m_whitenoise_tap1)!=0) != (((int32_t)(m_RNG & m_whitenoise_tap2)!=(m_ncr_style_psg?m_whitenoise_tap2:0)) && in_noise_mode())) + { + m_RNG >>= 1; + m_RNG |= m_feedback_mask; + } + else + { + m_RNG >>= 1; + } + m_output[3] = m_RNG & 1; - // handle channel 3 - m_count[3]--; - if (m_count[3] <= 0) - { - // if noisemode is 1, both taps are enabled - // if noisemode is 0, the lower tap, whitenoisetap2, is held at 0 - // The != was a bit-XOR (^) before - if (((m_RNG & m_whitenoise_tap1)!=0) != (((int32_t)(m_RNG & m_whitenoise_tap2)!=(m_ncr_style_psg?m_whitenoise_tap2:0)) && in_noise_mode())) - { - m_RNG >>= 1; - m_RNG |= m_feedback_mask; - } - else - { - m_RNG >>= 1; - } - m_output[3] = m_RNG & 1; + m_count[3] = m_period[3]; + } - m_count[3] = m_period[3]; - } - } + if (m_stereo) + { + out = ((((m_stereo_mask & 0x10)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x20)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x40)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x80)!=0) && (m_output[3]!=0))? m_volume[3] : 0); - if (m_stereo) - { - out = ((((m_stereo_mask & 0x10)!=0) && (m_output[0]!=0))? m_volume[0] : 0) - + ((((m_stereo_mask & 0x20)!=0) && (m_output[1]!=0))? m_volume[1] : 0) - + ((((m_stereo_mask & 0x40)!=0) && (m_output[2]!=0))? m_volume[2] : 0) - + ((((m_stereo_mask & 0x80)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + out2= ((((m_stereo_mask & 0x1)!=0) && (m_output[0]!=0))? m_volume[0] : 0) + + ((((m_stereo_mask & 0x2)!=0) && (m_output[1]!=0))? m_volume[1] : 0) + + ((((m_stereo_mask & 0x4)!=0) && (m_output[2]!=0))? m_volume[2] : 0) + + ((((m_stereo_mask & 0x8)!=0) && (m_output[3]!=0))? m_volume[3] : 0); + } + else + { + out= ((m_output[0]!=0)? m_volume[0]:0) + +((m_output[1]!=0)? m_volume[1]:0) + +((m_output[2]!=0)? m_volume[2]:0) + +((m_output[3]!=0)? m_volume[3]:0); + } - out2= ((((m_stereo_mask & 0x1)!=0) && (m_output[0]!=0))? m_volume[0] : 0) - + ((((m_stereo_mask & 0x2)!=0) && (m_output[1]!=0))? m_volume[1] : 0) - + ((((m_stereo_mask & 0x4)!=0) && (m_output[2]!=0))? m_volume[2] : 0) - + ((((m_stereo_mask & 0x8)!=0) && (m_output[3]!=0))? m_volume[3] : 0); - } - else - { - out= ((m_output[0]!=0)? m_volume[0]:0) - +((m_output[1]!=0)? m_volume[1]:0) - +((m_output[2]!=0)? m_volume[2]:0) - +((m_output[3]!=0)? m_volume[3]:0); - } + if (m_negate) { out = -out; out2 = -out2; } - if (m_negate) { out = -out; out2 = -out2; } - - outputs[0][sampindex]=out; - if (m_stereo && (outputs[1] != nullptr)) - outputs[1][sampindex]=out2; - } + outputs[0]=out; + if (m_stereo) + outputs[1]=out2; } diff --git a/src/engine/platform/sound/sn76496.h b/src/engine/platform/sound/sn76496.h index 7a8a5c625..7ed440f97 100644 --- a/src/engine/platform/sound/sn76496.h +++ b/src/engine/platform/sound/sn76496.h @@ -15,7 +15,7 @@ public: void stereo_w(u8 data); void write(u8 data); void device_start(); - void sound_stream_update(short** outputs, int outLen); + void sound_stream_update(short* outputs, int outLen); inline int32_t get_channel_output(int ch) { return ((m_output[ch]!=0)?m_volume[ch]:0); } @@ -28,7 +28,6 @@ public: int noisetap2, bool negate, bool stereo, - int clockdivider, bool ncr, bool sega); @@ -38,7 +37,6 @@ public: int noisetap2, bool negate, bool stereo, - int clockdivider, bool ncr, bool sega) : sn76496_base_device( @@ -48,12 +46,11 @@ public: noisetap2, negate, stereo, - clockdivider, ncr, sega) {} -private: +public: // SORRY.... inline bool in_noise_mode(); bool m_ready_state; @@ -64,7 +61,6 @@ private: const int32_t m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13) bool m_negate; // output negate flag const bool m_stereo; // whether we're dealing with stereo or not - const int32_t m_clock_divider; // clock divider const bool m_ncr_style_psg; // flag to ignore writes to regs 1,3,5,6,7 with bit 7 low const bool m_sega_style_psg; // flag to make frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0; the initial register is pointing to 0x3 instead of 0x0; the volume reg is preloaded with 0xF instead of 0x0 @@ -73,7 +69,6 @@ private: int32_t m_last_register; // last register written int32_t m_volume[4]; // db volume of voice 0-2 and noise uint32_t m_RNG; // noise generator LFSR - int32_t m_current_clock; int32_t m_stereo_mask; // the stereo output mask int32_t m_period[4]; // Length of 1/2 of waveform int32_t m_count[4]; // Position within the waveform