diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 4b8d0302..20753538 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -137,7 +137,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/miniaudio_driver.cpp") + list(APPEND SWA_APU_CXX_SOURCES "apu/driver/sdl2_driver.cpp") endif() set(SWA_HID_CXX_SOURCES diff --git a/UnleashedRecomp/apu/driver/miniaudio_driver.cpp b/UnleashedRecomp/apu/driver/miniaudio_driver.cpp deleted file mode 100644 index b2dbc0ee..00000000 --- a/UnleashedRecomp/apu/driver/miniaudio_driver.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "miniaudio_driver.h" -#include -#include -#include -#include - -static PPCFunc* g_clientCallback{}; -static uint32_t 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))); - ByteSwapInplace(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] = ByteSwap(((uint32_t*)samples)[j * XAUDIO_NUM_SAMPLES + i]); - } -} diff --git a/UnleashedRecomp/apu/driver/sdl2_driver.cpp b/UnleashedRecomp/apu/driver/sdl2_driver.cpp new file mode 100644 index 00000000..12bca12f --- /dev/null +++ b/UnleashedRecomp/apu/driver/sdl2_driver.cpp @@ -0,0 +1,97 @@ +#include "sdl2_driver.h" +#include +#include +#include +#include + +static PPCFunc* g_clientCallback{}; +static uint32_t g_clientCallbackParam{}; // pointer in guest memory +static SDL_AudioDeviceID g_audioDevice{}; +static std::unique_ptr g_audioCtx; +static uint32_t* g_audioOutput; +static bool g_downMixToStereo; + +static void AudioCallback(void*, uint8_t* frames, int len) +{ + if (g_audioCtx == nullptr) + g_audioCtx = std::make_unique(0); + + g_audioCtx->ppcContext.r3.u64 = g_clientCallbackParam; + g_audioOutput = reinterpret_cast(frames); + (*g_clientCallback)(g_audioCtx->ppcContext, reinterpret_cast(g_memory.base)); +} + +void XAudioInitializeSystem() +{ + SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback"); + SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Unleashed Recompiled"); + SDL_InitSubSystem(SDL_INIT_AUDIO); + + SDL_AudioSpec desired{}, obtained{}; + desired.freq = XAUDIO_SAMPLES_HZ; + desired.format = AUDIO_F32SYS; + desired.channels = XAUDIO_NUM_CHANNELS; + desired.samples = XAUDIO_NUM_SAMPLES; + desired.callback = AudioCallback; + g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, SDL_AUDIO_ALLOW_CHANNELS_CHANGE); + + if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) + { + SDL_CloseAudioDevice(g_audioDevice); + g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); + } + + g_downMixToStereo = (obtained.channels == 2); +} + +void XAudioRegisterClient(PPCFunc* callback, uint32_t param) +{ + auto* pClientParam = static_cast(g_userHeap.Alloc(sizeof(param))); + ByteSwapInplace(param); + *pClientParam = param; + g_clientCallbackParam = g_memory.MapVirtual(pClientParam); + g_clientCallback = callback; + + SDL_PauseAudioDevice(g_audioDevice, 0); +} + +void XAudioSubmitFrame(void* samples) +{ + if (g_downMixToStereo) + { + // 0: left 1.0f, right 0.0f + // 1: left 0.0f, right 1.0f + // 2: left 0.75f, right 0.75f + // 3: left 0.0f, right 0.0f + // 4: left 1.0f, right 0.0f + // 5: left 0.0f, right 1.0f + + auto floatSamples = reinterpret_cast*>(samples); + + for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) + { + float ch0 = floatSamples[0 * XAUDIO_NUM_SAMPLES + i]; + float ch1 = floatSamples[1 * XAUDIO_NUM_SAMPLES + i]; + float ch2 = floatSamples[2 * XAUDIO_NUM_SAMPLES + i]; + float ch3 = floatSamples[3 * XAUDIO_NUM_SAMPLES + i]; + float ch4 = floatSamples[4 * XAUDIO_NUM_SAMPLES + i]; + float ch5 = floatSamples[5 * XAUDIO_NUM_SAMPLES + i]; + + float left = ch0 + ch2 * 0.75f + ch4; + float right = ch1 + ch2 * 0.75f + ch5; + + g_audioOutput[i * 2 + 0] = *reinterpret_cast(&left); + g_audioOutput[i * 2 + 1] = *reinterpret_cast(&right); + } + } + else + { + auto rawSamples = reinterpret_cast*>(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] = rawSamples[j * XAUDIO_NUM_SAMPLES + i]; + } + } +} diff --git a/UnleashedRecomp/apu/driver/miniaudio_driver.h b/UnleashedRecomp/apu/driver/sdl2_driver.h similarity index 100% rename from UnleashedRecomp/apu/driver/miniaudio_driver.h rename to UnleashedRecomp/apu/driver/sdl2_driver.h diff --git a/UnleashedRecomp/apu/driver/xaudio_driver.cpp b/UnleashedRecomp/apu/driver/xaudio_driver.cpp index 2e59a9ef..1d98ca94 100644 --- a/UnleashedRecomp/apu/driver/xaudio_driver.cpp +++ b/UnleashedRecomp/apu/driver/xaudio_driver.cpp @@ -90,7 +90,7 @@ void XAudioInitializeSystem() g_sourceVoice->Start(); KeInsertHostFunction(XAUDIO_DRIVER_KEY, DriverLoop); - GuestThread::Start(XAUDIO_DRIVER_KEY, 0, 0, &g_driverThread); + GuestThread::Start({ XAUDIO_DRIVER_KEY, 0, 0 }, nullptr); } void XAudioRegisterClient(PPCFunc* callback, uint32_t param)