From aebfc85cdfae38fddc11da5c7d418e5f67cda39f Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Tue, 5 Feb 2019 16:26:22 -0600 Subject: [PATCH] APU: Big refactor. Remove 8-bit, Mono, and Reverse Stereo options. --- apu/apu.cpp | 836 ++++++++++--------------- apu/hermite_resampler.h | 4 +- gtk/src/gtk_sound_driver_alsa.cpp | 14 +- gtk/src/gtk_sound_driver_oss.cpp | 53 +- gtk/src/gtk_sound_driver_portaudio.cpp | 12 +- gtk/src/gtk_sound_driver_pulse.cpp | 206 +++--- 6 files changed, 466 insertions(+), 659 deletions(-) diff --git a/apu/apu.cpp b/apu/apu.cpp index 5afcb5dd..66af4517 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -4,7 +4,8 @@ For further information, consult the LICENSE file in the root directory. \*****************************************************************************/ -#include +#include +#include #include "../snes9x.h" #include "apu.h" #include "../msu1.h" @@ -14,619 +15,460 @@ #include "bapu/snes/snes.hpp" -#define APU_DEFAULT_INPUT_RATE 31950 // ~ 59.94Hz -#define APU_MINIMUM_SAMPLE_COUNT 512 -#define APU_MINIMUM_SAMPLE_BLOCK 128 -#define APU_NUMERATOR_NTSC 15664 -#define APU_DENOMINATOR_NTSC 328125 -#define APU_NUMERATOR_PAL 34176 -#define APU_DENOMINATOR_PAL 709379 +static const int APU_DEFAULT_INPUT_RATE = 31950; // ~59.94Hz +static const int APU_SAMPLE_BLOCK = 48; +static const int APU_NUMERATOR_NTSC = 15664; +static const int APU_DENOMINATOR_NTSC = 328125; +static const int APU_NUMERATOR_PAL = 34176; +static const int APU_DENOMINATOR_PAL = 709379; + +// Max number of sample frames we'll ever generate before call to port API +static const int MAX_SAMPLE_FRAMES = (32040 + 59) / 60; namespace SNES { #include "bapu/dsp/blargg_endian.h" - - CPU cpu; +CPU cpu; } namespace spc { - static apu_callback sa_callback = NULL; - static void *extra_data = NULL; +static apu_callback callback = NULL; +static void *callback_data = NULL; - static bool8 sound_in_sync = TRUE; - static bool8 sound_enabled = FALSE; +static bool8 sound_in_sync = TRUE; +static bool8 sound_enabled = FALSE; +static uint16 dsp_buffer[MAX_SAMPLE_FRAMES * 2]; - static int buffer_size; - static int lag_master = 0; - static int lag = 0; +static Resampler *resampler = NULL; - static uint8 *landing_buffer = NULL; - static uint8 *shrink_buffer = NULL; +static int32 reference_time; +static uint32 remainder; - static Resampler *resampler = NULL; +static const int timing_hack_numerator = 256; +static int timing_hack_denominator = 256; +/* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup + if necessary on game load. */ +static uint32 ratio_numerator = APU_NUMERATOR_NTSC; +static uint32 ratio_denominator = APU_DENOMINATOR_NTSC; - static int32 reference_time; - static uint32 remainder; - - static const int timing_hack_numerator = 256; - static int timing_hack_denominator = 256; - /* Set these to NTSC for now. Will change to PAL in S9xAPUTimingSetSpeedup - if necessary on game load. */ - static uint32 ratio_numerator = APU_NUMERATOR_NTSC; - static uint32 ratio_denominator = APU_DENOMINATOR_NTSC; - - static double dynamic_rate_multiplier = 1.0; +static double dynamic_rate_multiplier = 1.0; } namespace msu { - static int buffer_size; - static uint8 *landing_buffer = NULL; - static Resampler *resampler = NULL; - static int resample_buffer_size = -1; - static uint8 *resample_buffer = NULL; +// Always 16-bit, Stereo; 1.5x dsp buffer to never overflow +static const int buffer_size = MAX_SAMPLE_FRAMES * 6; +static uint8 mixing_buffer[buffer_size]; +static Resampler *resampler = NULL; +static std::vector resample_buffer; } -static void EightBitize (uint8 *, int); -static void DeStereo (uint8 *, int); -static void ReverseStereo (uint8 *, int); -static void UpdatePlaybackRate (void); -static void SPCSnapshotCallback (void); -static inline int S9xAPUGetClock (int32); -static inline int S9xAPUGetClockRemainder (int32); +static void UpdatePlaybackRate(void); +static void SPCSnapshotCallback(void); +static inline int S9xAPUGetClock(int32); +static inline int S9xAPUGetClockRemainder(int32); - -static void EightBitize (uint8 *buffer, int sample_count) +static void reset_dsp_output() { - uint8 *buf8 = (uint8 *) buffer; - int16 *buf16 = (int16 *) buffer; - - for (int i = 0; i < sample_count; i++) - buf8[i] = (uint8) ((buf16[i] / 256) + 128); + SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *)spc::dsp_buffer, + MAX_SAMPLE_FRAMES * 2); } -static void DeStereo (uint8 *buffer, int sample_count) +bool8 S9xMixSamples(uint8 *dest, int sample_count) { - int16 *buf = (int16 *) buffer; - int32 s1, s2; + int16 *out = (int16 *)dest; - for (int i = 0; i < (sample_count >> 1); i++) - { - s1 = (int32) buf[2 * i]; - s2 = (int32) buf[2 * i + 1]; - buf[i] = (int16) ((s1 + s2) >> 1); - } + if (Settings.Mute) + { + memset(out, 0, sample_count << 1); + spc::resampler->clear(); + + if (Settings.MSU1) + msu::resampler->clear(); + } + else + { + if (spc::resampler->avail() >= sample_count) + { + spc::resampler->read((short *)out, sample_count); + + if (Settings.MSU1) + { + if (msu::resampler->avail() >= sample_count) + { + if ((int)msu::resample_buffer.size() < sample_count) + msu::resample_buffer.resize(sample_count); + msu::resampler->read((short *)msu::resample_buffer.data(), + sample_count); + for (int i = 0; i < sample_count; ++i) + out[i] += msu::resample_buffer[i]; + } + else // should never occur + assert(0); + } + } + else + { + memset(out, 0, sample_count << 1); + return false; + } + } + + return true; } -static void ReverseStereo (uint8 *src_buffer, int sample_count) +int S9xGetSampleCount(void) { - int16 *buffer = (int16 *) src_buffer; - - for (int i = 0; i < sample_count; i += 2) - { - buffer[i + 1] ^= buffer[i]; - buffer[i] ^= buffer[i + 1]; - buffer[i + 1] ^= buffer[i]; - } + return spc::resampler->avail(); } -bool8 S9xMixSamples (uint8 *buffer, int sample_count) +void S9xFinalizeSamples(void) { - static int shrink_buffer_size = -1; - uint8 *dest; + bool drop_msu1_samples = true; - if (!Settings.SixteenBitSound || !Settings.Stereo) - { - /* We still need both stereo samples for generating the mono sample */ - if (!Settings.Stereo) - sample_count <<= 1; + if (!Settings.Mute) + { + drop_msu1_samples = false; - /* We still have to generate 16-bit samples for bit-dropping, too */ - if (shrink_buffer_size < (sample_count << 1)) - { - delete[] spc::shrink_buffer; - spc::shrink_buffer = new uint8[sample_count << 1]; - shrink_buffer_size = sample_count << 1; - } + if (!spc::resampler->push((short *)spc::dsp_buffer, + SNES::dsp.spc_dsp.sample_count())) + { + spc::resampler->clear(); + msu::resampler->clear(); + drop_msu1_samples = true; + } + } - dest = spc::shrink_buffer; - } - else - dest = buffer; + // only generate msu1 if we really consumed the dsp samples (sample_count() resets at end of function), + // otherwise we will generate multiple times for the same samples - so this needs to be after all early + // function returns + if (Settings.MSU1) + { + // generate the same number of msu1 samples as dsp samples were generated + S9xMSU1SetOutput((int16 *)msu::mixing_buffer, msu::buffer_size); + S9xMSU1Generate(SNES::dsp.spc_dsp.sample_count()); + if (drop_msu1_samples) + msu::resampler->clear(); + else if (!msu::resampler->push((short *)msu::mixing_buffer, S9xMSU1Samples())) + { + // should not occur, msu buffer is larger and we drop msu samples if spc buffer overruns + assert(0); + } + } - if (Settings.MSU1 && msu::resample_buffer_size < (sample_count << 1)) - { - delete[] msu::resample_buffer; - msu::resample_buffer = new uint8[sample_count << 1]; - msu::resample_buffer_size = sample_count << 1; - } + if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute) + spc::sound_in_sync = TRUE; + else if (spc::resampler->space_empty() >= spc::resampler->space_filled()) + spc::sound_in_sync = TRUE; + else + spc::sound_in_sync = FALSE; - if (Settings.Mute) - { - memset(dest, 0, sample_count << 1); - spc::resampler->clear(); - - if(Settings.MSU1) - msu::resampler->clear(); - - return (FALSE); - } - else - { - if (spc::resampler->avail() >= (sample_count + spc::lag)) - { - spc::resampler->read((short *) dest, sample_count); - if (spc::lag == spc::lag_master) - spc::lag = 0; - - if (Settings.MSU1) - { - if (msu::resampler->avail() >= sample_count) - { - msu::resampler->read((short *)msu::resample_buffer, sample_count); - for (int i = 0; i < sample_count; ++i) - *((int16*)(dest+(i * 2))) += *((int16*)(msu::resample_buffer +(i * 2))); - } - else // should never occur - assert(0); - } - } - else - { - memset(buffer, (Settings.SixteenBitSound ? 0 : 128), (sample_count << (Settings.SixteenBitSound ? 1 : 0)) >> (Settings.Stereo ? 0 : 1)); - if (spc::lag == 0) - spc::lag = spc::lag_master; - - return (FALSE); - } - } - - if (Settings.ReverseStereo && Settings.Stereo) - ReverseStereo(dest, sample_count); - - if (!Settings.Stereo || !Settings.SixteenBitSound) - { - if (!Settings.Stereo) - { - DeStereo(dest, sample_count); - sample_count >>= 1; - } - - if (!Settings.SixteenBitSound) - EightBitize(dest, sample_count); - - memcpy(buffer, dest, (sample_count << (Settings.SixteenBitSound ? 1 : 0))); - } - - return (TRUE); + reset_dsp_output(); } -int S9xGetSampleCount (void) +void S9xLandSamples(void) { - return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1)); + if (spc::callback != NULL) + spc::callback(spc::callback_data); + else + S9xFinalizeSamples(); } -/* TODO: Attach */ -void S9xFinalizeSamples (void) +void S9xClearSamples(void) { - bool drop_current_msu1_samples = true; - - if (!Settings.Mute) - { - drop_current_msu1_samples = false; - - if (!spc::resampler->push((short *)spc::landing_buffer, SNES::dsp.spc_dsp.sample_count())) - { - /* We weren't able to process the entire buffer. Potential overrun. */ - spc::sound_in_sync = FALSE; - - if (Settings.SoundSync && !Settings.TurboMode) - return; - - // since we drop the current dsp samples we also want to drop generated msu1 samples - drop_current_msu1_samples = true; - } - } - - // only generate msu1 if we really consumed the dsp samples (sample_count() resets at end of function), - // otherwise we will generate multiple times for the same samples - so this needs to be after all early - // function returns - if (Settings.MSU1) - { - // generate the same number of msu1 samples as dsp samples were generated - S9xMSU1SetOutput((int16 *)msu::landing_buffer, msu::buffer_size); - S9xMSU1Generate(SNES::dsp.spc_dsp.sample_count()); - if (!drop_current_msu1_samples && !msu::resampler->push((short *)msu::landing_buffer, S9xMSU1Samples())) - { - // should not occur, msu buffer is larger and we drop msu samples if spc buffer overruns - assert(0); - } - } - - - if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute) - spc::sound_in_sync = TRUE; - else - if (spc::resampler->space_empty() >= spc::resampler->space_filled()) - spc::sound_in_sync = TRUE; - else - spc::sound_in_sync = FALSE; - - SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); + spc::resampler->clear(); + if (Settings.MSU1) + msu::resampler->clear(); } -void S9xLandSamples (void) +bool8 S9xSyncSound(void) { - if (spc::sa_callback != NULL) - spc::sa_callback(spc::extra_data); - else - S9xFinalizeSamples(); + if (!Settings.SoundSync || spc::sound_in_sync) + return (TRUE); + + S9xLandSamples(); + + return (spc::sound_in_sync); } -void S9xClearSamples (void) +void S9xSetSamplesAvailableCallback(apu_callback callback, void *data) { - spc::resampler->clear(); - if (Settings.MSU1) - msu::resampler->clear(); - spc::lag = spc::lag_master; + spc::callback = callback; + spc::callback_data = data; } -bool8 S9xSyncSound (void) +void S9xUpdateDynamicRate(int avail, int buffer_size) { - if (!Settings.SoundSync || spc::sound_in_sync) - return (TRUE); + spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / + (double)(1000 * buffer_size); - S9xLandSamples(); - - return (spc::sound_in_sync); + UpdatePlaybackRate(); } -void S9xSetSamplesAvailableCallback (apu_callback callback, void *data) +static void UpdatePlaybackRate(void) { - spc::sa_callback = callback; - spc::extra_data = data; + if (Settings.SoundInputRate == 0) + Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE; + + double time_ratio = (double)Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator); + + if (Settings.DynamicRateControl) + { + time_ratio *= spc::dynamic_rate_multiplier; + } + + spc::resampler->time_ratio(time_ratio); + + if (Settings.MSU1) + { + time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0); + msu::resampler->time_ratio(time_ratio); + } } -void S9xUpdateDynamicRate (int avail, int buffer_size) +bool8 S9xInitSound(int unused, int unused2) { - spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / - (double)(1000 * buffer_size); + // The resampler and spc unit use samples (16-bit short) as arguments. + if (!spc::resampler) + { + spc::resampler = new HermiteResampler(MAX_SAMPLE_FRAMES * 2); + if (!spc::resampler) + return (FALSE); + } - UpdatePlaybackRate(); + if (!msu::resampler) + { + msu::resampler = new HermiteResampler(msu::buffer_size); + if (!msu::resampler) + return (FALSE); + } + else + msu::resampler->resize(msu::buffer_size); + + reset_dsp_output(); + + UpdatePlaybackRate(); + + spc::sound_enabled = S9xOpenSoundDevice(); + + return (spc::sound_enabled); } -static void UpdatePlaybackRate (void) +void S9xSetSoundControl(uint8 voice_switch) { - if (Settings.SoundInputRate == 0) - Settings.SoundInputRate = APU_DEFAULT_INPUT_RATE; - - double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator); - - if (Settings.DynamicRateControl) - { - time_ratio *= spc::dynamic_rate_multiplier; - } - - spc::resampler->time_ratio(time_ratio); - - if (Settings.MSU1) - { - time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040.0); - msu::resampler->time_ratio(time_ratio); - } + SNES::dsp.spc_dsp.set_stereo_switch(voice_switch << 8 | voice_switch); } -bool8 S9xInitSound (int buffer_ms, int lag_ms) +void S9xSetSoundMute(bool8 mute) { - // buffer_ms : buffer size given in millisecond - // lag_ms : allowable time-lag given in millisecond - - int sample_count = buffer_ms * 32040 / 1000; - int lag_sample_count = lag_ms * 32040 / 1000; - - spc::lag_master = lag_sample_count; - if (Settings.Stereo) - spc::lag_master <<= 1; - spc::lag = spc::lag_master; - - if (sample_count < APU_MINIMUM_SAMPLE_COUNT) - sample_count = APU_MINIMUM_SAMPLE_COUNT; - - spc::buffer_size = sample_count << 2; - msu::buffer_size = (int)((sample_count << 2) * 1.5); // Always 16-bit, Stereo; 1.5 to never overflow before dsp buffer - - printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count); - - if (spc::landing_buffer) - delete[] spc::landing_buffer; - spc::landing_buffer = new uint8[spc::buffer_size * 2]; - if (!spc::landing_buffer) - return (FALSE); - if (msu::landing_buffer) - delete[] msu::landing_buffer; - msu::landing_buffer = new uint8[msu::buffer_size * 2]; - if (!msu::landing_buffer) - return (FALSE); - - /* The resampler and spc unit use samples (16-bit short) as - arguments. Use 2x in the resampler for buffer leveling with SoundSync */ - if (!spc::resampler) - { - spc::resampler = new HermiteResampler(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); - if (!spc::resampler) - { - delete[] spc::landing_buffer; - return (FALSE); - } - } - else - spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1)); - - - if (!msu::resampler) - { - msu::resampler = new HermiteResampler(msu::buffer_size); - if (!msu::resampler) - { - delete[] msu::landing_buffer; - return (FALSE); - } - } - else - msu::resampler->resize(msu::buffer_size); - - - SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size); - - UpdatePlaybackRate(); - - spc::sound_enabled = S9xOpenSoundDevice(); - - return (spc::sound_enabled); + Settings.Mute = mute; + if (!spc::sound_enabled) + Settings.Mute = TRUE; } -void S9xSetSoundControl (uint8 voice_switch) +void S9xDumpSPCSnapshot(void) { - SNES::dsp.spc_dsp.set_stereo_switch (voice_switch << 8 | voice_switch); + SNES::dsp.spc_dsp.dump_spc_snapshot(); } -void S9xSetSoundMute (bool8 mute) +static void SPCSnapshotCallback(void) { - Settings.Mute = mute; - if (!spc::sound_enabled) - Settings.Mute = TRUE; + S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR)); + printf("Dumped key-on triggered spc snapshot.\n"); } -void S9xDumpSPCSnapshot (void) +bool8 S9xInitAPU(void) { - SNES::dsp.spc_dsp.dump_spc_snapshot(); + spc::resampler = NULL; + msu::resampler = NULL; + return (TRUE); } -static void SPCSnapshotCallback (void) +void S9xDeinitAPU(void) { - S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR)); - printf("Dumped key-on triggered spc snapshot.\n"); + if (spc::resampler) + { + delete spc::resampler; + spc::resampler = NULL; + } + + if (msu::resampler) + { + delete msu::resampler; + msu::resampler = NULL; + } + + S9xMSU1DeInit(); } -bool8 S9xInitAPU (void) +static inline int S9xAPUGetClock(int32 cpucycles) { - spc::landing_buffer = NULL; - spc::shrink_buffer = NULL; - spc::resampler = NULL; - msu::resampler = NULL; - - return (TRUE); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / + spc::ratio_denominator; } -void S9xDeinitAPU (void) +static inline int S9xAPUGetClockRemainder(int32 cpucycles) { - if (spc::resampler) - { - delete spc::resampler; - spc::resampler = NULL; - } - - if (spc::landing_buffer) - { - delete[] spc::landing_buffer; - spc::landing_buffer = NULL; - } - - if (spc::shrink_buffer) - { - delete[] spc::shrink_buffer; - spc::shrink_buffer = NULL; - } - - if (msu::resampler) - { - delete msu::resampler; - msu::resampler = NULL; - } - - if (msu::landing_buffer) - { - delete[] msu::landing_buffer; - msu::landing_buffer = NULL; - } - - if (msu::resample_buffer) - { - delete[] msu::resample_buffer; - msu::resample_buffer = NULL; - } - - S9xMSU1DeInit(); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % + spc::ratio_denominator; } -static inline int S9xAPUGetClock (int32 cpucycles) +uint8 S9xAPUReadPort(int port) { - return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / - spc::ratio_denominator; + S9xAPUExecute(); + return ((uint8)SNES::smp.port_read(port & 3)); } -static inline int S9xAPUGetClockRemainder (int32 cpucycles) +void S9xAPUWritePort(int port, uint8 byte) { - return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % - spc::ratio_denominator; + S9xAPUExecute(); + SNES::cpu.port_write(port & 3, byte); } -uint8 S9xAPUReadPort (int port) +void S9xAPUSetReferenceTime(int32 cpucycles) { - S9xAPUExecute (); - return ((uint8) SNES::smp.port_read (port & 3)); + spc::reference_time = cpucycles; } -void S9xAPUWritePort (int port, uint8 byte) +void S9xAPUExecute(void) { - S9xAPUExecute (); - SNES::cpu.port_write (port & 3, byte); + SNES::smp.clock -= S9xAPUGetClock(CPU.Cycles); + SNES::smp.enter(); + + spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles); + + S9xAPUSetReferenceTime(CPU.Cycles); } -void S9xAPUSetReferenceTime (int32 cpucycles) +void S9xAPUEndScanline(void) { - spc::reference_time = cpucycles; + S9xAPUExecute(); + SNES::dsp.synchronize(); + + if (SNES::dsp.spc_dsp.sample_count() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync) + S9xLandSamples(); } -void S9xAPUExecute (void) +void S9xAPUTimingSetSpeedup(int ticks) { - SNES::smp.clock -= S9xAPUGetClock (CPU.Cycles); - SNES::smp.enter (); + if (ticks != 0) + printf("APU speedup hack: %d\n", ticks); - spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles); + spc::timing_hack_denominator = 256 - ticks; - S9xAPUSetReferenceTime(CPU.Cycles); + spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC; + spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC; + spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator; + + UpdatePlaybackRate(); } -void S9xAPUEndScanline (void) +void S9xResetAPU(void) { - S9xAPUExecute(); - SNES::dsp.synchronize(); + spc::reference_time = 0; + spc::remainder = 0; - if (SNES::dsp.spc_dsp.sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync) - S9xLandSamples(); + SNES::cpu.reset(); + SNES::cpu.frequency = Settings.PAL ? PAL_MASTER_CLOCK : NTSC_MASTER_CLOCK; + SNES::smp.power(); + SNES::dsp.power(); + reset_dsp_output(); + SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback); + + spc::resampler->clear(); + + if (Settings.MSU1) + msu::resampler->clear(); } -void S9xAPUTimingSetSpeedup (int ticks) +void S9xSoftResetAPU(void) { - if (ticks != 0) - printf("APU speedup hack: %d\n", ticks); + spc::reference_time = 0; + spc::remainder = 0; + SNES::cpu.reset(); + SNES::smp.reset(); + SNES::dsp.reset(); + reset_dsp_output(); - spc::timing_hack_denominator = 256 - ticks; + spc::resampler->clear(); - spc::ratio_numerator = Settings.PAL ? APU_NUMERATOR_PAL : APU_NUMERATOR_NTSC; - spc::ratio_denominator = Settings.PAL ? APU_DENOMINATOR_PAL : APU_DENOMINATOR_NTSC; - spc::ratio_denominator = spc::ratio_denominator * spc::timing_hack_denominator / spc::timing_hack_numerator; - - UpdatePlaybackRate(); + if (Settings.MSU1) + msu::resampler->clear(); } -void S9xResetAPU (void) +void S9xAPUSaveState(uint8 *block) { - spc::reference_time = 0; - spc::remainder = 0; + uint8 *ptr = block; - SNES::cpu.reset (); - SNES::cpu.frequency = Settings.PAL ? PAL_MASTER_CLOCK : NTSC_MASTER_CLOCK; - SNES::smp.power (); - SNES::dsp.power (); - SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); - SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback); + SNES::smp.save_state(&ptr); + SNES::dsp.save_state(&ptr); - spc::resampler->clear(); + SNES::set_le32(ptr, spc::reference_time); + ptr += sizeof(int32); + SNES::set_le32(ptr, spc::remainder); + ptr += sizeof(int32); + SNES::set_le32(ptr, SNES::dsp.clock); + ptr += sizeof(int32); + memcpy(ptr, SNES::cpu.registers, 4); + ptr += sizeof(int32); - if (Settings.MSU1) - msu::resampler->clear(); + memset(ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE - (ptr - block)); } -void S9xSoftResetAPU (void) +void S9xAPULoadState(uint8 *block) { - spc::reference_time = 0; - spc::remainder = 0; - SNES::cpu.reset (); - SNES::smp.reset (); - SNES::dsp.reset (); - SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); + uint8 *ptr = block; - spc::resampler->clear(); + SNES::smp.load_state(&ptr); + SNES::dsp.load_state(&ptr); - if (Settings.MSU1) - msu::resampler->clear(); + spc::reference_time = SNES::get_le32(ptr); + ptr += sizeof(int32); + spc::remainder = SNES::get_le32(ptr); + ptr += sizeof(int32); + SNES::dsp.clock = SNES::get_le32(ptr); + ptr += sizeof(int32); + memcpy(SNES::cpu.registers, ptr, 4); } -void S9xAPUSaveState (uint8 *block) +static void to_var_from_buf(uint8 **buf, void *var, size_t size) { - uint8 *ptr = block; - - SNES::smp.save_state (&ptr); - SNES::dsp.save_state (&ptr); - - SNES::set_le32(ptr, spc::reference_time); - ptr += sizeof(int32); - SNES::set_le32(ptr, spc::remainder); - ptr += sizeof(int32); - SNES::set_le32(ptr, SNES::dsp.clock); - ptr += sizeof(int32); - memcpy (ptr, SNES::cpu.registers, 4); - ptr += sizeof(int32); - - memset (ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE-(ptr-block)); -} - -void S9xAPULoadState (uint8 *block) -{ - uint8 *ptr = block; - - SNES::smp.load_state (&ptr); - SNES::dsp.load_state (&ptr); - - spc::reference_time = SNES::get_le32(ptr); - ptr += sizeof(int32); - spc::remainder = SNES::get_le32(ptr); - ptr += sizeof(int32); - SNES::dsp.clock = SNES::get_le32(ptr); - ptr += sizeof(int32); - memcpy (SNES::cpu.registers, ptr, 4); -} - -static void to_var_from_buf (uint8 **buf, void *var, size_t size) -{ - memcpy(var, *buf, size); - *buf += size; + memcpy(var, *buf, size); + *buf += size; } #undef IF_0_THEN_256 -#define IF_0_THEN_256( n ) ((uint8) ((n) - 1) + 1) +#define IF_0_THEN_256(n) ((uint8)((n)-1) + 1) void S9xAPULoadBlarggState(uint8 *oldblock) { - uint8 *ptr = oldblock; + uint8 *ptr = oldblock; - SNES::SPC_State_Copier copier(&ptr,to_var_from_buf); + SNES::SPC_State_Copier copier(&ptr, to_var_from_buf); - copier.copy(SNES::smp.apuram,0x10000); // RAM + copier.copy(SNES::smp.apuram, 0x10000); // RAM - uint8 regs_in [0x10]; - uint8 regs [0x10]; + uint8 regs_in[0x10]; + uint8 regs[0x10]; uint16 pc, spc_time, dsp_time; - uint8 a,x,y,psw,sp; + uint8 a, x, y, psw, sp; - copier.copy(regs,0x10); // REGS - copier.copy(regs_in,0x10); // REGS_IN + copier.copy(regs, 0x10); // REGS + copier.copy(regs_in, 0x10); // REGS_IN // CPU Regs - pc = copier.copy_int( 0, sizeof(uint16) ); - a = copier.copy_int( 0, sizeof(uint8) ); - x = copier.copy_int( 0, sizeof(uint8) ); - y = copier.copy_int( 0, sizeof(uint8) ); - psw = copier.copy_int( 0, sizeof(uint8) ); - sp = copier.copy_int( 0, sizeof(uint8) ); + pc = copier.copy_int(0, sizeof(uint16)); + a = copier.copy_int(0, sizeof(uint8)); + x = copier.copy_int(0, sizeof(uint8)); + y = copier.copy_int(0, sizeof(uint8)); + psw = copier.copy_int(0, sizeof(uint8)); + sp = copier.copy_int(0, sizeof(uint8)); copier.extra(); // times - spc_time = copier.copy_int( 0, sizeof(uint16) ); - dsp_time = copier.copy_int( 0, sizeof(uint16) ); + spc_time = copier.copy_int(0, sizeof(uint16)); + dsp_time = copier.copy_int(0, sizeof(uint16)); int cur_time = S9xAPUGetClock(CPU.Cycles); @@ -641,16 +483,16 @@ void S9xAPULoadBlarggState(uint8 *oldblock) // Timers uint16 next_time[3]; uint8 divider[3], counter[3]; - for ( int i = 0; i < 3; i++ ) + for (int i = 0; i < 3; i++) { - next_time[i] = copier.copy_int( 0, sizeof(uint16) ); - divider[i] = copier.copy_int( 0, sizeof(uint8) ); - counter[i] = copier.copy_int( 0, sizeof(uint8) ); + next_time[i] = copier.copy_int(0, sizeof(uint16)); + divider[i] = copier.copy_int(0, sizeof(uint8)); + counter[i] = copier.copy_int(0, sizeof(uint8)); copier.extra(); } // construct timers out of available parts from blargg smp - SNES::smp.timer0.enable = regs[1] >> 0 & 1; // regs[1] = CONTROL - SNES::smp.timer0.target = IF_0_THEN_256(regs[10]); // regs[10+i] = TiTARGET + SNES::smp.timer0.enable = regs[1] >> 0 & 1; // regs[1] = CONTROL + SNES::smp.timer0.target = IF_0_THEN_256(regs[10]); // regs[10+i] = TiTARGET // blargg counts time, get ticks through timer frequency // (assume tempo = 256) SNES::smp.timer0.stage1_ticks = 128 - (next_time[0] - cur_time) / 128; @@ -692,40 +534,40 @@ void S9xAPULoadBlarggState(uint8 *oldblock) SNES::smp.status.ram00f9 = regs_in[9]; // default to 0 - we are on an opcode boundary, shouldn't matter - SNES::smp.rd=SNES::smp.wr=SNES::smp.dp=SNES::smp.sp=SNES::smp.ya=SNES::smp.bit=0; + SNES::smp.rd = SNES::smp.wr = SNES::smp.dp = SNES::smp.sp = SNES::smp.ya = SNES::smp.bit = 0; spc::reference_time = SNES::get_le32(ptr); ptr += sizeof(int32); spc::remainder = SNES::get_le32(ptr); // blargg stores CPUIx in regs_in - memcpy (SNES::cpu.registers, regs_in + 4, 4); + memcpy(SNES::cpu.registers, regs_in + 4, 4); } -bool8 S9xSPCDump (const char *filename) +bool8 S9xSPCDump(const char *filename) { - FILE *fs; - uint8 buf[SPC_FILE_SIZE]; - size_t ignore; + FILE *fs; + uint8 buf[SPC_FILE_SIZE]; + size_t ignore; - fs = fopen(filename, "wb"); - if (!fs) - return (FALSE); + fs = fopen(filename, "wb"); + if (!fs) + return (FALSE); - S9xSetSoundMute(TRUE); + S9xSetSoundMute(TRUE); - SNES::smp.save_spc (buf); + SNES::smp.save_spc(buf); - ignore = fwrite (buf, SPC_FILE_SIZE, 1, fs); + ignore = fwrite(buf, SPC_FILE_SIZE, 1, fs); - if (ignore == 0) - { - fprintf (stderr, "Couldn't write file %s.\n", filename); - } + if (ignore == 0) + { + fprintf(stderr, "Couldn't write file %s.\n", filename); + } - fclose(fs); + fclose(fs); - S9xSetSoundMute(FALSE); + S9xSetSoundMute(FALSE); - return (TRUE); + return (TRUE); } diff --git a/apu/hermite_resampler.h b/apu/hermite_resampler.h index a95723f2..f77b2793 100644 --- a/apu/hermite_resampler.h +++ b/apu/hermite_resampler.h @@ -62,7 +62,7 @@ class HermiteResampler : public Resampler clear (void) { ring_buffer::clear (); - r_frac = 1.0; + r_frac = 0.0; r_left [0] = r_left [1] = r_left [2] = r_left [3] = 0; r_right[0] = r_right[1] = r_right[2] = r_right[3] = 0; } @@ -138,7 +138,7 @@ class HermiteResampler : public Resampler return (ring_buffer::space_filled() + sizeof(short) - 1) / sizeof(short); } - return (int) floor (((size >> 2) - r_frac) / r_step) * 2; + return (int) trunc (((size >> 2) - r_frac) / r_step) * 2; } }; diff --git a/gtk/src/gtk_sound_driver_alsa.cpp b/gtk/src/gtk_sound_driver_alsa.cpp index 39a0908b..9eeb2123 100644 --- a/gtk/src/gtk_sound_driver_alsa.cpp +++ b/gtk/src/gtk_sound_driver_alsa.cpp @@ -85,17 +85,17 @@ bool S9xAlsaSoundDriver::open_device() } printf (" --> (%s, %s, %dhz, %d ms)...\n", - Settings.SixteenBitSound ? "16-bit" : "8-bit", - Settings.Stereo ? "Stereo" : "Mono", + "16-bit", + "Stereo", Settings.SoundPlaybackRate, gui_config->sound_buffer_size); snd_pcm_hw_params_alloca (&hw_params); snd_pcm_hw_params_any (pcm, hw_params); - snd_pcm_hw_params_set_format (pcm, hw_params, Settings.SixteenBitSound ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8); + snd_pcm_hw_params_set_format (pcm, hw_params, SND_PCM_FORMAT_S16); snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_rate_resample (pcm, hw_params, 0); - snd_pcm_hw_params_set_channels (pcm, hw_params, Settings.Stereo ? 2 : 1); + snd_pcm_hw_params_set_channels (pcm, hw_params, 2); snd_pcm_hw_params_get_rate_min (hw_params, &min, NULL); snd_pcm_hw_params_get_rate_max (hw_params, &max, NULL); @@ -190,14 +190,14 @@ S9xAlsaSoundDriver::samples_available () { // Using rate control, we should always keep the emulator's sound buffers empty to // maintain an accurate measurement. - if (frames < (S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0))) + if (frames < (S9xGetSampleCount () >> 1)) { S9xClearSamples (); return; } } - frames = MIN (frames, S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0)); + frames = MIN (frames, S9xGetSampleCount () >> 1); bytes = snd_pcm_frames_to_bytes (pcm, frames); @@ -212,7 +212,7 @@ S9xAlsaSoundDriver::samples_available () sound_buffer_size = bytes; } - S9xMixSamples (sound_buffer, frames << (Settings.Stereo ? 1 : 0)); + S9xMixSamples (sound_buffer, frames * 2); frames_written = 0; diff --git a/gtk/src/gtk_sound_driver_oss.cpp b/gtk/src/gtk_sound_driver_oss.cpp index a1aabd69..ec5a0525 100644 --- a/gtk/src/gtk_sound_driver_oss.cpp +++ b/gtk/src/gtk_sound_driver_oss.cpp @@ -66,10 +66,7 @@ bool S9xOSSSoundDriver::open_device() output_buffer_size = (gui_config->sound_buffer_size * Settings.SoundPlaybackRate) / 1000; - if (Settings.Stereo) - output_buffer_size *= 2; - if (Settings.SixteenBitSound) - output_buffer_size *= 2; + output_buffer_size *= 4; if (output_buffer_size < 256) output_buffer_size = 256; @@ -106,35 +103,16 @@ bool S9xOSSSoundDriver::open_device() printf ("OK\n"); - if (Settings.SixteenBitSound) - { - printf (" --> (Format: 16-bit)..."); + printf (" --> (Format: 16-bit)..."); - temp = AFMT_S16_LE; - if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0) - goto close_fail; - } - else - { - printf (" --> (Format: 8-bit)..."); - - temp = AFMT_U8; - if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0) - goto close_fail; - } + temp = AFMT_S16_LE; + if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0) + goto close_fail; printf ("OK\n"); - if (Settings.Stereo) - { - temp = 2; - printf (" --> (Stereo)..."); - } - else - { - temp = 1; - printf (" --> (Mono)..."); - } + temp = 2; + printf (" --> (Stereo)..."); if (ioctl (filedes, SNDCTL_DSP_CHANNELS, &temp) < 0) goto close_fail; @@ -160,9 +138,7 @@ bool S9xOSSSoundDriver::open_device() printf (" --> (Buffer size: %d bytes, %dms latency)...", output_buffer_size, - (((output_buffer_size * 1000) >> (Settings.Stereo ? 1 : 0)) - >> (Settings.SixteenBitSound ? 1 : 0)) - / (Settings.SoundPlaybackRate)); + (output_buffer_size * 250) / Settings.SoundPlaybackRate); printf ("OK\n"); @@ -203,29 +179,28 @@ S9xOSSSoundDriver::samples_available () { // Using rate control, we should always keep the emulator's sound buffers empty to // maintain an accurate measurement. - if (samples_to_write > (info.bytes >> (Settings.SixteenBitSound ? 1 : 0))) + if (samples_to_write > (info.bytes >> 1)) { S9xClearSamples (); return; } } - samples_to_write = MIN (info.bytes >> (Settings.SixteenBitSound ? 1 : 0), - samples_to_write); + samples_to_write = MIN (info.bytes >> 1, samples_to_write) & ~1; if (samples_to_write < 0) return; - if (sound_buffer_size < samples_to_write << (Settings.SixteenBitSound ? 1 : 0)) + if (sound_buffer_size < samples_to_write * 2) { - sound_buffer = (uint8 *) realloc (sound_buffer, samples_to_write << (Settings.SixteenBitSound ? 1 : 0)); - sound_buffer_size = samples_to_write << (Settings.SixteenBitSound ? 1 : 0); + sound_buffer = (uint8 *) realloc (sound_buffer, samples_to_write * 2); + sound_buffer_size = samples_to_write * 2; } S9xMixSamples (sound_buffer, samples_to_write); bytes_written = 0; - bytes_to_write = samples_to_write << (Settings.SixteenBitSound ? 1 : 0); + bytes_to_write = samples_to_write * 2; while (bytes_to_write > bytes_written) { diff --git a/gtk/src/gtk_sound_driver_portaudio.cpp b/gtk/src/gtk_sound_driver_portaudio.cpp index fdddc623..2cc84855 100644 --- a/gtk/src/gtk_sound_driver_portaudio.cpp +++ b/gtk/src/gtk_sound_driver_portaudio.cpp @@ -10,7 +10,7 @@ static inline int frames_to_bytes (int frames) { - return (frames * (Settings.SixteenBitSound ? 2 : 1) * (Settings.Stereo ? 2 : 1)); + return frames * 4; } static void @@ -106,8 +106,8 @@ bool S9xPortAudioSoundDriver::open_device() audio_stream = NULL; } - param.channelCount = Settings.Stereo ? 2 : 1; - param.sampleFormat = Settings.SixteenBitSound ? paInt16 : paUInt8; + param.channelCount = 2; + param.sampleFormat = paInt16; param.hostApiSpecificStreamInfo = NULL; printf ("PortAudio sound driver initializing...\n"); @@ -200,14 +200,14 @@ S9xPortAudioSoundDriver::samples_available () { // Using rate control, we should always keep the emulator's sound buffers empty to // maintain an accurate measurement. - if (frames < (S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0))) + if (frames < (S9xGetSampleCount () >> 1)) { S9xClearSamples (); return; } } - frames = MIN (frames, S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0)); + frames = MIN (frames, S9xGetSampleCount () >> 1); bytes = frames_to_bytes (frames); if (sound_buffer_size < bytes || sound_buffer == NULL) @@ -216,7 +216,7 @@ S9xPortAudioSoundDriver::samples_available () sound_buffer_size = bytes; } - S9xMixSamples (sound_buffer, frames << (Settings.Stereo ? 1 : 0)); + S9xMixSamples (sound_buffer, frames << 1); Pa_WriteStream (audio_stream, sound_buffer, frames); } diff --git a/gtk/src/gtk_sound_driver_pulse.cpp b/gtk/src/gtk_sound_driver_pulse.cpp index 6e2c26a4..fb24f883 100644 --- a/gtk/src/gtk_sound_driver_pulse.cpp +++ b/gtk/src/gtk_sound_driver_pulse.cpp @@ -11,13 +11,12 @@ #include #include -static void -pulse_samples_available (void *data) +static void pulse_samples_available(void *data) { - ((S9xPulseSoundDriver *) data)->samples_available (); + ((S9xPulseSoundDriver *)data)->samples_available(); } -S9xPulseSoundDriver::S9xPulseSoundDriver () +S9xPulseSoundDriver::S9xPulseSoundDriver() { mainloop = NULL; context = NULL; @@ -25,94 +24,85 @@ S9xPulseSoundDriver::S9xPulseSoundDriver () buffer_size = 0; } -void -S9xPulseSoundDriver::init () +void S9xPulseSoundDriver::init() { } -void -S9xPulseSoundDriver::terminate () +void S9xPulseSoundDriver::terminate() { - S9xSetSamplesAvailableCallback (NULL, NULL); + S9xSetSamplesAvailableCallback(NULL, NULL); if (mainloop) - pa_threaded_mainloop_stop (mainloop); + pa_threaded_mainloop_stop(mainloop); if (stream) { - pa_stream_disconnect (stream); - pa_stream_unref (stream); + pa_stream_disconnect(stream); + pa_stream_unref(stream); } if (context) { - pa_context_disconnect (context); - pa_context_unref (context); + pa_context_disconnect(context); + pa_context_unref(context); } if (mainloop) { - pa_threaded_mainloop_free (mainloop); + pa_threaded_mainloop_free(mainloop); } } -void -S9xPulseSoundDriver::start () +void S9xPulseSoundDriver::start() { } -void -S9xPulseSoundDriver::stop () +void S9xPulseSoundDriver::stop() { } -void -S9xPulseSoundDriver::lock () +void S9xPulseSoundDriver::lock() { - pa_threaded_mainloop_lock (mainloop); + pa_threaded_mainloop_lock(mainloop); } -void -S9xPulseSoundDriver::unlock () +void S9xPulseSoundDriver::unlock() { - pa_threaded_mainloop_unlock (mainloop); + pa_threaded_mainloop_unlock(mainloop); } -void -S9xPulseSoundDriver::wait () +void S9xPulseSoundDriver::wait() { - pa_threaded_mainloop_wait (mainloop); + pa_threaded_mainloop_wait(mainloop); } -static void -context_state_cb (pa_context *c, void *userdata) +static void context_state_cb(pa_context *c, void *userdata) { - S9xPulseSoundDriver *driver = (S9xPulseSoundDriver *) userdata; + S9xPulseSoundDriver *driver = (S9xPulseSoundDriver *)userdata; int state; - state = pa_context_get_state (c); + state = pa_context_get_state(c); - if (state == PA_CONTEXT_READY || - state == PA_CONTEXT_FAILED || + if (state == PA_CONTEXT_READY || + state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { - pa_threaded_mainloop_signal (driver->mainloop, 0); + pa_threaded_mainloop_signal(driver->mainloop, 0); } } -static void -stream_state_callback (pa_stream *p, void *userdata) +static void stream_state_callback(pa_stream *p, void *userdata) { - S9xPulseSoundDriver *driver = (S9xPulseSoundDriver *) userdata; + S9xPulseSoundDriver *driver = (S9xPulseSoundDriver *)userdata; int state; - state = pa_stream_get_state (p); + state = pa_stream_get_state(p); - if (state == PA_STREAM_READY || - state == PA_STREAM_FAILED || + if (state == PA_STREAM_READY || + state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED) { - pa_threaded_mainloop_signal (driver->mainloop, 0); + pa_threaded_mainloop_signal(driver->mainloop, 0); } } @@ -123,154 +113,154 @@ bool S9xPulseSoundDriver::open_device() pa_buffer_attr buffer_attr; const pa_buffer_attr *actual_buffer_attr; - ss.channels = Settings.Stereo ? 2 : 1; - ss.format = Settings.SixteenBitSound ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; - ss.rate = Settings.SoundPlaybackRate; + ss.channels = 2; + ss.format = PA_SAMPLE_S16NE; + ss.rate = Settings.SoundPlaybackRate; - buffer_attr.fragsize = -1; - buffer_attr.tlength = pa_usec_to_bytes (gui_config->sound_buffer_size * 1000, &ss); - buffer_attr.maxlength = -1; - buffer_attr.minreq = -1; - buffer_attr.prebuf = -1; + buffer_attr.fragsize = -1; + buffer_attr.tlength = pa_usec_to_bytes(gui_config->sound_buffer_size * 1000, &ss); + buffer_attr.maxlength = buffer_attr.tlength * 2; + buffer_attr.minreq = -1; + buffer_attr.prebuf = -1; - printf ("PulseAudio sound driver initializing...\n"); + printf("PulseAudio sound driver initializing...\n"); - printf (" --> (%dhz, %s %s, %dms)...", - Settings.SoundPlaybackRate, - Settings.SixteenBitSound ? "16-bit" : "8-bit", - Settings.Stereo ? "Stereo" : "Mono", - gui_config->sound_buffer_size); - fflush (stdout); + printf(" --> (%dhz, %s %s, %dms)...", + Settings.SoundPlaybackRate, + "16-bit", + "Stereo", + gui_config->sound_buffer_size); + fflush(stdout); - mainloop = pa_threaded_mainloop_new (); + mainloop = pa_threaded_mainloop_new(); if (!mainloop) { - fprintf (stderr, "Failed to create mainloop.\n"); + fprintf(stderr, "Failed to create mainloop.\n"); goto error0; } - context = pa_context_new (pa_threaded_mainloop_get_api (mainloop), "Snes9x"); + context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Snes9x"); if (!context) goto error1; - pa_context_set_state_callback (context, context_state_cb, this); - if ((err = pa_context_connect (context, NULL, PA_CONTEXT_NOFLAGS, NULL)) != 0) + pa_context_set_state_callback(context, context_state_cb, this); + if ((err = pa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL)) != 0) goto error2; - lock (); + lock(); - if ((err = pa_threaded_mainloop_start (mainloop)) != 0) + if ((err = pa_threaded_mainloop_start(mainloop)) != 0) goto error2; - wait (); + wait(); - if ((err = pa_context_get_state (context)) != PA_CONTEXT_READY) + if ((err = pa_context_get_state(context)) != PA_CONTEXT_READY) { - printf ("Coundn't create context: State: %d\n", err); + printf("Coundn't create context: State: %d\n", err); goto error2; } - stream = pa_stream_new (context, "Game", &ss, NULL); + stream = pa_stream_new(context, "Game", &ss, NULL); if (!stream) goto error2; - pa_stream_set_state_callback (stream, stream_state_callback, this); + pa_stream_set_state_callback(stream, stream_state_callback, this); - if (pa_stream_connect_playback (stream, - NULL, - &buffer_attr, - PA_STREAM_ADJUST_LATENCY, - NULL, - NULL) < 0) + if (pa_stream_connect_playback(stream, + NULL, + &buffer_attr, + PA_STREAM_ADJUST_LATENCY, + NULL, + NULL) < 0) goto error3; - wait (); + wait(); - if (pa_stream_get_state (stream) != PA_STREAM_READY) + if (pa_stream_get_state(stream) != PA_STREAM_READY) { goto error3; } - actual_buffer_attr = pa_stream_get_buffer_attr (stream); + actual_buffer_attr = pa_stream_get_buffer_attr(stream); buffer_size = actual_buffer_attr->tlength; - printf ("OK\n"); + printf("OK\n"); - S9xSetSamplesAvailableCallback (pulse_samples_available, this); + S9xSetSamplesAvailableCallback(pulse_samples_available, this); - unlock (); + unlock(); return true; error3: - pa_stream_disconnect (stream); - pa_stream_unref (stream); + pa_stream_disconnect(stream); + pa_stream_unref(stream); error2: - pa_context_disconnect (context); - pa_context_unref (context); - unlock (); + pa_context_disconnect(context); + pa_context_unref(context); + unlock(); error1: - pa_threaded_mainloop_free (mainloop); + pa_threaded_mainloop_free(mainloop); error0: - printf ("Failed: %s\n", pa_strerror (err)); + printf("Failed: %s\n", pa_strerror(err)); return false; } -void -S9xPulseSoundDriver::samples_available () +void S9xPulseSoundDriver::samples_available() { size_t bytes; int samples; const pa_buffer_attr *buffer_attr; void *output_buffer = NULL; - lock (); - bytes = pa_stream_writable_size (stream); - buffer_attr = pa_stream_get_buffer_attr (stream); - unlock (); + lock(); + bytes = pa_stream_writable_size(stream); + buffer_attr = pa_stream_get_buffer_attr(stream); + unlock(); buffer_size = buffer_attr->tlength; if (Settings.DynamicRateControl) { - S9xUpdateDynamicRate (bytes, buffer_size); + S9xUpdateDynamicRate(bytes, buffer_size); } - S9xFinalizeSamples (); + S9xFinalizeSamples(); - samples = S9xGetSampleCount (); + samples = S9xGetSampleCount(); if (Settings.DynamicRateControl) { - if ((int) bytes < (samples << (Settings.SixteenBitSound ? 1 : 0))) + if ((int)bytes < (samples * 2)) { - S9xClearSamples (); + S9xClearSamples(); return; } } - bytes = MIN ((int) bytes, (samples << (Settings.SixteenBitSound ? 1 : 0))); + bytes = MIN((int)bytes, samples * 2) & ~1; if (!bytes) return; - lock (); + lock(); - if (pa_stream_begin_write (stream, &output_buffer, &bytes) != 0) + if (pa_stream_begin_write(stream, &output_buffer, &bytes) != 0) { - pa_stream_flush (stream, NULL, NULL); - unlock (); + pa_stream_flush(stream, NULL, NULL); + unlock(); return; } + if (bytes <= 0 || !output_buffer) { - unlock (); + unlock(); return; } - S9xMixSamples ((uint8 *) output_buffer, bytes >> (Settings.SixteenBitSound ? 1 : 0)); - pa_stream_write (stream, output_buffer, bytes, NULL, 0, PA_SEEK_RELATIVE); + S9xMixSamples((uint8 *)output_buffer, bytes >> 1); + pa_stream_write(stream, output_buffer, bytes, NULL, 0, PA_SEEK_RELATIVE); - unlock (); + unlock(); }