Implement audio output

This commit is contained in:
wheremyfoodat 2024-02-22 02:15:49 +02:00
parent 093364f615
commit 21ced6fae7
11 changed files with 299 additions and 9 deletions

View file

@ -0,0 +1,119 @@
#include "audio/miniaudio_device.hpp"
#include "helpers.hpp"
MiniAudioDevice::MiniAudioDevice() : initialized(false), running(false), samples(nullptr) {}
void MiniAudioDevice::init(Samples& samples, bool safe) {
this->samples = &samples;
// Probe for device and available backends and initialize audio
ma_backend backends[ma_backend_null + 1];
unsigned count = 0;
if (safe) {
backends[0] = ma_backend_null;
count = 1;
} else {
bool found = false;
for (uint i = 0; i <= ma_backend_null; i++) {
ma_backend backend = ma_backend(i);
if (!ma_is_backend_enabled(backend)) {
continue;
}
backends[count++] = backend;
printf("Found audio backend: %s\n", ma_get_backend_name(backend));
// TODO: Make backend selectable here
found = true;
//count = 1;
//backends[0] = backend;
}
if (!found) {
initialized = false;
Helpers::warn("No valid audio backend found\n");
return;
}
}
if (ma_context_init(backends, count, nullptr, &context) != MA_SUCCESS) {
initialized = false;
Helpers::warn("Unable to initialize audio context");
return;
}
audioDevices.clear();
struct UserContext {
MiniAudioDevice* miniAudio;
ma_device_config& config;
bool found = false;
};
UserContext userContext = {.miniAudio = this, .config = deviceConfig};
ma_context_enumerate_devices(
&context,
[](ma_context* pContext, ma_device_type deviceType, const ma_device_info* pInfo, void* pUserData) -> ma_bool32 {
if (deviceType != ma_device_type_playback) {
return true;
}
UserContext* userContext = reinterpret_cast<UserContext*>(pUserData);
userContext->miniAudio->audioDevices.push_back(pInfo->name);
// TODO: Check if this is the device we want here
userContext->config.playback.pDeviceID = &pInfo->id;
userContext->found = true;
return true;
},
&userContext
);
if (!userContext.found) {
Helpers::warn("MiniAudio: Device not found");
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
// The 3DS outputs s16 stereo audio @ 32768 Hz
deviceConfig.playback.format = ma_format_s16;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 32768;
//deviceConfig.periodSizeInFrames = 64;
//deviceConfig.periods = 2;
deviceConfig.pUserData = this;
deviceConfig.aaudio.usage = ma_aaudio_usage_game;
deviceConfig.wasapi.noAutoConvertSRC = true;
deviceConfig.dataCallback = [](ma_device* device, void* out, const void* input, ma_uint32 frameCount) {
auto self = reinterpret_cast<MiniAudioDevice*>(device->pUserData);
s16* output = reinterpret_cast<ma_int16*>(out);
self->samples->pop(output, frameCount);
};
if (ma_device_init(&context, &deviceConfig, &device) != MA_SUCCESS) {
Helpers::warn("Unable to initialize audio device");
initialized = false;
return;
}
initialized = true;
start();
}
void MiniAudioDevice::start() {
if (!initialized) {
Helpers::warn("MiniAudio device not initialize, won't start");
return;
}
if (ma_device_start(&device) == MA_SUCCESS) {
running = true;
} else {
running = false;
Helpers::warn("Failed to start audio device");
}
}

View file

@ -6,6 +6,10 @@
#include "services/dsp.hpp"
using namespace Audio;
static constexpr u32 sampleRate = 32768;
static constexpr u32 duration = 30;
static s16 samples[sampleRate * duration * 2];
static uint sampleIndex = 0;
struct Dsp1 {
// All sizes are in bytes unless otherwise specified
@ -51,10 +55,7 @@ TeakraDSP::TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService)
ahbm.write32 = [&](u32 addr, u32 value) { *(u32*)&mem.getFCRAM()[addr - PhysicalAddrs::FCRAM] = value; };
teakra.SetAHBMCallback(ahbm);
teakra.SetAudioCallback([=](std::array<s16, 2> sample) {
//printf("%d %d\n", sample[0], sample[1]);
// NOP for now
});
teakra.SetAudioCallback([=](std::array<s16, 2> sample) { sampleBuffer.push(sample.data(), 2); });
// Set up event handlers. These handlers forward a hardware interrupt to the DSP service, which is responsible
// For triggering the appropriate DSP kernel events

View file

@ -25,10 +25,11 @@ Emulator::Emulator()
#endif
{
DSPService& dspService = kernel.getServiceManager().getDSP();
dsp = Audio::makeDSPCore(config.dspType, memory, scheduler, dspService);
dspService.setDSPCore(dsp.get());
audioDevice.init(dsp->getSamples());
#ifdef PANDA3DS_ENABLE_DISCORD_RPC
if (config.discordRpcEnabled) {
discordRpc.init();

7
src/miniaudio.cpp Normal file
View file

@ -0,0 +1,7 @@
// We do not need the ability to be able to encode or decode audio files for the time being
// So we disable said functionality to make the executable smaller
#define MA_NO_DECODING
#define MA_NO_ENCODING
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"