diff --git a/CMakeLists.txt b/CMakeLists.txt index be70036c..5d9c691d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,7 +402,8 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/termcolor.hpp include/align.hpp include/audio/aac_decoder.hpp include/PICA/pica_simd.hpp include/services/fonts.hpp include/audio/audio_interpolation.hpp include/audio/hle_mixer.hpp include/audio/dsp_simd.hpp include/services/dsp_firmware_db.hpp include/frontend_settings.hpp include/fs/archive_twl_photo.hpp - include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/services/ns.hpp + include/fs/archive_twl_sound.hpp include/fs/archive_card_spi.hpp include/services/ns.hpp include/audio/audio_device.hpp + include/audio/libretro_audio_device.hpp ) cmrc_add_resource_library( diff --git a/include/audio/audio_device.hpp b/include/audio/audio_device.hpp new file mode 100644 index 00000000..6dc1ff8f --- /dev/null +++ b/include/audio/audio_device.hpp @@ -0,0 +1,31 @@ +#pragma once +#include + +#include "config.hpp" +#include "helpers.hpp" +#include "ring_buffer.hpp" + +class AudioDeviceInterface { + protected: + using Samples = Common::RingBuffer; + Samples* samples = nullptr; + + const AudioDeviceConfig& audioSettings; + + 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; } + + // If safe is on, we create a null audio device + virtual void init(Samples& samples, bool safe = false) = 0; + virtual void close() = 0; + + virtual void start() = 0; + virtual void stop() = 0; +}; \ No newline at end of file diff --git a/include/audio/libretro_audio_device.hpp b/include/audio/libretro_audio_device.hpp new file mode 100644 index 00000000..a6e29b95 --- /dev/null +++ b/include/audio/libretro_audio_device.hpp @@ -0,0 +1,33 @@ +#pragma once +#include +#include +#include + +#include "audio/audio_device.hpp" + +class LibretroAudioDevice : public AudioDeviceInterface { + bool initialized = false; + + public: + LibretroAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) { + running = false; + } + + void init(Samples& samples, bool safe = false) override { + this->samples = &samples; + + initialized = true; + running = false; + } + + void close() override { + initialized = false; + running = false; + }; + + void start() override { running = true; } + void stop() override { running = false; }; + + bool isInitialized() const { return initialized; } + bool isRunning() const { return running; } +}; \ No newline at end of file diff --git a/include/audio/miniaudio_device.hpp b/include/audio/miniaudio_device.hpp index 9aae6eed..99cdd026 100644 --- a/include/audio/miniaudio_device.hpp +++ b/include/audio/miniaudio_device.hpp @@ -3,40 +3,31 @@ #include #include -#include "config.hpp" -#include "helpers.hpp" +#include "audio/audio_device.hpp" #include "miniaudio.h" -#include "ring_buffer.hpp" -class MiniAudioDevice { - public: - using Samples = Common::RingBuffer; +class MiniAudioDevice : public AudioDeviceInterface { static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate static constexpr ma_uint32 channelCount = 2; // Audio output is stereo + bool initialized = false; + ma_device device; ma_context context; ma_device_config deviceConfig; - Samples* samples = nullptr; - - const AudioDeviceConfig& audioSettings; - - bool initialized = false; - bool running = false; // Store the last stereo sample we output. We play this when underruning to avoid pops. - std::array lastStereoSample; std::vector audioDevices; public: MiniAudioDevice(const AudioDeviceConfig& audioSettings); // If safe is on, we create a null audio device - void init(Samples& samples, bool safe = false); - void close(); + void init(Samples& samples, bool safe = false) override; + void close() override; - void start(); - void stop(); + void start() override; + void stop() override; bool isInitialized() const { return initialized; } }; \ No newline at end of file diff --git a/include/emulator.hpp b/include/emulator.hpp index a222a021..81d7ed84 100644 --- a/include/emulator.hpp +++ b/include/emulator.hpp @@ -8,6 +8,7 @@ #include "PICA/gpu.hpp" #include "audio/dsp_core.hpp" +#include "audio/libretro_audio_device.hpp" #include "audio/miniaudio_device.hpp" #include "cheats.hpp" #include "config.hpp" @@ -48,7 +49,11 @@ class Emulator { Scheduler scheduler; Crypto::AESEngine aesEngine; +#ifndef __LIBRETRO__ MiniAudioDevice audioDevice; +#else + LibretroAudioDevice audioDevice; +#endif Cheats cheats; public: @@ -126,6 +131,7 @@ class Emulator { LuaManager& getLua() { return lua; } Scheduler& getScheduler() { return scheduler; } Memory& getMemory() { return memory; } + AudioDeviceInterface& getAudioDevice() { return audioDevice; } RendererType getRendererType() const { return config.rendererType; } Renderer* getRenderer() { return gpu.getRenderer(); } diff --git a/src/core/audio/miniaudio_device.cpp b/src/core/audio/miniaudio_device.cpp index e2cc6f37..8e2a1e71 100644 --- a/src/core/audio/miniaudio_device.cpp +++ b/src/core/audio/miniaudio_device.cpp @@ -7,10 +7,10 @@ #include "helpers.hpp" -MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) - : initialized(false), running(false), samples(nullptr), audioSettings(audioSettings) {} +MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) { + running = false; +} -#ifndef __LIBRETRO__ void MiniAudioDevice::init(Samples& samples, bool safe) { this->samples = &samples; running = false; @@ -213,5 +213,4 @@ void MiniAudioDevice::close() { ma_device_uninit(&device); ma_context_uninit(&context); } -} -#endif +} \ No newline at end of file diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 45791c2d..52c9e47c 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -22,7 +22,6 @@ static bool usingGLES = false; std::unique_ptr emulator; RendererGL* renderer; -MiniAudioDevice* audioDevice; std::filesystem::path Emulator::getConfigPath() { return std::filesystem::path(savePath / "config.toml"); @@ -32,27 +31,6 @@ 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); } @@ -411,29 +389,30 @@ void retro_run() { emulator->runFrame(); videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0); + auto& audioDevice = emulator->getAudioDevice(); - if (audioDevice->running) { + 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); + samplesWritten += audioDevice.getSamples()->pop(audioBuffer, frameCount * channelCount); // Get the last sample for underrun handling if (samplesWritten != 0) { std::memcpy( - &audioDevice->lastStereoSample[0], + &audioDevice.lastStereoSample[0], &audioBuffer[(samplesWritten - 1) * 2], - sizeof(audioDevice->lastStereoSample) + 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]; + s16 l = audioDevice.lastStereoSample[0]; + s16 r = audioDevice.lastStereoSample[1]; for (usize i = samplesWritten; i < frameCount; i++) { *pointer++ = l;