mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-16 02:49:48 +12:00
Adding audio interface part 1
This commit is contained in:
parent
be071ffb78
commit
486e2ea5cb
7 changed files with 91 additions and 51 deletions
|
@ -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/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/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/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(
|
cmrc_add_resource_library(
|
||||||
|
|
31
include/audio/audio_device.hpp
Normal file
31
include/audio/audio_device.hpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "helpers.hpp"
|
||||||
|
#include "ring_buffer.hpp"
|
||||||
|
|
||||||
|
class AudioDeviceInterface {
|
||||||
|
protected:
|
||||||
|
using Samples = Common::RingBuffer<s16, 0x2000 * 2>;
|
||||||
|
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<s16, 2> 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;
|
||||||
|
};
|
33
include/audio/libretro_audio_device.hpp
Normal file
33
include/audio/libretro_audio_device.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
#include <atomic>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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; }
|
||||||
|
};
|
|
@ -3,40 +3,31 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "audio/audio_device.hpp"
|
||||||
#include "helpers.hpp"
|
|
||||||
#include "miniaudio.h"
|
#include "miniaudio.h"
|
||||||
#include "ring_buffer.hpp"
|
|
||||||
|
|
||||||
class MiniAudioDevice {
|
class MiniAudioDevice : public AudioDeviceInterface {
|
||||||
public:
|
|
||||||
using Samples = Common::RingBuffer<ma_int16, 0x2000 * 2>;
|
|
||||||
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
|
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
|
||||||
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
|
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
|
||||||
|
|
||||||
|
bool initialized = false;
|
||||||
|
|
||||||
ma_device device;
|
ma_device device;
|
||||||
ma_context context;
|
ma_context context;
|
||||||
ma_device_config deviceConfig;
|
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.
|
// Store the last stereo sample we output. We play this when underruning to avoid pops.
|
||||||
std::array<s16, 2> lastStereoSample;
|
|
||||||
std::vector<std::string> audioDevices;
|
std::vector<std::string> audioDevices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MiniAudioDevice(const AudioDeviceConfig& audioSettings);
|
MiniAudioDevice(const AudioDeviceConfig& audioSettings);
|
||||||
|
|
||||||
// If safe is on, we create a null audio device
|
// If safe is on, we create a null audio device
|
||||||
void init(Samples& samples, bool safe = false);
|
void init(Samples& samples, bool safe = false) override;
|
||||||
void close();
|
void close() override;
|
||||||
|
|
||||||
void start();
|
void start() override;
|
||||||
void stop();
|
void stop() override;
|
||||||
|
|
||||||
bool isInitialized() const { return initialized; }
|
bool isInitialized() const { return initialized; }
|
||||||
};
|
};
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "PICA/gpu.hpp"
|
#include "PICA/gpu.hpp"
|
||||||
#include "audio/dsp_core.hpp"
|
#include "audio/dsp_core.hpp"
|
||||||
|
#include "audio/libretro_audio_device.hpp"
|
||||||
#include "audio/miniaudio_device.hpp"
|
#include "audio/miniaudio_device.hpp"
|
||||||
#include "cheats.hpp"
|
#include "cheats.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
@ -48,7 +49,11 @@ class Emulator {
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
|
||||||
Crypto::AESEngine aesEngine;
|
Crypto::AESEngine aesEngine;
|
||||||
|
#ifndef __LIBRETRO__
|
||||||
MiniAudioDevice audioDevice;
|
MiniAudioDevice audioDevice;
|
||||||
|
#else
|
||||||
|
LibretroAudioDevice audioDevice;
|
||||||
|
#endif
|
||||||
Cheats cheats;
|
Cheats cheats;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -126,6 +131,7 @@ class Emulator {
|
||||||
LuaManager& getLua() { return lua; }
|
LuaManager& getLua() { return lua; }
|
||||||
Scheduler& getScheduler() { return scheduler; }
|
Scheduler& getScheduler() { return scheduler; }
|
||||||
Memory& getMemory() { return memory; }
|
Memory& getMemory() { return memory; }
|
||||||
|
AudioDeviceInterface& getAudioDevice() { return audioDevice; }
|
||||||
|
|
||||||
RendererType getRendererType() const { return config.rendererType; }
|
RendererType getRendererType() const { return config.rendererType; }
|
||||||
Renderer* getRenderer() { return gpu.getRenderer(); }
|
Renderer* getRenderer() { return gpu.getRenderer(); }
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings)
|
MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings) : AudioDeviceInterface(nullptr, audioSettings), initialized(false) {
|
||||||
: initialized(false), running(false), samples(nullptr), audioSettings(audioSettings) {}
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __LIBRETRO__
|
|
||||||
void MiniAudioDevice::init(Samples& samples, bool safe) {
|
void MiniAudioDevice::init(Samples& samples, bool safe) {
|
||||||
this->samples = &samples;
|
this->samples = &samples;
|
||||||
running = false;
|
running = false;
|
||||||
|
@ -213,5 +213,4 @@ void MiniAudioDevice::close() {
|
||||||
ma_device_uninit(&device);
|
ma_device_uninit(&device);
|
||||||
ma_context_uninit(&context);
|
ma_context_uninit(&context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
|
@ -22,7 +22,6 @@ static bool usingGLES = false;
|
||||||
|
|
||||||
std::unique_ptr<Emulator> emulator;
|
std::unique_ptr<Emulator> emulator;
|
||||||
RendererGL* renderer;
|
RendererGL* renderer;
|
||||||
MiniAudioDevice* audioDevice;
|
|
||||||
|
|
||||||
std::filesystem::path Emulator::getConfigPath() {
|
std::filesystem::path Emulator::getConfigPath() {
|
||||||
return std::filesystem::path(savePath / "config.toml");
|
return std::filesystem::path(savePath / "config.toml");
|
||||||
|
@ -32,27 +31,6 @@ std::filesystem::path Emulator::getAppDataRoot() {
|
||||||
return std::filesystem::path(savePath / "Emulator Files");
|
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) {
|
static void* getGLProcAddress(const char* name) {
|
||||||
return (void*)hwRender.get_proc_address(name);
|
return (void*)hwRender.get_proc_address(name);
|
||||||
}
|
}
|
||||||
|
@ -411,29 +389,30 @@ void retro_run() {
|
||||||
emulator->runFrame();
|
emulator->runFrame();
|
||||||
|
|
||||||
videoCallback(RETRO_HW_FRAME_BUFFER_VALID, emulator->width, emulator->height, 0);
|
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 frameCount = 547;
|
||||||
static constexpr int channelCount = 2;
|
static constexpr int channelCount = 2;
|
||||||
static int16_t audioBuffer[frameCount * channelCount];
|
static int16_t audioBuffer[frameCount * channelCount];
|
||||||
|
|
||||||
usize samplesWritten = 0;
|
usize samplesWritten = 0;
|
||||||
samplesWritten += audioDevice->samples->pop(audioBuffer, frameCount * channelCount);
|
samplesWritten += audioDevice.getSamples()->pop(audioBuffer, frameCount * channelCount);
|
||||||
|
|
||||||
// Get the last sample for underrun handling
|
// Get the last sample for underrun handling
|
||||||
if (samplesWritten != 0) {
|
if (samplesWritten != 0) {
|
||||||
std::memcpy(
|
std::memcpy(
|
||||||
&audioDevice->lastStereoSample[0],
|
&audioDevice.lastStereoSample[0],
|
||||||
&audioBuffer[(samplesWritten - 1) * 2],
|
&audioBuffer[(samplesWritten - 1) * 2],
|
||||||
sizeof(audioDevice->lastStereoSample)
|
sizeof(audioDevice.lastStereoSample)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If underruning, copy the last output sample
|
// If underruning, copy the last output sample
|
||||||
{
|
{
|
||||||
s16* pointer = &audioBuffer[samplesWritten * 2];
|
s16* pointer = &audioBuffer[samplesWritten * 2];
|
||||||
s16 l = audioDevice->lastStereoSample[0];
|
s16 l = audioDevice.lastStereoSample[0];
|
||||||
s16 r = audioDevice->lastStereoSample[1];
|
s16 r = audioDevice.lastStereoSample[1];
|
||||||
|
|
||||||
for (usize i = samplesWritten; i < frameCount; i++) {
|
for (usize i = samplesWritten; i < frameCount; i++) {
|
||||||
*pointer++ = l;
|
*pointer++ = l;
|
||||||
|
|
Loading…
Add table
Reference in a new issue