From 19f03c44de09af04dc9e82d6542cefe179009a35 Mon Sep 17 00:00:00 2001 From: Brandon Wright Date: Tue, 5 Feb 2019 17:20:23 -0600 Subject: [PATCH] Revert "APU: Big refactor." I'll put this in a branch. This reverts commit aebfc85cdfae38fddc11da5c7d418e5f67cda39f. --- 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, 659 insertions(+), 466 deletions(-) diff --git a/apu/apu.cpp b/apu/apu.cpp index 66af4517..5afcb5dd 100644 --- a/apu/apu.cpp +++ b/apu/apu.cpp @@ -4,8 +4,7 @@ For further information, consult the LICENSE file in the root directory. \*****************************************************************************/ -#include -#include +#include #include "../snes9x.h" #include "apu.h" #include "../msu1.h" @@ -15,460 +14,619 @@ #include "bapu/snes/snes.hpp" -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; +#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 namespace SNES { #include "bapu/dsp/blargg_endian.h" -CPU cpu; + + CPU cpu; } namespace spc { -static apu_callback callback = NULL; -static void *callback_data = NULL; + static apu_callback sa_callback = NULL; + static void *extra_data = NULL; -static bool8 sound_in_sync = TRUE; -static bool8 sound_enabled = FALSE; -static uint16 dsp_buffer[MAX_SAMPLE_FRAMES * 2]; + static bool8 sound_in_sync = TRUE; + static bool8 sound_enabled = FALSE; -static Resampler *resampler = NULL; + static int buffer_size; + static int lag_master = 0; + static int lag = 0; -static int32 reference_time; -static uint32 remainder; + static uint8 *landing_buffer = NULL; + static uint8 *shrink_buffer = 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 Resampler *resampler = NULL; -static double dynamic_rate_multiplier = 1.0; + 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; } namespace msu { -// 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 int buffer_size; + static uint8 *landing_buffer = NULL; + static Resampler *resampler = NULL; + static int resample_buffer_size = -1; + static uint8 *resample_buffer = NULL; } -static void UpdatePlaybackRate(void); -static void SPCSnapshotCallback(void); -static inline int S9xAPUGetClock(int32); -static inline int S9xAPUGetClockRemainder(int32); +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 reset_dsp_output() + +static void EightBitize (uint8 *buffer, int sample_count) { - SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *)spc::dsp_buffer, - MAX_SAMPLE_FRAMES * 2); + uint8 *buf8 = (uint8 *) buffer; + int16 *buf16 = (int16 *) buffer; + + for (int i = 0; i < sample_count; i++) + buf8[i] = (uint8) ((buf16[i] / 256) + 128); } -bool8 S9xMixSamples(uint8 *dest, int sample_count) +static void DeStereo (uint8 *buffer, int sample_count) { - int16 *out = (int16 *)dest; + int16 *buf = (int16 *) buffer; + int32 s1, s2; - 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; + 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); + } } -int S9xGetSampleCount(void) +static void ReverseStereo (uint8 *src_buffer, int sample_count) { - return spc::resampler->avail(); + 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]; + } } -void S9xFinalizeSamples(void) +bool8 S9xMixSamples (uint8 *buffer, int sample_count) { - bool drop_msu1_samples = true; + static int shrink_buffer_size = -1; + uint8 *dest; - if (!Settings.Mute) - { - drop_msu1_samples = false; + if (!Settings.SixteenBitSound || !Settings.Stereo) + { + /* We still need both stereo samples for generating the mono sample */ + if (!Settings.Stereo) + 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; - } - } + /* 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; + } - // 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); - } - } + dest = spc::shrink_buffer; + } + else + dest = buffer; - 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.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; + } - reset_dsp_output(); + 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); } -void S9xLandSamples(void) +int S9xGetSampleCount (void) { - if (spc::callback != NULL) - spc::callback(spc::callback_data); - else - S9xFinalizeSamples(); + return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1)); } -void S9xClearSamples(void) +/* TODO: Attach */ +void S9xFinalizeSamples (void) { - spc::resampler->clear(); - if (Settings.MSU1) - msu::resampler->clear(); + 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); } -bool8 S9xSyncSound(void) +void S9xLandSamples (void) { - if (!Settings.SoundSync || spc::sound_in_sync) - return (TRUE); - - S9xLandSamples(); - - return (spc::sound_in_sync); + if (spc::sa_callback != NULL) + spc::sa_callback(spc::extra_data); + else + S9xFinalizeSamples(); } -void S9xSetSamplesAvailableCallback(apu_callback callback, void *data) +void S9xClearSamples (void) { - spc::callback = callback; - spc::callback_data = data; + spc::resampler->clear(); + if (Settings.MSU1) + msu::resampler->clear(); + spc::lag = spc::lag_master; } -void S9xUpdateDynamicRate(int avail, int buffer_size) +bool8 S9xSyncSound (void) { - spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / - (double)(1000 * buffer_size); + if (!Settings.SoundSync || spc::sound_in_sync) + return (TRUE); - UpdatePlaybackRate(); + S9xLandSamples(); + + return (spc::sound_in_sync); } -static void UpdatePlaybackRate(void) +void S9xSetSamplesAvailableCallback (apu_callback callback, void *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); - } + spc::sa_callback = callback; + spc::extra_data = data; } -bool8 S9xInitSound(int unused, int unused2) +void S9xUpdateDynamicRate (int avail, int 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); - } + spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / + (double)(1000 * buffer_size); - 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); + UpdatePlaybackRate(); } -void S9xSetSoundControl(uint8 voice_switch) +static void UpdatePlaybackRate (void) { - SNES::dsp.spc_dsp.set_stereo_switch(voice_switch << 8 | 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); + } } -void S9xSetSoundMute(bool8 mute) +bool8 S9xInitSound (int buffer_ms, int lag_ms) { - Settings.Mute = mute; - if (!spc::sound_enabled) - Settings.Mute = TRUE; + // 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); } -void S9xDumpSPCSnapshot(void) +void S9xSetSoundControl (uint8 voice_switch) { - SNES::dsp.spc_dsp.dump_spc_snapshot(); + SNES::dsp.spc_dsp.set_stereo_switch (voice_switch << 8 | voice_switch); } -static void SPCSnapshotCallback(void) +void S9xSetSoundMute (bool8 mute) { - S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR)); - printf("Dumped key-on triggered spc snapshot.\n"); + Settings.Mute = mute; + if (!spc::sound_enabled) + Settings.Mute = TRUE; } -bool8 S9xInitAPU(void) +void S9xDumpSPCSnapshot (void) { - spc::resampler = NULL; - msu::resampler = NULL; + SNES::dsp.spc_dsp.dump_spc_snapshot(); - return (TRUE); } -void S9xDeinitAPU(void) +static void SPCSnapshotCallback (void) { - if (spc::resampler) - { - delete spc::resampler; - spc::resampler = NULL; - } - - if (msu::resampler) - { - delete msu::resampler; - msu::resampler = NULL; - } - - S9xMSU1DeInit(); + S9xSPCDump(S9xGetFilenameInc((".spc"), SPC_DIR)); + printf("Dumped key-on triggered spc snapshot.\n"); } -static inline int S9xAPUGetClock(int32 cpucycles) +bool8 S9xInitAPU (void) { - return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / - spc::ratio_denominator; + spc::landing_buffer = NULL; + spc::shrink_buffer = NULL; + spc::resampler = NULL; + msu::resampler = NULL; + + return (TRUE); } -static inline int S9xAPUGetClockRemainder(int32 cpucycles) +void S9xDeinitAPU (void) { - return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % - spc::ratio_denominator; + 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(); } -uint8 S9xAPUReadPort(int port) +static inline int S9xAPUGetClock (int32 cpucycles) { - S9xAPUExecute(); - return ((uint8)SNES::smp.port_read(port & 3)); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) / + spc::ratio_denominator; } -void S9xAPUWritePort(int port, uint8 byte) +static inline int S9xAPUGetClockRemainder (int32 cpucycles) { - S9xAPUExecute(); - SNES::cpu.port_write(port & 3, byte); + return (spc::ratio_numerator * (cpucycles - spc::reference_time) + spc::remainder) % + spc::ratio_denominator; } -void S9xAPUSetReferenceTime(int32 cpucycles) +uint8 S9xAPUReadPort (int port) { - spc::reference_time = cpucycles; + S9xAPUExecute (); + return ((uint8) SNES::smp.port_read (port & 3)); } -void S9xAPUExecute(void) +void S9xAPUWritePort (int port, uint8 byte) { - SNES::smp.clock -= S9xAPUGetClock(CPU.Cycles); - SNES::smp.enter(); - - spc::remainder = S9xAPUGetClockRemainder(CPU.Cycles); - - S9xAPUSetReferenceTime(CPU.Cycles); + S9xAPUExecute (); + SNES::cpu.port_write (port & 3, byte); } -void S9xAPUEndScanline(void) +void S9xAPUSetReferenceTime (int32 cpucycles) { - S9xAPUExecute(); - SNES::dsp.synchronize(); - - if (SNES::dsp.spc_dsp.sample_count() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync) - S9xLandSamples(); + spc::reference_time = cpucycles; } -void S9xAPUTimingSetSpeedup(int ticks) +void S9xAPUExecute (void) { - if (ticks != 0) - printf("APU speedup hack: %d\n", ticks); + SNES::smp.clock -= S9xAPUGetClock (CPU.Cycles); + SNES::smp.enter (); - spc::timing_hack_denominator = 256 - ticks; + spc::remainder = S9xAPUGetClockRemainder(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(); + S9xAPUSetReferenceTime(CPU.Cycles); } -void S9xResetAPU(void) +void S9xAPUEndScanline (void) { - spc::reference_time = 0; - spc::remainder = 0; + S9xAPUExecute(); + SNES::dsp.synchronize(); - 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(); + if (SNES::dsp.spc_dsp.sample_count() >= APU_MINIMUM_SAMPLE_BLOCK || !spc::sound_in_sync) + S9xLandSamples(); } -void S9xSoftResetAPU(void) +void S9xAPUTimingSetSpeedup (int ticks) { - spc::reference_time = 0; - spc::remainder = 0; - SNES::cpu.reset(); - SNES::smp.reset(); - SNES::dsp.reset(); - reset_dsp_output(); + if (ticks != 0) + printf("APU speedup hack: %d\n", ticks); - spc::resampler->clear(); + spc::timing_hack_denominator = 256 - ticks; - if (Settings.MSU1) - msu::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(); } -void S9xAPUSaveState(uint8 *block) +void S9xResetAPU (void) { - uint8 *ptr = block; + spc::reference_time = 0; + spc::remainder = 0; - SNES::smp.save_state(&ptr); - SNES::dsp.save_state(&ptr); + 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::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); + spc::resampler->clear(); - memset(ptr, 0, SPC_SAVE_STATE_BLOCK_SIZE - (ptr - block)); + if (Settings.MSU1) + msu::resampler->clear(); } -void S9xAPULoadState(uint8 *block) +void S9xSoftResetAPU (void) { - uint8 *ptr = 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); - SNES::smp.load_state(&ptr); - SNES::dsp.load_state(&ptr); + spc::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); + if (Settings.MSU1) + msu::resampler->clear(); } -static void to_var_from_buf(uint8 **buf, void *var, size_t size) +void S9xAPUSaveState (uint8 *block) { - memcpy(var, *buf, size); - *buf += 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; } #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); @@ -483,16 +641,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; @@ -534,40 +692,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 f77b2793..a95723f2 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 = 0.0; + r_frac = 1.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) trunc (((size >> 2) - r_frac) / r_step) * 2; + return (int) floor (((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 9eeb2123..39a0908b 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", - "16-bit", - "Stereo", + Settings.SixteenBitSound ? "16-bit" : "8-bit", + Settings.Stereo ? "Stereo" : "Mono", 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, SND_PCM_FORMAT_S16); + snd_pcm_hw_params_set_format (pcm, hw_params, Settings.SixteenBitSound ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8); 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, 2); + snd_pcm_hw_params_set_channels (pcm, hw_params, Settings.Stereo ? 2 : 1); 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 () >> 1)) + if (frames < (S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0))) { S9xClearSamples (); return; } } - frames = MIN (frames, S9xGetSampleCount () >> 1); + frames = MIN (frames, S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0)); bytes = snd_pcm_frames_to_bytes (pcm, frames); @@ -212,7 +212,7 @@ S9xAlsaSoundDriver::samples_available () sound_buffer_size = bytes; } - S9xMixSamples (sound_buffer, frames * 2); + S9xMixSamples (sound_buffer, frames << (Settings.Stereo ? 1 : 0)); frames_written = 0; diff --git a/gtk/src/gtk_sound_driver_oss.cpp b/gtk/src/gtk_sound_driver_oss.cpp index ec5a0525..a1aabd69 100644 --- a/gtk/src/gtk_sound_driver_oss.cpp +++ b/gtk/src/gtk_sound_driver_oss.cpp @@ -66,7 +66,10 @@ bool S9xOSSSoundDriver::open_device() output_buffer_size = (gui_config->sound_buffer_size * Settings.SoundPlaybackRate) / 1000; - output_buffer_size *= 4; + if (Settings.Stereo) + output_buffer_size *= 2; + if (Settings.SixteenBitSound) + output_buffer_size *= 2; if (output_buffer_size < 256) output_buffer_size = 256; @@ -103,16 +106,35 @@ bool S9xOSSSoundDriver::open_device() printf ("OK\n"); - printf (" --> (Format: 16-bit)..."); + if (Settings.SixteenBitSound) + { + printf (" --> (Format: 16-bit)..."); - temp = AFMT_S16_LE; - 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; + } + else + { + printf (" --> (Format: 8-bit)..."); + + temp = AFMT_U8; + if (ioctl (filedes, SNDCTL_DSP_SETFMT, &temp) < 0) + goto close_fail; + } printf ("OK\n"); - temp = 2; - printf (" --> (Stereo)..."); + if (Settings.Stereo) + { + temp = 2; + printf (" --> (Stereo)..."); + } + else + { + temp = 1; + printf (" --> (Mono)..."); + } if (ioctl (filedes, SNDCTL_DSP_CHANNELS, &temp) < 0) goto close_fail; @@ -138,7 +160,9 @@ bool S9xOSSSoundDriver::open_device() printf (" --> (Buffer size: %d bytes, %dms latency)...", output_buffer_size, - (output_buffer_size * 250) / Settings.SoundPlaybackRate); + (((output_buffer_size * 1000) >> (Settings.Stereo ? 1 : 0)) + >> (Settings.SixteenBitSound ? 1 : 0)) + / (Settings.SoundPlaybackRate)); printf ("OK\n"); @@ -179,28 +203,29 @@ 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 >> 1)) + if (samples_to_write > (info.bytes >> (Settings.SixteenBitSound ? 1 : 0))) { S9xClearSamples (); return; } } - samples_to_write = MIN (info.bytes >> 1, samples_to_write) & ~1; + samples_to_write = MIN (info.bytes >> (Settings.SixteenBitSound ? 1 : 0), + samples_to_write); if (samples_to_write < 0) return; - if (sound_buffer_size < samples_to_write * 2) + if (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; + sound_buffer = (uint8 *) realloc (sound_buffer, samples_to_write << (Settings.SixteenBitSound ? 1 : 0)); + sound_buffer_size = samples_to_write << (Settings.SixteenBitSound ? 1 : 0); } S9xMixSamples (sound_buffer, samples_to_write); bytes_written = 0; - bytes_to_write = samples_to_write * 2; + bytes_to_write = samples_to_write << (Settings.SixteenBitSound ? 1 : 0); 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 2cc84855..fdddc623 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 * 4; + return (frames * (Settings.SixteenBitSound ? 2 : 1) * (Settings.Stereo ? 2 : 1)); } static void @@ -106,8 +106,8 @@ bool S9xPortAudioSoundDriver::open_device() audio_stream = NULL; } - param.channelCount = 2; - param.sampleFormat = paInt16; + param.channelCount = Settings.Stereo ? 2 : 1; + param.sampleFormat = Settings.SixteenBitSound ? paInt16 : paUInt8; 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 () >> 1)) + if (frames < (S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0))) { S9xClearSamples (); return; } } - frames = MIN (frames, S9xGetSampleCount () >> 1); + frames = MIN (frames, S9xGetSampleCount () >> (Settings.Stereo ? 1 : 0)); 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 << 1); + S9xMixSamples (sound_buffer, frames << (Settings.Stereo ? 1 : 0)); 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 fb24f883..6e2c26a4 100644 --- a/gtk/src/gtk_sound_driver_pulse.cpp +++ b/gtk/src/gtk_sound_driver_pulse.cpp @@ -11,12 +11,13 @@ #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; @@ -24,85 +25,94 @@ 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); } } @@ -113,154 +123,154 @@ bool S9xPulseSoundDriver::open_device() pa_buffer_attr buffer_attr; const pa_buffer_attr *actual_buffer_attr; - ss.channels = 2; - ss.format = PA_SAMPLE_S16NE; - ss.rate = Settings.SoundPlaybackRate; + ss.channels = Settings.Stereo ? 2 : 1; + ss.format = Settings.SixteenBitSound ? PA_SAMPLE_S16NE : PA_SAMPLE_U8; + 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 = buffer_attr.tlength * 2; - 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 = -1; + 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, - "16-bit", - "Stereo", - gui_config->sound_buffer_size); - fflush(stdout); + printf (" --> (%dhz, %s %s, %dms)...", + Settings.SoundPlaybackRate, + Settings.SixteenBitSound ? "16-bit" : "8-bit", + Settings.Stereo ? "Stereo" : "Mono", + 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 * 2)) + if ((int) bytes < (samples << (Settings.SixteenBitSound ? 1 : 0))) { - S9xClearSamples(); + S9xClearSamples (); return; } } - bytes = MIN((int)bytes, samples * 2) & ~1; + bytes = MIN ((int) bytes, (samples << (Settings.SixteenBitSound ? 1 : 0))); 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 >> 1); - pa_stream_write(stream, output_buffer, bytes, NULL, 0, PA_SEEK_RELATIVE); + S9xMixSamples ((uint8 *) output_buffer, bytes >> (Settings.SixteenBitSound ? 1 : 0)); + pa_stream_write (stream, output_buffer, bytes, NULL, 0, PA_SEEK_RELATIVE); - unlock(); + unlock (); }