From bafea657e7c33f65c561bd91b7084fedd59def84 Mon Sep 17 00:00:00 2001 From: BearOso Date: Wed, 28 Jun 2023 17:58:00 -0500 Subject: [PATCH] Working. --- common/audio/s9x_sound_driver.hpp | 2 +- common/audio/s9x_sound_driver_alsa.cpp | 12 +++++-- common/audio/s9x_sound_driver_alsa.hpp | 2 +- common/audio/s9x_sound_driver_cubeb.cpp | 17 +++++++-- common/audio/s9x_sound_driver_cubeb.hpp | 2 +- common/audio/s9x_sound_driver_portaudio.cpp | 8 ++++- common/audio/s9x_sound_driver_portaudio.hpp | 2 +- common/audio/s9x_sound_driver_sdl.cpp | 16 ++++----- common/audio/s9x_sound_driver_sdl.hpp | 2 +- qt/src/EmuApplication.cpp | 38 +++++++++++++++++++-- qt/src/Snes9xController.cpp | 5 +++ qt/src/Snes9xController.hpp | 1 + 12 files changed, 84 insertions(+), 23 deletions(-) diff --git a/common/audio/s9x_sound_driver.hpp b/common/audio/s9x_sound_driver.hpp index 90a82b1b..03c0fdad 100644 --- a/common/audio/s9x_sound_driver.hpp +++ b/common/audio/s9x_sound_driver.hpp @@ -16,7 +16,7 @@ class S9xSoundDriver virtual ~S9xSoundDriver() { } - virtual void write_samples(int16_t *data, int samples) = 0; + virtual bool write_samples(int16_t *data, int samples) = 0; virtual int space_free() = 0; virtual std::pair buffer_level() = 0; virtual void init() = 0; diff --git a/common/audio/s9x_sound_driver_alsa.cpp b/common/audio/s9x_sound_driver_alsa.cpp index 8f7f51b6..809b3c4f 100644 --- a/common/audio/s9x_sound_driver_alsa.cpp +++ b/common/audio/s9x_sound_driver_alsa.cpp @@ -139,7 +139,7 @@ fail: return false; } -void S9xAlsaSoundDriver::write_samples(int16_t *data, int samples) +bool S9xAlsaSoundDriver::write_samples(int16_t *data, int samples) { snd_pcm_sframes_t frames_written, frames; size_t bytes; @@ -149,16 +149,20 @@ void S9xAlsaSoundDriver::write_samples(int16_t *data, int samples) if (frames < 0) { frames = snd_pcm_recover(pcm, frames, 1); - return; + return false; } + bool result = true; snd_pcm_nonblock(pcm, 0); if (frames > samples / 2) + { frames = samples / 2; + result = false; + } bytes = snd_pcm_frames_to_bytes(pcm, frames); if (bytes <= 0) - return; + return false; frames_written = 0; while (frames_written < frames) @@ -183,6 +187,8 @@ void S9xAlsaSoundDriver::write_samples(int16_t *data, int samples) frames_written += result; } } + + return result; } int S9xAlsaSoundDriver::space_free() diff --git a/common/audio/s9x_sound_driver_alsa.hpp b/common/audio/s9x_sound_driver_alsa.hpp index ed94aae8..d47525ab 100644 --- a/common/audio/s9x_sound_driver_alsa.hpp +++ b/common/audio/s9x_sound_driver_alsa.hpp @@ -19,7 +19,7 @@ class S9xAlsaSoundDriver : public S9xSoundDriver bool open_device(int playback_rate, int buffer_size_ms) override; void start() override; void stop() override; - void write_samples(int16_t *data, int samples) override; + bool write_samples(int16_t *data, int samples) override; int space_free() override; std::pair buffer_level() override; diff --git a/common/audio/s9x_sound_driver_cubeb.cpp b/common/audio/s9x_sound_driver_cubeb.cpp index e0ba789d..549882fe 100644 --- a/common/audio/s9x_sound_driver_cubeb.cpp +++ b/common/audio/s9x_sound_driver_cubeb.cpp @@ -7,11 +7,17 @@ #include "s9x_sound_driver_cubeb.hpp" #include -void S9xCubebSoundDriver::write_samples(int16_t *data, int samples) +bool S9xCubebSoundDriver::write_samples(int16_t *data, int samples) { + bool retval = true; if (samples > buffer.space_empty()) + { + retval = false; samples = buffer.space_empty(); + } buffer.push(data, samples); + + return retval; } S9xCubebSoundDriver::S9xCubebSoundDriver() @@ -74,6 +80,7 @@ long S9xCubebSoundDriver::data_callback(cubeb_stream *stream, void const *input_ auto avail = buffer.avail(); if (avail < nframes * 2) { + printf("Underrun\n"); auto zeroed_samples = nframes * 2 - avail; memset(output_buffer, 0, zeroed_samples); buffer.read((int16_t *)output_buffer + zeroed_samples, nframes * 2 - zeroed_samples); @@ -94,13 +101,19 @@ bool S9xCubebSoundDriver::open_device(int playback_rate, int buffer_size) params.rate = playback_rate; params.prefs = CUBEB_STREAM_PREF_NONE; + uint32_t suggested_latency = playback_rate * buffer_size / 1000; uint32_t min_latency; cubeb_get_min_latency(context, ¶ms, &min_latency); + if (min_latency > suggested_latency) + { + suggested_latency = min_latency; + printf("Using minimum latency: %d\n", min_latency); + } auto retval = cubeb_stream_init(context, &stream, "Snes9x", nullptr, nullptr, nullptr, ¶ms, - min_latency, + suggested_latency, &::data_callback, &state_callback, this); diff --git a/common/audio/s9x_sound_driver_cubeb.hpp b/common/audio/s9x_sound_driver_cubeb.hpp index c61d86ea..5f54001a 100644 --- a/common/audio/s9x_sound_driver_cubeb.hpp +++ b/common/audio/s9x_sound_driver_cubeb.hpp @@ -23,7 +23,7 @@ class S9xCubebSoundDriver : public S9xSoundDriver void start() override; void stop() override; long data_callback(cubeb_stream *stream, void const *input_buffer, void *output_buffer, long nframes); - void write_samples(int16_t *data, int samples) override; + bool write_samples(int16_t *data, int samples) override; int space_free() override; std::pair buffer_level() override; diff --git a/common/audio/s9x_sound_driver_portaudio.cpp b/common/audio/s9x_sound_driver_portaudio.cpp index 8d51b364..7b90563e 100644 --- a/common/audio/s9x_sound_driver_portaudio.cpp +++ b/common/audio/s9x_sound_driver_portaudio.cpp @@ -184,7 +184,7 @@ std::pair S9xPortAudioSoundDriver::buffer_level() return { Pa_GetStreamWriteAvailable(audio_stream), output_buffer_size }; } -void S9xPortAudioSoundDriver::write_samples(int16_t *data, int samples) +bool S9xPortAudioSoundDriver::write_samples(int16_t *data, int samples) { int frames; @@ -199,8 +199,14 @@ void S9xPortAudioSoundDriver::write_samples(int16_t *data, int samples) frames -= output_buffer_size >> 1; } + bool retval = true; if (frames > samples / 2) + { + retval = false; frames = samples / 2; + } Pa_WriteStream(audio_stream, data, frames); + + return retval; } diff --git a/common/audio/s9x_sound_driver_portaudio.hpp b/common/audio/s9x_sound_driver_portaudio.hpp index 1683c7d8..72e390f0 100644 --- a/common/audio/s9x_sound_driver_portaudio.hpp +++ b/common/audio/s9x_sound_driver_portaudio.hpp @@ -22,7 +22,7 @@ class S9xPortAudioSoundDriver : public S9xSoundDriver bool open_device(int playback_rate, int buffer_size) override; void start() override; void stop() override; - void write_samples(int16_t *data, int samples) override; + bool write_samples(int16_t *data, int samples) override; int space_free() override; std::pair buffer_level() override; void samples_available(); diff --git a/common/audio/s9x_sound_driver_sdl.cpp b/common/audio/s9x_sound_driver_sdl.cpp index cfe7b45b..a18ad342 100644 --- a/common/audio/s9x_sound_driver_sdl.cpp +++ b/common/audio/s9x_sound_driver_sdl.cpp @@ -7,21 +7,23 @@ #include "s9x_sound_driver_sdl.hpp" #include "SDL_audio.h" -void S9xSDLSoundDriver::write_samples(int16_t *data, int samples) +bool S9xSDLSoundDriver::write_samples(int16_t *data, int samples) { - mutex.lock(); + bool retval = true; if (samples > buffer.space_empty()) + { + retval = false; samples = buffer.space_empty(); + } buffer.push(data, samples); - mutex.unlock(); + + return retval; } void S9xSDLSoundDriver::mix(unsigned char *output, int bytes) { - mutex.lock(); if (buffer.avail() >= bytes >> 1) buffer.read((int16_t *)output, bytes >> 1); - mutex.unlock(); } S9xSDLSoundDriver::S9xSDLSoundDriver() @@ -89,16 +91,12 @@ bool S9xSDLSoundDriver::open_device(int playback_rate, int buffer_size) int S9xSDLSoundDriver::space_free() { - mutex.lock(); auto space_empty = buffer.space_empty(); - mutex.unlock(); return space_empty; } std::pair S9xSDLSoundDriver::buffer_level() { - mutex.lock(); std::pair level = { buffer.space_empty(), buffer.buffer_size }; - mutex.unlock(); return level; } \ No newline at end of file diff --git a/common/audio/s9x_sound_driver_sdl.hpp b/common/audio/s9x_sound_driver_sdl.hpp index 0a2347f8..816135eb 100644 --- a/common/audio/s9x_sound_driver_sdl.hpp +++ b/common/audio/s9x_sound_driver_sdl.hpp @@ -28,7 +28,7 @@ class S9xSDLSoundDriver : public S9xSoundDriver bool open_device(int playback_rate, int buffer_size) override; void start() override; void stop() override; - void write_samples(int16_t *data, int samples) override; + bool write_samples(int16_t *data, int samples) override; int space_free() override; std::pair buffer_level() override; diff --git a/qt/src/EmuApplication.cpp b/qt/src/EmuApplication.cpp index fb6698cd..b1f72329 100644 --- a/qt/src/EmuApplication.cpp +++ b/qt/src/EmuApplication.cpp @@ -49,19 +49,51 @@ void EmuApplication::restartAudio() void EmuApplication::writeSamples(int16_t *data, int samples) { + static uint64_t total; + static uint64_t ticks; + static std::chrono::steady_clock::time_point then; if (config->speed_sync_method == EmuConfig::eSoundSync && !core->isAbnormalSpeed()) { int iterations = 0; - while (sound_driver->space_free() < samples && iterations < 100) + while (sound_driver->space_free() < samples && iterations < 500) { iterations++; std::this_thread::sleep_for(50us); } } - - sound_driver->write_samples(data, samples); auto buffer_level = sound_driver->buffer_level(); core->updateSoundBufferLevel(buffer_level.first, buffer_level.second); + + if (!sound_driver->write_samples(data, samples)) + { + printf("Overrun\n"); + core->clearSoundBuffer(); + } + + char sym = '*'; + int percent = (buffer_level.second - buffer_level.first) * 100 / buffer_level.second; + printf("\033[0;0H>"); + if (percent < 50) + sym = '_'; + for (int i = 0; i < percent; i+=2) + putchar(sym); + for (int i = percent; i <= 100; i+=2) + putchar('-'); + + total += percent; + ticks++; + + auto now = std::chrono::steady_clock::now(); + if (now - then >= std::chrono::seconds(1)) + { + then = now; + printf(" %lu %%", total / ticks); + total = 0; + ticks = 0; + } + printf("\n"); + + printf(" 10 20 30 40 50 60 70 80 90 100"); } void EmuApplication::startGame() diff --git a/qt/src/Snes9xController.cpp b/qt/src/Snes9xController.cpp index cbd473e0..faedb95c 100644 --- a/qt/src/Snes9xController.cpp +++ b/qt/src/Snes9xController.cpp @@ -534,6 +534,11 @@ void Snes9xController::SamplesAvailable() } } +void Snes9xController::clearSoundBuffer() +{ + S9xClearSamples(); +} + void S9xMessage(int message_class, int type, const char *message) { S9xSetInfoString(message); diff --git a/qt/src/Snes9xController.hpp b/qt/src/Snes9xController.hpp index 01cd2ee2..b3e97a9e 100644 --- a/qt/src/Snes9xController.hpp +++ b/qt/src/Snes9xController.hpp @@ -35,6 +35,7 @@ class Snes9xController void softReset(); void setPaused(bool paused); void setMessage(std::string message); + void clearSoundBuffer(); std::string getStateFolder(); std::string config_folder; std::string sram_folder;