From be071ffb787555f80bf4002a9c3985d839e06d25 Mon Sep 17 00:00:00 2001 From: Jonian Guveli Date: Sat, 1 Feb 2025 23:19:45 +0200 Subject: [PATCH] Libretro: Add audio support --- include/audio/miniaudio_device.hpp | 1 + src/core/audio/miniaudio_device.cpp | 2 ++ src/libretro_core.cpp | 54 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/include/audio/miniaudio_device.hpp b/include/audio/miniaudio_device.hpp index 0363aa44..9aae6eed 100644 --- a/include/audio/miniaudio_device.hpp +++ b/include/audio/miniaudio_device.hpp @@ -9,6 +9,7 @@ #include "ring_buffer.hpp" class MiniAudioDevice { + public: using Samples = Common::RingBuffer; static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate static constexpr ma_uint32 channelCount = 2; // Audio output is stereo diff --git a/src/core/audio/miniaudio_device.cpp b/src/core/audio/miniaudio_device.cpp index 550fb039..e2cc6f37 100644 --- a/src/core/audio/miniaudio_device.cpp +++ b/src/core/audio/miniaudio_device.cpp @@ -10,6 +10,7 @@ MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) : initialized(false), running(false), samples(nullptr), audioSettings(audioSettings) {} +#ifndef __LIBRETRO__ void MiniAudioDevice::init(Samples& samples, bool safe) { this->samples = &samples; running = false; @@ -213,3 +214,4 @@ void MiniAudioDevice::close() { ma_context_uninit(&context); } } +#endif diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 727da8d2..45791c2d 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -22,6 +22,7 @@ static bool usingGLES = false; std::unique_ptr emulator; RendererGL* renderer; +MiniAudioDevice* audioDevice; std::filesystem::path Emulator::getConfigPath() { return std::filesystem::path(savePath / "config.toml"); @@ -31,6 +32,27 @@ std::filesystem::path Emulator::getAppDataRoot() { return std::filesystem::path(savePath / "Emulator Files"); } +void MiniAudioDevice::init(Samples& samples, bool safe) { + this->samples = &samples; + initialized = true; + running = false; + + audioDevice = this; +} + +void MiniAudioDevice::start() { + running = true; +} + +void MiniAudioDevice::stop() { + running = false; +} + +void MiniAudioDevice::close() { + running = false; + initialized = false; +} + static void* getGLProcAddress(const char* name) { return (void*)hwRender.get_proc_address(name); } @@ -389,6 +411,38 @@ void retro_run() { emulator->runFrame(); videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0); + + if (audioDevice->running) { + static constexpr int frameCount = 547; + static constexpr int channelCount = 2; + static int16_t audioBuffer[frameCount * channelCount]; + + usize samplesWritten = 0; + samplesWritten += audioDevice->samples->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))); + } } void retro_set_controller_port_device(uint port, uint device) {}