From 6c65e0914d1cda92a84e4aa7952913739974030e Mon Sep 17 00:00:00 2001 From: "Skyth (Asilkan)" <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:10:06 +0300 Subject: [PATCH] Implement miniaudio. (#15) --- UnleashedRecomp/CMakeLists.txt | 6 +- .../apu/driver/miniaudio_driver.cpp | 56 +++++++++++++ .../{sdl2_driver.h => miniaudio_driver.h} | 1 - UnleashedRecomp/apu/driver/sdl2_driver.cpp | 81 ------------------- UnleashedRecomp/cpu/guest_code.h | 2 +- UnleashedRecomp/cpu/guest_thread.cpp | 43 ++++++---- UnleashedRecomp/cpu/guest_thread.h | 9 +++ UnleashedRecomp/stdafx.h | 1 - vcpkg.json | 2 +- 9 files changed, 96 insertions(+), 105 deletions(-) create mode 100644 UnleashedRecomp/apu/driver/miniaudio_driver.cpp rename UnleashedRecomp/apu/driver/{sdl2_driver.h => miniaudio_driver.h} (67%) delete mode 100644 UnleashedRecomp/apu/driver/sdl2_driver.cpp diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 7cb86ec..2690905 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -64,7 +64,7 @@ set(SWA_APU_CXX_SOURCES if(SWA_XAUDIO2) list(APPEND SWA_APU_CXX_SOURCES "apu/driver/xaudio_driver.cpp") else() - list(APPEND SWA_APU_CXX_SOURCES "apu/driver/sdl2_driver.cpp") + list(APPEND SWA_APU_CXX_SOURCES "apu/driver/miniaudio_driver.cpp") endif() set(SWA_HID_CXX_SOURCES @@ -160,7 +160,7 @@ find_package(unofficial-concurrentqueue REQUIRED) find_package(imgui CONFIG REQUIRED) find_package(magic_enum CONFIG REQUIRED) find_package(unofficial-tiny-aes-c CONFIG REQUIRED) -find_path(READERWRITERQUEUE_INCLUDE_DIRS "readerwriterqueue/atomicops.h") +find_path(MINIAUDIO_INCLUDE_DIRS "miniaudio.h") file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) add_custom_command(TARGET UnleashedRecomp POST_BUILD @@ -208,7 +208,7 @@ target_include_directories(UnleashedRecomp PRIVATE ${LIBMSPACK_PATH} ${Stb_INCLUDE_DIR} ${SMOLV_SOURCE_DIR} - ${READERWRITERQUEUE_INCLUDE_DIRS} + ${MINIAUDIO_INCLUDE_DIRS} ) target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS}) diff --git a/UnleashedRecomp/apu/driver/miniaudio_driver.cpp b/UnleashedRecomp/apu/driver/miniaudio_driver.cpp new file mode 100644 index 0000000..a5b6dd2 --- /dev/null +++ b/UnleashedRecomp/apu/driver/miniaudio_driver.cpp @@ -0,0 +1,56 @@ +#include "miniaudio_driver.h" +#include +#include +#include +#include + +#define MINIAUDIO_IMPLEMENTATION +#include + +static PPCFunc* g_clientCallback{}; +static DWORD g_clientCallbackParam{}; // pointer in guest memory +static ma_device g_audioDevice{}; +static std::unique_ptr g_audioCtx; +static uint32_t* g_audioOutput; + +static void AudioCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +{ + if (g_audioCtx == nullptr) + g_audioCtx = std::make_unique(0); + + g_audioCtx->ppcContext.r3.u64 = g_clientCallbackParam; + g_audioOutput = reinterpret_cast(pOutput); + (*g_clientCallback)(g_audioCtx->ppcContext, reinterpret_cast(g_memory.base)); +} + +void XAudioInitializeSystem() +{ + ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.sampleRate = XAUDIO_SAMPLES_HZ; + deviceConfig.periodSizeInFrames = XAUDIO_NUM_SAMPLES; + deviceConfig.noPreSilencedOutputBuffer = true; + deviceConfig.dataCallback = AudioCallback; + deviceConfig.playback.format = ma_format_f32; + deviceConfig.playback.channels = XAUDIO_NUM_CHANNELS; + ma_device_init(nullptr, &deviceConfig, &g_audioDevice); +} + +void XAudioRegisterClient(PPCFunc* callback, uint32_t param) +{ + auto* pClientParam = static_cast(g_userHeap.Alloc(sizeof(param))); + ByteSwap(param); + *pClientParam = param; + g_clientCallbackParam = g_memory.MapVirtual(pClientParam); + g_clientCallback = callback; + + ma_device_start(&g_audioDevice); +} + +void XAudioSubmitFrame(void* samples) +{ + for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) + { + for (size_t j = 0; j < XAUDIO_NUM_CHANNELS; j++) + g_audioOutput[i * XAUDIO_NUM_CHANNELS + j] = std::byteswap(((uint32_t*)samples)[j * XAUDIO_NUM_SAMPLES + i]); + } +} diff --git a/UnleashedRecomp/apu/driver/sdl2_driver.h b/UnleashedRecomp/apu/driver/miniaudio_driver.h similarity index 67% rename from UnleashedRecomp/apu/driver/sdl2_driver.h rename to UnleashedRecomp/apu/driver/miniaudio_driver.h index ab732be..c8f99bf 100644 --- a/UnleashedRecomp/apu/driver/sdl2_driver.h +++ b/UnleashedRecomp/apu/driver/miniaudio_driver.h @@ -1,3 +1,2 @@ #pragma once -#include #include diff --git a/UnleashedRecomp/apu/driver/sdl2_driver.cpp b/UnleashedRecomp/apu/driver/sdl2_driver.cpp deleted file mode 100644 index da4cba7..0000000 --- a/UnleashedRecomp/apu/driver/sdl2_driver.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "sdl2_driver.h" -#include -#include -#include -#include - -#define SDLAUDIO_DRIVER_KEY (uint32_t)('SDLA') - -static constexpr uint32_t AUDIO_FRAME_SIZE = XAUDIO_NUM_SAMPLES * XAUDIO_NUM_CHANNELS; - -static std::atomic g_clientCallback{}; -static DWORD g_clientCallbackParam{}; // pointer in guest memory - -static SDL_AudioDeviceID g_audioDevice{}; -static moodycamel::BlockingReaderWriterCircularBuffer> g_audioQueue(16); - -static void SDLAudioCallback(void*, uint8_t* frames, int len) -{ - std::array audioFrame; - if (g_audioQueue.try_dequeue(audioFrame)) - memcpy(frames, &audioFrame, sizeof(audioFrame)); - else - memset(frames, 0, len); -} - -static PPC_FUNC(DriverLoop) -{ - GuestThread::SetThreadName(GetCurrentThreadId(), "Audio Driver"); - - while (true) - { - if (!g_clientCallback) - continue; - - ctx.r3.u64 = g_clientCallbackParam; - GuestCode::Run((void*)g_clientCallback, &ctx); - } -} - -void XAudioInitializeSystem() -{ - SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback"); - SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "SWA"); - - auto err = SDL_InitSubSystem(SDL_INIT_AUDIO); - SDL_AudioSpec spec{}; - spec.freq = XAUDIO_SAMPLES_HZ; - spec.format = AUDIO_F32SYS; - spec.channels = XAUDIO_NUM_CHANNELS; - spec.samples = XAUDIO_NUM_SAMPLES; - spec.callback = SDLAudioCallback; - g_audioDevice = SDL_OpenAudioDevice(nullptr, false, &spec, &spec, 0); - assert(g_audioDevice); - - SDL_PauseAudioDevice(g_audioDevice, 0); - KeInsertHostFunction(SDLAUDIO_DRIVER_KEY, DriverLoop); - GuestThread::Start(SDLAUDIO_DRIVER_KEY, 0, 0, nullptr); -} - -void XAudioRegisterClient(PPCFunc* callback, uint32_t param) -{ - auto* pClientParam = static_cast(g_userHeap.Alloc(sizeof(param))); - ByteSwap(param); - *pClientParam = param; - g_clientCallbackParam = g_memory.MapVirtual(pClientParam); - - g_clientCallback = callback; -} - -void XAudioSubmitFrame(void* samples) -{ - std::array audioFrame; - - for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) - { - for (size_t j = 0; j < XAUDIO_NUM_CHANNELS; j++) - audioFrame[i * XAUDIO_NUM_CHANNELS + j] = std::byteswap(((uint32_t*)samples)[j * XAUDIO_NUM_SAMPLES + i]); - } - - g_audioQueue.wait_enqueue(audioFrame); -} diff --git a/UnleashedRecomp/cpu/guest_code.h b/UnleashedRecomp/cpu/guest_code.h index 11a2708..4177b05 100644 --- a/UnleashedRecomp/cpu/guest_code.h +++ b/UnleashedRecomp/cpu/guest_code.h @@ -4,7 +4,7 @@ struct GuestCode { - inline static void Run(void* hostAddress, PPCContext* ctx, void* baseAddress, void* callStack) + inline static void Run(void* hostAddress, PPCContext* ctx, void* baseAddress) { ctx->fpscr.loadFromHost(); reinterpret_cast(hostAddress)(*ctx, reinterpret_cast(baseAddress)); diff --git a/UnleashedRecomp/cpu/guest_thread.cpp b/UnleashedRecomp/cpu/guest_thread.cpp index c13f580..21010ee 100644 --- a/UnleashedRecomp/cpu/guest_thread.cpp +++ b/UnleashedRecomp/cpu/guest_thread.cpp @@ -11,24 +11,15 @@ constexpr size_t PCR_SIZE = 0xAB0; constexpr size_t TLS_SIZE = 0x100; constexpr size_t TEB_SIZE = 0x2E0; constexpr size_t STACK_SIZE = 0x40000; -constexpr size_t CALL_STACK_SIZE = 0x8000; -constexpr size_t TOTAL_SIZE = PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE + CALL_STACK_SIZE; +constexpr size_t TOTAL_SIZE = PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE; constexpr size_t TEB_OFFSET = PCR_SIZE + TLS_SIZE; -DWORD GuestThread::Start(uint32_t function) +GuestThreadContext::GuestThreadContext(uint32_t cpuNumber) { - const GuestThreadParameter parameter{ function }; - return Start(parameter); -} - -DWORD GuestThread::Start(const GuestThreadParameter& parameter) -{ - auto* thread = (uint8_t*)g_userHeap.Alloc(TOTAL_SIZE); - - const auto procMask = (uint8_t)(parameter.flags >> 24); - const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask); + assert(thread == nullptr); + thread = (uint8_t*)g_userHeap.Alloc(TOTAL_SIZE); memset(thread, 0, TOTAL_SIZE); *(uint32_t*)thread = std::byteswap(g_memory.MapVirtual(thread + PCR_SIZE)); // tls pointer @@ -38,18 +29,36 @@ DWORD GuestThread::Start(const GuestThreadParameter& parameter) *(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky *(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = std::byteswap(GetCurrentThreadId()); // thread id - PPCContext ppcContext{}; ppcContext.fn = (uint8_t*)g_codeCache.bucket; ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer - ppcContext.r3.u64 = parameter.value; ppcContext.r13.u64 = g_memory.MapVirtual(thread); + assert(GetPPCContext() == nullptr); SetPPCContext(ppcContext); +} - GuestCode::Run(g_codeCache.Find(parameter.function), &ppcContext, g_memory.Translate(0), g_memory.Translate(ppcContext.r1.u32)); +GuestThreadContext::~GuestThreadContext() +{ g_userHeap.Free(thread); +} - return (DWORD)ppcContext.r3.u64; +DWORD GuestThread::Start(uint32_t function) +{ + const GuestThreadParameter parameter{ function }; + return Start(parameter); +} + +DWORD GuestThread::Start(const GuestThreadParameter& parameter) +{ + const auto procMask = (uint8_t)(parameter.flags >> 24); + const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask); + + GuestThreadContext ctx(cpuNumber); + ctx.ppcContext.r3.u64 = parameter.value; + + GuestCode::Run(g_codeCache.Find(parameter.function), &ctx.ppcContext, g_memory.Translate(0)); + + return (DWORD)ctx.ppcContext.r3.u64; } DWORD HostThreadStart(void* pParameter) diff --git a/UnleashedRecomp/cpu/guest_thread.h b/UnleashedRecomp/cpu/guest_thread.h index fd7f8ff..7fb6e9b 100644 --- a/UnleashedRecomp/cpu/guest_thread.h +++ b/UnleashedRecomp/cpu/guest_thread.h @@ -8,6 +8,15 @@ struct GuestThreadParameter uint32_t flags; }; +struct GuestThreadContext +{ + PPCContext ppcContext{}; + uint8_t* thread = nullptr; + + GuestThreadContext(uint32_t cpuNumber); + ~GuestThreadContext(); +}; + struct GuestThread { static DWORD Start(uint32_t function); diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index bf52446..8fd5bb2 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -32,7 +32,6 @@ #include #include #include -#include using Microsoft::WRL::ComPtr; diff --git a/vcpkg.json b/vcpkg.json index 5e13523..1f07072 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -22,6 +22,6 @@ "features": [ "sdl2-binding" ] }, "magic-enum", - "readerwriterqueue" + "miniaudio" ] }