From baf24bb36a112532fcff182904018fb37872c05b Mon Sep 17 00:00:00 2001 From: Sajid Date: Tue, 1 Oct 2024 01:20:29 +0600 Subject: [PATCH] audio gaming --- UnleashedRecomp/CMakeLists.txt | 5 + UnleashedRecomp/apu/audio.cpp | 4 +- UnleashedRecomp/apu/audio.h | 12 +- UnleashedRecomp/apu/driver/xaudio_driver.cpp | 120 +++++++++++++++++++ UnleashedRecomp/cpu/code_cache.cpp | 7 +- UnleashedRecomp/cpu/code_cache.h | 3 +- UnleashedRecomp/cpu/guest_code.h | 2 +- UnleashedRecomp/cpu/guest_thread.cpp | 15 +++ UnleashedRecomp/gpu/video.cpp | 16 +++ UnleashedRecomp/main.cpp | 3 + 10 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 UnleashedRecomp/apu/driver/xaudio_driver.cpp diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 573d411..bab79d6 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -4,6 +4,10 @@ file(GLOB "*.cpp") add_compile_definitions(SWA_IMPL) add_compile_definitions(SDL_MAIN_HANDLED) + +# Microsoft wtf? +add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR ) + add_compile_options( "/D_HAS_EXCEPTIONS=0" "/fp:strict" @@ -41,6 +45,7 @@ set(SWA_GPU_CXX_SOURCES set(SWA_APU_CXX_SOURCES "apu/audio.cpp" + "apu/driver/xaudio_driver.cpp" ) set(SWA_HID_CXX_SOURCES diff --git a/UnleashedRecomp/apu/audio.cpp b/UnleashedRecomp/apu/audio.cpp index e0f6cc2..c234c5a 100644 --- a/UnleashedRecomp/apu/audio.cpp +++ b/UnleashedRecomp/apu/audio.cpp @@ -7,6 +7,7 @@ uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver) { *driver = AUDIO_DRIVER_KEY; + XAudioRegisterClient(KeFindHostFunction(*callback), callback[1]); return 0; } @@ -15,7 +16,8 @@ uint32_t XAudioUnregisterRenderDriverClient(DWORD driver) return 0; } -uint32_t XAudioSubmitRenderDriverFrame(XLPDWORD callback, XLPDWORD driver) +uint32_t XAudioSubmitRenderDriverFrame(uint32_t driver, void* samples) { + XAudioSubmitFrame(samples); return 0; } diff --git a/UnleashedRecomp/apu/audio.h b/UnleashedRecomp/apu/audio.h index fdf2a2a..e04cf38 100644 --- a/UnleashedRecomp/apu/audio.h +++ b/UnleashedRecomp/apu/audio.h @@ -1,5 +1,11 @@ #pragma once -SWA_API uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver); -SWA_API uint32_t XAudioUnregisterRenderDriverClient(DWORD driver); -SWA_API uint32_t XAudioSubmitRenderDriverFrame(XLPDWORD callback, XLPDWORD driver); +#ifdef SWA_IMPL +void XAudioInitializeSystem(); +void XAudioRegisterClient(PPCFunc* callback, uint32_t param); +void XAudioSubmitFrame(void* samples); +#endif + +uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver); +uint32_t XAudioUnregisterRenderDriverClient(DWORD driver); +uint32_t XAudioSubmitRenderDriverFrame(uint32_t driver, void* samples); diff --git a/UnleashedRecomp/apu/driver/xaudio_driver.cpp b/UnleashedRecomp/apu/driver/xaudio_driver.cpp new file mode 100644 index 0000000..c000133 --- /dev/null +++ b/UnleashedRecomp/apu/driver/xaudio_driver.cpp @@ -0,0 +1,120 @@ +#include +#include "xaudio_driver.h" +#include + +#include +#include +#include +#include + +#define XAUDIO_DRIVER_KEY (uint32_t)('XAUD') + +PPCFunc* g_clientCallback{}; +DWORD g_clientCallbackParam{}; +DWORD g_driverThread{}; + +// TODO: Should use a counted ptr +IXAudio2* g_audio{}; +IXAudio2MasteringVoice* g_masteringVoice{}; +IXAudio2SourceVoice* g_sourceVoice{}; + +constexpr uint32_t g_semaphoreCount = 16; +constexpr uint32_t g_audioFrameSize = 256 * 6; +HANDLE g_audioSemaphore{ CreateSemaphoreA(nullptr, g_semaphoreCount, g_semaphoreCount, nullptr) }; +uint32_t g_audioFrames[g_audioFrameSize * g_semaphoreCount]; +uint32_t g_audioFrameIndex = 0; + +class VoiceCallback : public IXAudio2VoiceCallback +{ + void OnVoiceProcessingPassStart(UINT32 BytesRequired) override {} + void OnVoiceProcessingPassEnd() override {} + + void OnBufferStart(void* pBufferContext) override {} + void OnBufferEnd(void* pBufferContext) override + { + ReleaseSemaphore(g_audioSemaphore, 1, nullptr); + } + + void OnStreamEnd() override {} + + void OnLoopEnd(void* pBufferContext) override {} + void OnVoiceError(void* pBufferContext, HRESULT Error) override {} +} gVoiceCallback; + +inline PPC_FUNC(DriverLoop) +{ + GuestThread::SetThreadName(GetCurrentThreadId(), "Audio Driver"); + + auto* cpu = GetPPCContext(); + while (true) + { + if (!g_clientCallback) + { + continue; + } + + WaitForSingleObject(g_audioSemaphore, INFINITE); + + cpu->r3.u64 = g_clientCallbackParam; + GuestCode::Run(g_clientCallback, cpu); + } +} + +void XAudioInitializeSystem() +{ + if (g_audio) + { + return; + } + + //reinterpret_cast( + // GetProcAddress(LoadLibraryA("XAudio2_8.dll"), "XAudio2Create"))(&gAudio, 0, 1); + + XAudio2Create(&g_audio); + g_audio->CreateMasteringVoice(&g_masteringVoice); + + WAVEFORMATIEEEFLOATEX format{}; + format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + format.Format.cbSize = sizeof(format) - sizeof(format.Format); + format.Format.nChannels = 6; + format.Format.nSamplesPerSec = 48000; + format.Format.wBitsPerSample = 32; + format.Format.nBlockAlign = (format.Format.nChannels * format.Format.wBitsPerSample) / 8; + format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign; + + format.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample; + format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | + SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; + + g_audio->CreateSourceVoice(&g_sourceVoice, &format.Format, 0, 1024, &gVoiceCallback); + g_sourceVoice->Start(); + + KeInsertHostFunction(XAUDIO_DRIVER_KEY, DriverLoop); + GuestThread::Start(XAUDIO_DRIVER_KEY, 0, 0, &g_driverThread); +} + +void XAudioRegisterClient(PPCFunc* callback, uint32_t param) +{ + g_clientCallback = callback; + g_clientCallbackParam = param; +} + +void XAudioSubmitFrame(void* samples) +{ + uint32_t* audioFrame = &g_audioFrames[g_audioFrameSize * g_audioFrameIndex]; + g_audioFrameIndex = (g_audioFrameIndex + 1) % g_semaphoreCount; + + for (size_t i = 0; i < 256; i++) + { + for (size_t j = 0; j < 6; j++) + audioFrame[i * 6 + j] = std::byteswap(((uint32_t*)samples)[j * 256 + i]); + } + + XAUDIO2_BUFFER buffer{}; + buffer.pAudioData = (BYTE*)audioFrame; + buffer.AudioBytes = 256 * 6 * sizeof(float); + buffer.PlayLength = 256; + + g_sourceVoice->SubmitSourceBuffer(&buffer); +} diff --git a/UnleashedRecomp/cpu/code_cache.cpp b/UnleashedRecomp/cpu/code_cache.cpp index 39fa2e6..84df9dd 100644 --- a/UnleashedRecomp/cpu/code_cache.cpp +++ b/UnleashedRecomp/cpu/code_cache.cpp @@ -36,7 +36,12 @@ void* CodeCache::Find(uint32_t guest) const return *reinterpret_cast(bucket + static_cast(guest) * 2); } -PPCFunc* KeFindHostFunction(uint32_t guest) +SWA_API PPCFunc* KeFindHostFunction(uint32_t guest) { return static_cast(gCodeCache.Find(guest)); } + +SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function) +{ + gCodeCache.Insert(guest, function); +} diff --git a/UnleashedRecomp/cpu/code_cache.h b/UnleashedRecomp/cpu/code_cache.h index 55a6da9..09d7451 100644 --- a/UnleashedRecomp/cpu/code_cache.h +++ b/UnleashedRecomp/cpu/code_cache.h @@ -13,6 +13,7 @@ struct CodeCache void* Find(uint32_t guest) const; }; -PPCFunc* KeFindHostFunction(uint32_t guest); +SWA_API PPCFunc* KeFindHostFunction(uint32_t guest); +SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function); extern CodeCache gCodeCache; diff --git a/UnleashedRecomp/cpu/guest_code.h b/UnleashedRecomp/cpu/guest_code.h index bf0453c..9c92095 100644 --- a/UnleashedRecomp/cpu/guest_code.h +++ b/UnleashedRecomp/cpu/guest_code.h @@ -1,6 +1,6 @@ #pragma once #include "ppc_context.h" -#include "memory.h" +#include struct GuestCode { diff --git a/UnleashedRecomp/cpu/guest_thread.cpp b/UnleashedRecomp/cpu/guest_thread.cpp index b5338cb..7bffa7e 100644 --- a/UnleashedRecomp/cpu/guest_thread.cpp +++ b/UnleashedRecomp/cpu/guest_thread.cpp @@ -133,6 +133,21 @@ DWORD SetThreadIdealProcessorImpl(uint32_t hThread, DWORD dwIdealProcessor) return SetThreadIdealProcessor((HANDLE)hThread, dwIdealProcessor); } +GUEST_FUNCTION_HOOK(sub_831B0ED0, memcpy); +GUEST_FUNCTION_HOOK(sub_831CCB98, memcpy); +GUEST_FUNCTION_HOOK(sub_831CEAE0, memcpy); +GUEST_FUNCTION_HOOK(sub_831CEE04, memcpy); +GUEST_FUNCTION_HOOK(sub_831CF2D0, memcpy); +GUEST_FUNCTION_HOOK(sub_831CF660, memcpy); +GUEST_FUNCTION_HOOK(sub_831B1358, memcpy); +GUEST_FUNCTION_HOOK(sub_831B5E00, memmove); +GUEST_FUNCTION_HOOK(sub_831B0BA0, memset); +GUEST_FUNCTION_HOOK(sub_831CCAA0, memset); + +GUEST_FUNCTION_HOOK(sub_82BD4CA8, OutputDebugStringA); + GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl); GUEST_FUNCTION_HOOK(sub_82BD57A8, GetThreadPriorityImpl); GUEST_FUNCTION_HOOK(sub_82BD5910, SetThreadIdealProcessorImpl); + +GUEST_FUNCTION_STUB(sub_82BD58F8); // Some function that updates the TEB, don't really care since the field is not set diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index e9de774..73f23d9 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -13,6 +13,22 @@ void* VdGetGlobalDevice() return nullptr; } +// CApplication::Update +PPC_FUNC_IMPL(__imp__sub_822C1130); +PPC_FUNC(sub_822C1130) +{ + SDL_PumpEvents(); + SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); + + __imp__sub_822C1130(ctx, base); +} + +// Skip logo +PPC_FUNC(sub_82547DF0) +{ + sub_825517C8(ctx, base); +} + // Direct3D stubs GUEST_FUNCTION_STUB(sub_824EB290); GUEST_FUNCTION_STUB(sub_82BDA8C0); diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index 675699c..cca736d 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #define GAME_XEX_PATH "game:\\default.xex" @@ -52,6 +53,8 @@ void KiSystemStartup() // OS mounts game data to D: XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr); + + XAudioInitializeSystem(); } uint32_t LdrLoadModule(const char* path)