mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-04 04:47:22 +12:00
Get audio output working with LLE DSP (#419)
* Implement audio output * Semi-proper audio output * Add audio enable and vsync settings * Add audio enable and vsync settings * Optimize audio output a bit * Make max ring buffer timeout smaller * Make max ring buffer timeout smaller * Revert to spinlocking for audio sync * Sleep emulator thread if too many samples queued * Fix Teakra submodule breaking * Don't start audio device too soon * Fix IWYU errors * Fix compilation errors on GCC/Clang * Ignore std::hardware_destructive_interference_size on Android NDK * Fix more IWYU errors
This commit is contained in:
parent
8bca988b55
commit
d459cb1d6c
16 changed files with 396 additions and 15 deletions
|
@ -9,6 +9,7 @@
|
|||
#include "helpers.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "ring_buffer.hpp"
|
||||
|
||||
// The DSP core must have access to the DSP service to be able to trigger interrupts properly
|
||||
class DSPService;
|
||||
|
@ -23,16 +24,22 @@ namespace Audio {
|
|||
static constexpr u64 lleSlice = 16384;
|
||||
|
||||
class DSPCore {
|
||||
using Samples = Common::RingBuffer<s16, 1024>;
|
||||
|
||||
protected:
|
||||
Memory& mem;
|
||||
Scheduler& scheduler;
|
||||
DSPService& dspService;
|
||||
|
||||
Samples sampleBuffer;
|
||||
bool audioEnabled = false;
|
||||
|
||||
MAKE_LOG_FUNCTION(log, dspLogger)
|
||||
|
||||
public:
|
||||
enum class Type { Null, Teakra };
|
||||
DSPCore(Memory& mem, Scheduler& scheduler, DSPService& dspService) : mem(mem), scheduler(scheduler), dspService(dspService) {}
|
||||
DSPCore(Memory& mem, Scheduler& scheduler, DSPService& dspService)
|
||||
: mem(mem), scheduler(scheduler), dspService(dspService) {}
|
||||
virtual ~DSPCore() {}
|
||||
|
||||
virtual void reset() = 0;
|
||||
|
@ -50,6 +57,9 @@ namespace Audio {
|
|||
|
||||
static Audio::DSPCore::Type typeFromString(std::string inString);
|
||||
static const char* typeToString(Audio::DSPCore::Type type);
|
||||
|
||||
Samples& getSamples() { return sampleBuffer; }
|
||||
virtual void setAudioEnabled(bool enable) { audioEnabled = enable; }
|
||||
};
|
||||
|
||||
std::unique_ptr<DSPCore> makeDSPCore(DSPCore::Type type, Memory& mem, Scheduler& scheduler, DSPService& dspService);
|
||||
|
|
31
include/audio/miniaudio_device.hpp
Normal file
31
include/audio/miniaudio_device.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "miniaudio.h"
|
||||
#include "ring_buffer.hpp"
|
||||
|
||||
class MiniAudioDevice {
|
||||
using Samples = Common::RingBuffer<ma_int16, 1024>;
|
||||
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
|
||||
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
|
||||
|
||||
ma_context context;
|
||||
ma_device_config deviceConfig;
|
||||
ma_device device;
|
||||
ma_resampler resampler;
|
||||
Samples* samples = nullptr;
|
||||
|
||||
bool initialized = false;
|
||||
bool running = false;
|
||||
|
||||
std::vector<std::string> audioDevices;
|
||||
public:
|
||||
MiniAudioDevice();
|
||||
// If safe is on, we create a null audio device
|
||||
void init(Samples& samples, bool safe = false);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
};
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
|
||||
#include "audio/dsp_core.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "swap.hpp"
|
||||
|
@ -10,6 +12,11 @@ namespace Audio {
|
|||
u32 pipeBaseAddr;
|
||||
bool running; // Is the DSP running?
|
||||
bool loaded; // Have we finished loading a binary with LoadComponent?
|
||||
bool signalledData;
|
||||
bool signalledSemaphore;
|
||||
|
||||
uint audioFrameIndex = 0; // Index in our audio frame
|
||||
std::array<s16, 160 * 2> audioFrame;
|
||||
|
||||
// Get a pointer to a data memory address
|
||||
u8* getDataPointer(u32 address) { return getDspMemory() + Memory::DSP_DATA_MEMORY_OFFSET + address; }
|
||||
|
@ -62,10 +69,6 @@ namespace Audio {
|
|||
std::memcpy(statusAddress + 6, &status.writePointer, sizeof(u16));
|
||||
}
|
||||
}
|
||||
|
||||
bool signalledData;
|
||||
bool signalledSemaphore;
|
||||
|
||||
// Run 1 slice of DSP instructions
|
||||
void runSlice() {
|
||||
if (running) {
|
||||
|
@ -85,6 +88,7 @@ namespace Audio {
|
|||
scheduler.addEvent(Scheduler::EventType::RunDSP, scheduler.currentTimestamp + Audio::lleSlice * 2);
|
||||
}
|
||||
|
||||
void setAudioEnabled(bool enable) override;
|
||||
u8* getDspMemory() override { return teakra.GetDspMemory().data(); }
|
||||
|
||||
u16 recvData(u32 regId) override { return teakra.RecvData(regId); }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue