Add new audio interfaces

This commit is contained in:
Tony Wasserka 2024-09-29 19:29:28 +02:00
parent 8dadaf304c
commit d66316c917
13 changed files with 78 additions and 18 deletions

View file

@ -0,0 +1,9 @@
#pragma once
#include <ui/audio_frontend.hpp>
class SDLAudioFrontend : public AudioFrontend {
public:
void OutputSamples(std::array<int16_t, 2> samples) override {}
SDLAudioFrontend() = default;
};

View file

@ -1,3 +1,5 @@
#include "audio_frontend_sdl.hpp"
#include <ui/key_database.hpp> #include <ui/key_database.hpp>
#include "platform/file_formats/cia.hpp" #include "platform/file_formats/cia.hpp"
@ -361,6 +363,7 @@ if (bootstrap_nand) // Experimental system bootstrapper
//exit(1); //exit(1);
g_samples.reserve(32768); g_samples.reserve(32768);
auto audio_frontend = std::make_unique<SDLAudioFrontend>();
#ifndef DISABLE_AUDIO #ifndef DISABLE_AUDIO
static std::ofstream ofs("samples.raw", std::ios_base::binary); static std::ofstream ofs("samples.raw", std::ios_base::binary);
static std::ofstream ofs2("samples2.raw", std::ios_base::binary); static std::ofstream ofs2("samples2.raw", std::ios_base::binary);
@ -531,7 +534,7 @@ if (bootstrap_nand) // Experimental system bootstrapper
} }
auto gamecard = LoadGameCard(*frontend_logger, settings); auto gamecard = LoadGameCard(*frontend_logger, settings);
session = std::make_unique<EmuSession>(*log_manager, settings, *display, *display, keydb, std::move(gamecard)); session = std::make_unique<EmuSession>(*log_manager, settings, *audio_frontend, *display, *display, keydb, std::move(gamecard));
emuthread = std::thread { emuthread = std::thread {
[&emuthread_exception, &session]() { [&emuthread_exception, &session]() {

View file

@ -10,6 +10,8 @@
#include "framework/logging.hpp" #include "framework/logging.hpp"
#include "framework/meta_tools.hpp" #include "framework/meta_tools.hpp"
#include <ui/audio_frontend.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <boost/endian/arithmetic.hpp> #include <boost/endian/arithmetic.hpp>
@ -842,6 +844,8 @@ static bool just_reset = false;
struct DSPMMIO : MemoryAccessHandler { struct DSPMMIO : MemoryAccessHandler {
std::shared_ptr<spdlog::logger> logger; std::shared_ptr<spdlog::logger> logger;
AudioFrontend* frontend = nullptr;
DSPConfig config {}; DSPConfig config {};
DSPStatus status { DSPStatus{}.write_fifo_empty()(true) }; DSPStatus status { DSPStatus{}.write_fifo_empty()(true) };
@ -1032,7 +1036,7 @@ struct DSPMMIO : MemoryAccessHandler {
static std::ofstream ofs2("samples2.raw", std::ios_base::binary); static std::ofstream ofs2("samples2.raw", std::ios_base::binary);
static std::vector<uint16_t> data; static std::vector<uint16_t> data;
static std::vector<uint16_t> data2; static std::vector<uint16_t> data2;
static auto audio_callback = [](std::array<int16_t, 2> samples) { auto audio_callback = [this](std::array<int16_t, 2> samples) {
data.push_back(samples[0]); data.push_back(samples[0]);
data2.push_back(samples[1]); data2.push_back(samples[1]);
if (data.size() == 0x10000) { if (data.size() == 0x10000) {
@ -1044,10 +1048,9 @@ struct DSPMMIO : MemoryAccessHandler {
data2.clear(); data2.clear();
} }
TeakraAudioCallback(samples); frontend->OutputSamples(samples);
}; };
g_teakra->SetAudioCallback(audio_callback); g_teakra->SetAudioCallback(audio_callback);
// g_teakra->SetAudioCallback(TeakraAudioCallback);
// NOTE: These don't seem to be needed (only for unaligned memory accesses?) // NOTE: These don't seem to be needed (only for unaligned memory accesses?)
static Teakra::AHBMCallback ahbm; static Teakra::AHBMCallback ahbm;
@ -1265,6 +1268,10 @@ PhysicalMemory::PhysicalMemory(LogManager& log_manager)
g_mem = this; g_mem = this;
} }
void PhysicalMemory::InjectDependency(AudioFrontend& frontend) {
std::get<IO_DSP1>(memory).handler->frontend = &frontend;
}
void PhysicalMemory::InjectDependency(PicaContext& context) { void PhysicalMemory::InjectDependency(PicaContext& context) {
std::get<IO_GPU>(memory).handler->context = context.context.get(); std::get<IO_GPU>(memory).handler->context = context.context.get();
} }

View file

@ -15,6 +15,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
struct AudioFrontend;
class LogManager; class LogManager;
class PicaContext; class PicaContext;
@ -343,7 +345,8 @@ struct PhysicalMemory {
*/ */
PhysicalMemory(LogManager& log_manager); PhysicalMemory(LogManager& log_manager);
void InjectDependency(PicaContext& pica); void InjectDependency(AudioFrontend&);
void InjectDependency(PicaContext&);
void InjectDependency(InputSource&); void InjectDependency(InputSource&);
}; };

View file

@ -1942,8 +1942,11 @@ const uint32_t num_firm_modules = 5;
// See MakeNewProcessId for details. // See MakeNewProcessId for details.
// TODO: Instead of this workaround, we should just not launch // TODO: Instead of this workaround, we should just not launch
// FakeDebugProcess before the FIRM modules. // FakeDebugProcess before the FIRM modules.
OS::OS(Profiler::Profiler& profiler, Settings::Settings& settings, Interpreter::Setup& setup_, LogManager& log_manager, PicaContext& pica, EmuDisplay::EmuDisplay& display) OS::OS( Profiler::Profiler& profiler, Settings::Settings& settings,
: next_pid(num_firm_modules), Interpreter::Setup& setup_, LogManager& log_manager,
AudioFrontend& audio, PicaContext& pica, EmuDisplay::EmuDisplay& display)
: hypervisor(settings, audio),
next_pid(num_firm_modules),
internal_memory_owner(std::make_shared<MemoryBlockOwner>()), internal_memory_owner(std::make_shared<MemoryBlockOwner>()),
memory_regions { memory_regions {
MemoryManager { ApplicationMemoryStart(settings), ApplicationMemorySize(settings) }, MemoryManager { ApplicationMemoryStart(settings), ApplicationMemorySize(settings) },
@ -2020,8 +2023,8 @@ OS::~OS() {
debug_process.reset(); // TODO: Not needed debug_process.reset(); // TODO: Not needed
} }
std::pair<std::unique_ptr<OS>, std::unique_ptr<::ConsoleModule>> OS::Create(Settings::Settings& settings, Interpreter::Setup& setup, LogManager& log_manager, Profiler::Profiler& profiler, PicaContext& pica, EmuDisplay::EmuDisplay& display) { std::pair<std::unique_ptr<OS>, std::unique_ptr<::ConsoleModule>> OS::Create(Settings::Settings& settings, Interpreter::Setup& setup, LogManager& log_manager, Profiler::Profiler& profiler, AudioFrontend& audio, PicaContext& pica, EmuDisplay::EmuDisplay& display) {
auto&& os = std::make_unique<OS>(profiler, settings, setup, log_manager, pica, display); auto&& os = std::make_unique<OS>(profiler, settings, setup, log_manager, audio, pica, display);
auto&& console_module = std::unique_ptr<::ConsoleModule>(new ConsoleModule(*os)); auto&& console_module = std::unique_ptr<::ConsoleModule>(new ConsoleModule(*os));
return std::make_pair(std::move(os), std::move(console_module)); return std::make_pair(std::move(os), std::move(console_module));
} }

View file

@ -1563,7 +1563,8 @@ public: // TODO: privatize this again!
[[deprecated]] MemoryManager& memory_base() { return memory_regions[2]; } [[deprecated]] MemoryManager& memory_base() { return memory_regions[2]; }
MemoryManager& FindMemoryRegionContaining(uint32_t paddr, uint32_t size); MemoryManager& FindMemoryRegionContaining(uint32_t paddr, uint32_t size);
OS(Profiler::Profiler&, Settings::Settings&, Interpreter::Setup&, LogManager&, PicaContext&, EmuDisplay::EmuDisplay&); OS( Profiler::Profiler&, Settings::Settings&, Interpreter::Setup&,
LogManager&, AudioFrontend&, PicaContext&, EmuDisplay::EmuDisplay&);
~OS(); ~OS();
Profiler::Profiler& profiler; Profiler::Profiler& profiler;
@ -1869,7 +1870,7 @@ public:
*/ */
SVCEmptyFuture SVCAddThread(std::shared_ptr<Thread> thread); SVCEmptyFuture SVCAddThread(std::shared_ptr<Thread> thread);
static std::pair<std::unique_ptr<OS>, std::unique_ptr<ConsoleModule>> Create(Settings::Settings& settings, Interpreter::Setup& setup, LogManager& log_manager, Profiler::Profiler&, PicaContext&, EmuDisplay::EmuDisplay&); static std::pair<std::unique_ptr<OS>, std::unique_ptr<ConsoleModule>> Create(Settings::Settings& settings, Interpreter::Setup& setup, LogManager& log_manager, Profiler::Profiler&, AudioFrontend&, PicaContext&, EmuDisplay::EmuDisplay&);
/** /**
* Initialized the OS, spawning all service processes along the way. * Initialized the OS, spawning all service processes along the way.

View file

@ -79,7 +79,9 @@ struct State {
} }
Hypervisor::Hypervisor() : state(new HPV::State) { Hypervisor::Hypervisor(Settings::Settings& settings, AudioFrontend& audio_frontend) : state(new HPV::State) {
state->dsp_context.settings = &settings;
state->dsp_context.frontend = &audio_frontend;
} }
Hypervisor::~Hypervisor() = default; Hypervisor::~Hypervisor() = default;

View file

@ -1,9 +1,14 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <map>
#include <memory> #include <memory>
struct AudioFrontend;
namespace Settings {
struct Settings;
}
namespace HLE { namespace HLE {
namespace OS { namespace OS {
@ -32,7 +37,7 @@ class Hypervisor {
std::unique_ptr<HPV::State> state; std::unique_ptr<HPV::State> state;
public: public:
Hypervisor(); Hypervisor(Settings::Settings&, AudioFrontend&);
~Hypervisor(); ~Hypervisor();
// "thread" refers to the target (i.e. server) thread // "thread" refers to the target (i.e. server) thread

View file

@ -1,6 +1,7 @@
#include "dsp_hpv.hpp" #include "dsp_hpv.hpp"
#include "os_hypervisor_private.hpp" #include "os_hypervisor_private.hpp"
#include "os.hpp" #include "os.hpp"
#include <ui/audio_frontend.hpp>
#include <platform/dsp.hpp> #include <platform/dsp.hpp>
@ -28,6 +29,10 @@ struct DspService : SessionToPort {
DspService(RefCounted<Port> port_, DSPContext& context_) : SessionToPort(port_, context_) { DspService(RefCounted<Port> port_, DSPContext& context_) : SessionToPort(port_, context_) {
} }
DSPContext& GetContext() {
return static_cast<DSPContext&>(context);
}
void OnRequest(Hypervisor& hypervisor, Thread& thread, Handle session) override { void OnRequest(Hypervisor& hypervisor, Thread& thread, Handle session) override {
using namespace Platform::CTR::DSP; using namespace Platform::CTR::DSP;

View file

@ -2,6 +2,12 @@
#include "os_hypervisor_private.hpp" #include "os_hypervisor_private.hpp"
struct AudioFrontend;
namespace Settings {
struct Settings;
}
namespace HLE { namespace HLE {
namespace OS { namespace OS {
@ -9,6 +15,8 @@ namespace OS {
namespace HPV { namespace HPV {
struct DSPContext : SessionContext { struct DSPContext : SessionContext {
Settings::Settings* settings = nullptr;
AudioFrontend* frontend = nullptr;
}; };
HPV::RefCounted<Object> CreateDspService(RefCounted<Port> port, DSPContext&); HPV::RefCounted<Object> CreateDspService(RefCounted<Port> port, DSPContext&);

View file

@ -63,16 +63,19 @@ std::unique_ptr<Loader::GameCard> LoadGameCard(spdlog::logger& logger, Settings:
} }
EmuSession::EmuSession( LogManager& log_manager, Settings::Settings& settings, EmuSession::EmuSession( LogManager& log_manager, Settings::Settings& settings,
VulkanDeviceManager& vulkan_device_manager, EmuDisplay::EmuDisplay& display, AudioFrontend& audio, VulkanDeviceManager& vulkan_device_manager,
const KeyDatabase& keydb, std::unique_ptr<Loader::GameCard> gamecard) EmuDisplay::EmuDisplay& display, const KeyDatabase& keydb,
std::unique_ptr<Loader::GameCard> gamecard)
: setup(std::make_shared<Interpreter::Setup>(log_manager, keydb, std::move(gamecard), profiler, debug_server)), : setup(std::make_shared<Interpreter::Setup>(log_manager, keydb, std::move(gamecard), profiler, debug_server)),
pica { log_manager.RegisterLogger("Pica"), debug_server, settings, setup->mem, profiler, pica { log_manager.RegisterLogger("Pica"), debug_server, settings, setup->mem, profiler,
vulkan_device_manager.physical_device, *vulkan_device_manager.device, vulkan_device_manager.physical_device, *vulkan_device_manager.device,
vulkan_device_manager.graphics_queue_index, vulkan_device_manager.graphics_queue } { vulkan_device_manager.graphics_queue_index, vulkan_device_manager.graphics_queue } {
setup->cpus[0].cpu.cpsr.mode = ARM::InternalProcessorMode::User; setup->cpus[0].cpu.cpsr.mode = ARM::InternalProcessorMode::User;
setup->mem.InjectDependency(audio);
std::unique_ptr<ConsoleModule> os_module; std::unique_ptr<ConsoleModule> os_module;
std::tie(setup->os, os_module) = HLE::OS::OS::Create(settings, *setup, log_manager, profiler, pica, display); std::tie(setup->os, os_module) = HLE::OS::OS::Create(settings, *setup, log_manager, profiler, audio, pica, display);
for (auto& cpu : setup->cpus) for (auto& cpu : setup->cpus)
cpu.os = setup->os.get(); cpu.os = setup->os.get();
setup->os->Initialize(); setup->os->Initialize();

View file

@ -9,6 +9,8 @@
#include <framework/profiler.hpp> #include <framework/profiler.hpp>
struct AudioFrontend;
class NetworkConsole; class NetworkConsole;
namespace Loader { namespace Loader {
@ -36,7 +38,7 @@ struct EmuSession {
std::thread console_thread; std::thread console_thread;
EmuSession( LogManager&, Settings::Settings&, EmuSession( LogManager&, Settings::Settings&,
VulkanDeviceManager&, EmuDisplay::EmuDisplay&, AudioFrontend&, VulkanDeviceManager&, EmuDisplay::EmuDisplay&,
const KeyDatabase&, std::unique_ptr<Loader::GameCard>); const KeyDatabase&, std::unique_ptr<Loader::GameCard>);
void Run(); void Run();

View file

@ -0,0 +1,9 @@
#pragma once
#include <array>
#include <cstdint>
struct AudioFrontend {
virtual void OutputSamples(std::array<int16_t, 2> samples) = 0;
};