diff --git a/include/audio/audio_device.hpp b/include/audio/audio_device.hpp index 6dc1ff8f..4534f9e3 100644 --- a/include/audio/audio_device.hpp +++ b/include/audio/audio_device.hpp @@ -8,17 +8,17 @@ class AudioDeviceInterface { protected: using Samples = Common::RingBuffer; + using RenderBatchCallback = usize (*)(const s16*, usize); + Samples* samples = nullptr; const AudioDeviceConfig& audioSettings; + // Store the last stereo sample we output. We play this when underruning to avoid pops. + std::array lastStereoSample{}; public: AudioDeviceInterface(Samples* samples, const AudioDeviceConfig& audioSettings) : samples(samples), audioSettings(audioSettings) {} - // Store the last stereo sample we output. We play this when underruning to avoid pops. - // TODO: Make this protected again before merging!!! - std::array lastStereoSample{}; - bool running = false; Samples* getSamples() { return samples; } @@ -28,4 +28,7 @@ class AudioDeviceInterface { virtual void start() = 0; virtual void stop() = 0; + + // Only used for audio devices that render multiple audio frames in one go, eg the libretro audio device. + virtual void renderBatch(RenderBatchCallback callback) {} }; \ No newline at end of file diff --git a/include/audio/libretro_audio_device.hpp b/include/audio/libretro_audio_device.hpp index a6e29b95..86727cbe 100644 --- a/include/audio/libretro_audio_device.hpp +++ b/include/audio/libretro_audio_device.hpp @@ -1,7 +1,5 @@ #pragma once -#include -#include -#include +#include #include "audio/audio_device.hpp" @@ -28,6 +26,35 @@ class LibretroAudioDevice : public AudioDeviceInterface { void start() override { running = true; } void stop() override { running = false; }; + void renderBatch(RenderBatchCallback callback) override { + if (running) { + static constexpr int frameCount = 547; + static constexpr int channelCount = 2; + static s16 audioBuffer[frameCount * channelCount]; + + usize samplesWritten = 0; + samplesWritten += samples->pop(audioBuffer, frameCount * channelCount); + + // Get the last sample for underrun handling + if (samplesWritten != 0) { + std::memcpy(&lastStereoSample[0], &audioBuffer[(samplesWritten - 1) * 2], sizeof(lastStereoSample)); + } + + // If underruning, copy the last output sample + { + s16* pointer = &audioBuffer[samplesWritten * 2]; + s16 l = lastStereoSample[0]; + s16 r = lastStereoSample[1]; + + for (usize i = samplesWritten; i < frameCount; i++) { + *pointer++ = l; + *pointer++ = r; + } + } + + callback(audioBuffer, sizeof(audioBuffer) / (2 * sizeof(s16))); + } + } + bool isInitialized() const { return initialized; } - bool isRunning() const { return running; } }; \ No newline at end of file diff --git a/include/emulator.hpp b/include/emulator.hpp index 81d7ed84..76ea289d 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -60,7 +60,7 @@ class Emulator { static constexpr u32 width = 400; static constexpr u32 height = 240 * 2; // * 2 because 2 screens ROMType romType = ROMType::None; - bool running = false; // Is the emulator running a game? + bool running = false; // Is the emulator running a game? private: #ifdef PANDA3DS_ENABLE_HTTP_SERVER diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 52c9e47c..a9783320 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -389,39 +389,8 @@ void retro_run() { emulator->runFrame(); videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0); - auto& audioDevice = emulator->getAudioDevice(); - - if (audioDevice.running) { - static constexpr int frameCount = 547; - static constexpr int channelCount = 2; - static int16_t audioBuffer[frameCount * channelCount]; - - usize samplesWritten = 0; - samplesWritten += audioDevice.getSamples()->pop(audioBuffer, frameCount * channelCount); - - // Get the last sample for underrun handling - if (samplesWritten != 0) { - std::memcpy( - &audioDevice.lastStereoSample[0], - &audioBuffer[(samplesWritten - 1) * 2], - sizeof(audioDevice.lastStereoSample) - ); - } - - // If underruning, copy the last output sample - { - s16* pointer = &audioBuffer[samplesWritten * 2]; - s16 l = audioDevice.lastStereoSample[0]; - s16 r = audioDevice.lastStereoSample[1]; - - for (usize i = samplesWritten; i < frameCount; i++) { - *pointer++ = l; - *pointer++ = r; - } - } - - audioBatchCallback(audioBuffer, sizeof(audioBuffer) / (2 * sizeof(int16_t))); - } + // Call audio batch callback + emulator->getAudioDevice().renderBatch(audioBatchCallback); } void retro_set_controller_port_device(uint port, uint device) {}