diff --git a/.gitmodules b/.gitmodules index 59978ec3..6981e9f4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,9 +16,6 @@ [submodule "thirdparty/msdf-atlas-gen"] path = thirdparty/msdf-atlas-gen url = https://github.com/Chlumsky/msdf-atlas-gen.git -[submodule "thirdparty/miniaudio"] - path = thirdparty/miniaudio - url = https://github.com/mackron/miniaudio [submodule "thirdparty/vcpkg"] path = thirdparty/vcpkg url = https://github.com/microsoft/vcpkg @@ -58,9 +55,6 @@ [submodule "thirdparty/unordered_dense"] path = thirdparty/unordered_dense url = https://github.com/martinus/unordered_dense.git -[submodule "thirdparty/vorbis"] - path = thirdparty/vorbis - url = https://gitlab.xiph.org/xiph/vorbis.git -[submodule "thirdparty/ogg"] - path = thirdparty/ogg - url = https://gitlab.xiph.org/xiph/ogg.git +[submodule "thirdparty/SDL_mixer"] + path = thirdparty/SDL_mixer + url = https://github.com/libsdl-org/SDL_mixer \ No newline at end of file diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 4b8d0302..239c85c4 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -7,7 +7,7 @@ endif() if (CMAKE_SYSTEM_NAME MATCHES "Linux") option(SWA_FLATPAK "Configure the build for Flatpak compatibility." OFF) -endif() +endif() option(SWA_XAUDIO2 "Use XAudio2 for audio playback" OFF) @@ -53,14 +53,14 @@ add_compile_options( -Wno-int-to-void-pointer-cast -Wno-invalid-offsetof -Wno-null-arithmetic - -Wno-null-conversion + -Wno-null-conversion -Wno-tautological-undefined-compare -) - -if (WIN32) - add_compile_options(/fp:strict) -else() - add_compile_options(-ffp-model=strict) +) + +if (WIN32) + add_compile_options(/fp:strict) +else() + add_compile_options(-ffp-model=strict) endif() add_compile_definitions( @@ -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 @@ -187,46 +187,45 @@ set(SWA_INSTALL_CXX_SOURCES "install/hashes/mazuri.cpp" "install/hashes/spagonia.cpp" "install/hashes/update.cpp" -) - +) + set(SWA_USER_CXX_SOURCES "user/achievement_data.cpp" "user/config.cpp" -) - -set(SWA_THIRDPARTY_SOURCES - "${SWA_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp" - "${SWA_THIRDPARTY_ROOT}/imgui/imgui.cpp" - "${SWA_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp" - "${SWA_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp" - "${SWA_THIRDPARTY_ROOT}/imgui/imgui_tables.cpp" - "${SWA_THIRDPARTY_ROOT}/imgui/imgui_widgets.cpp" - "${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c" - "${SWA_THIRDPARTY_ROOT}/tiny-AES-c/aes.c" - "${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source/smolv.cpp" -) - -set(SWA_THIRDPARTY_INCLUDES - "${SWA_THIRDPARTY_ROOT}/concurrentqueue" +) + +set(SWA_THIRDPARTY_SOURCES + "${SWA_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp" + "${SWA_THIRDPARTY_ROOT}/imgui/imgui.cpp" + "${SWA_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp" + "${SWA_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp" + "${SWA_THIRDPARTY_ROOT}/imgui/imgui_tables.cpp" + "${SWA_THIRDPARTY_ROOT}/imgui/imgui_widgets.cpp" + "${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c" + "${SWA_THIRDPARTY_ROOT}/tiny-AES-c/aes.c" + "${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source/smolv.cpp" +) + +set(SWA_THIRDPARTY_INCLUDES + "${SWA_THIRDPARTY_ROOT}/concurrentqueue" "${SWA_THIRDPARTY_ROOT}/ddspp" - "${SWA_THIRDPARTY_ROOT}/imgui" + "${SWA_THIRDPARTY_ROOT}/imgui" "${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack" - "${SWA_THIRDPARTY_ROOT}/magic_enum/include" - "${SWA_THIRDPARTY_ROOT}/miniaudio" - "${SWA_THIRDPARTY_ROOT}/stb" - "${SWA_THIRDPARTY_ROOT}/tiny-AES-c" + "${SWA_THIRDPARTY_ROOT}/magic_enum/include" + "${SWA_THIRDPARTY_ROOT}/stb" + "${SWA_THIRDPARTY_ROOT}/tiny-AES-c" "${SWA_THIRDPARTY_ROOT}/TinySHA1" "${SWA_THIRDPARTY_ROOT}/unordered_dense/include" - "${SWA_THIRDPARTY_ROOT}/volk" - "${SWA_THIRDPARTY_ROOT}/Vulkan-Headers/include" - "${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include" - "${SWA_TOOLS_ROOT}/bc_diff" + "${SWA_THIRDPARTY_ROOT}/volk" + "${SWA_THIRDPARTY_ROOT}/Vulkan-Headers/include" + "${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include" + "${SWA_TOOLS_ROOT}/bc_diff" "${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source" -) - -if (SWA_D3D12) - list(APPEND SWA_THIRDPARTY_INCLUDES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include") - list(APPEND SWA_THIRDPARTY_SOURCES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp") +) + +if (SWA_D3D12) + list(APPEND SWA_THIRDPARTY_INCLUDES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include") + list(APPEND SWA_THIRDPARTY_SOURCES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp") endif() set_source_files_properties(${SWA_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) @@ -248,7 +247,7 @@ set(SWA_CXX_SOURCES ${SWA_PATCHES_CXX_SOURCES} ${SWA_UI_CXX_SOURCES} ${SWA_INSTALL_CXX_SOURCES} - ${SWA_USER_CXX_SOURCES} + ${SWA_USER_CXX_SOURCES} ${SWA_THIRDPARTY_SOURCES} ) @@ -261,7 +260,7 @@ else() add_executable(UnleashedRecomp ${SWA_CXX_SOURCES}) endif() -set_target_properties(UnleashedRecomp PROPERTIES OUTPUT_NAME ${TARGET_NAME}) +set_target_properties(UnleashedRecomp PROPERTIES OUTPUT_NAME ${TARGET_NAME}) if (SWA_FLATPAK) target_compile_definitions(UnleashedRecomp PRIVATE "GAME_INSTALL_DIRECTORY=\"/var/data\"") @@ -273,7 +272,7 @@ if (SWA_D3D12) target_compile_definitions(UnleashedRecomp PRIVATE SWA_D3D12) endif() -find_package(directx-dxc REQUIRED) +find_package(directx-dxc REQUIRED) if (SWA_D3D12) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) @@ -289,7 +288,7 @@ if (SWA_D3D12) Microsoft::DirectX-Headers Microsoft::DirectX-Guids Microsoft::DirectX12-Agility - Microsoft::DirectXShaderCompiler + Microsoft::DirectXShaderCompiler Microsoft::DXIL dxgi ) @@ -307,21 +306,22 @@ if (WIN32) endif() target_link_libraries(UnleashedRecomp PRIVATE - fmt::fmt + fmt::fmt libzstd_static msdf-atlas-gen::msdf-atlas-gen nfd::nfd o1heap PowerUtils SDL2::SDL2-static + SDL2_mixer tomlplusplus::tomlplusplus UnleashedRecompLib - Vorbis::vorbisfile - xxHash::xxhash ) + xxHash::xxhash +) target_include_directories(UnleashedRecomp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - "${CMAKE_CURRENT_SOURCE_DIR}/api" + "${CMAKE_CURRENT_SOURCE_DIR}/api" ${SWA_THIRDPARTY_INCLUDES} ) diff --git a/UnleashedRecomp/app.cpp b/UnleashedRecomp/app.cpp index ac936fc7..fa8c0982 100644 --- a/UnleashedRecomp/app.cpp +++ b/UnleashedRecomp/app.cpp @@ -15,6 +15,11 @@ void App::Restart(std::vector restartArgs) void App::Exit() { Config::Save(); + +#ifdef _WIN32 + timeEndPeriod(1); +#endif + std::_Exit(0); } 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..7c8777e7 --- /dev/null +++ b/UnleashedRecomp/apu/driver/sdl2_driver.cpp @@ -0,0 +1,128 @@ +#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 bool g_downMixToStereo; + +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; + 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); +} + +static std::unique_ptr g_audioThread; + +static void AudioThread() +{ + using namespace std::chrono_literals; + + GuestThreadContext ctx(0); + + size_t channels = g_downMixToStereo ? 2 : XAUDIO_NUM_CHANNELS; + + constexpr double INTERVAL = double(XAUDIO_NUM_SAMPLES) / double(XAUDIO_SAMPLES_HZ); + auto start = std::chrono::steady_clock::now(); + size_t iteration = 1; + + while (true) + { + uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice); + constexpr size_t MAX_LATENCY = 10; + const size_t callbackAudioSize = channels * XAUDIO_NUM_SAMPLES * sizeof(float); + + if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY) + { + ctx.ppcContext.r3.u32 = g_clientCallbackParam; + g_clientCallback(ctx.ppcContext, reinterpret_cast(g_memory.base)); + } + + auto next = start + std::chrono::duration(iteration * INTERVAL); + auto now = std::chrono::steady_clock::now(); + + if ((next - now) > 1s) + next = now; + + std::this_thread::sleep_until(next); + + iteration = std::chrono::duration(std::chrono::steady_clock::now() - start).count() / INTERVAL + 1; + } +} + +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); + g_audioThread = std::make_unique(AudioThread); +} + +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); + + std::array audioFrames; + + 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]; + + audioFrames[i * 2 + 0] = ch0 + ch2 * 0.75f + ch4; + audioFrames[i * 2 + 1] = ch1 + ch2 * 0.75f + ch5; + } + + SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); + } + else + { + auto rawSamples = reinterpret_cast*>(samples); + + std::array audioFrames; + + for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) + { + for (size_t j = 0; j < XAUDIO_NUM_CHANNELS; j++) + audioFrames[i * XAUDIO_NUM_CHANNELS + j] = rawSamples[j * XAUDIO_NUM_SAMPLES + i]; + } + + SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); + } +} 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) diff --git a/UnleashedRecomp/apu/embedded_player.cpp b/UnleashedRecomp/apu/embedded_player.cpp index 2fb899d0..e72b7b6a 100644 --- a/UnleashedRecomp/apu/embedded_player.cpp +++ b/UnleashedRecomp/apu/embedded_player.cpp @@ -10,82 +10,6 @@ #include #include -#pragma region libvorbis -static ma_result ma_decoding_backend_init__libvorbis(void* pUserData, ma_read_proc onRead, ma_seek_proc onSeek, ma_tell_proc onTell, void* pReadSeekTellUserData, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_libvorbis* pVorbis; - - (void)pUserData; - - pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_libvorbis_init(onRead, onSeek, onTell, pReadSeekTellUserData, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static ma_result ma_decoding_backend_init_file__libvorbis(void* pUserData, const char* pFilePath, const ma_decoding_backend_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_data_source** ppBackend) -{ - ma_result result; - ma_libvorbis* pVorbis; - - (void)pUserData; - - pVorbis = (ma_libvorbis*)ma_malloc(sizeof(*pVorbis), pAllocationCallbacks); - if (pVorbis == NULL) { - return MA_OUT_OF_MEMORY; - } - - result = ma_libvorbis_init_file(pFilePath, pConfig, pAllocationCallbacks, pVorbis); - if (result != MA_SUCCESS) { - ma_free(pVorbis, pAllocationCallbacks); - return result; - } - - *ppBackend = pVorbis; - - return MA_SUCCESS; -} - -static void ma_decoding_backend_uninit__libvorbis(void* pUserData, ma_data_source* pBackend, const ma_allocation_callbacks* pAllocationCallbacks) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend; - - (void)pUserData; - - ma_libvorbis_uninit(pVorbis, pAllocationCallbacks); - ma_free(pVorbis, pAllocationCallbacks); -} - -static ma_result ma_decoding_backend_get_channel_map__libvorbis(void* pUserData, ma_data_source* pBackend, ma_channel* pChannelMap, size_t channelMapCap) -{ - ma_libvorbis* pVorbis = (ma_libvorbis*)pBackend; - - (void)pUserData; - - return ma_libvorbis_get_data_format(pVorbis, NULL, NULL, NULL, pChannelMap, channelMapCap); -} - -static ma_decoding_backend_vtable g_ma_decoding_backend_vtable_libvorbis = -{ - ma_decoding_backend_init__libvorbis, - ma_decoding_backend_init_file__libvorbis, - NULL, /* onInitFileW() */ - NULL, /* onInitMemory() */ - ma_decoding_backend_uninit__libvorbis -}; -#pragma endregion - enum class EmbeddedSound { SysWorldMapCursor, @@ -101,12 +25,10 @@ enum class EmbeddedSound struct EmbeddedSoundData { static const int SimultaneousLimit = 4; - std::array, SimultaneousLimit> sounds; - std::array, SimultaneousLimit> decoders; - int oldestIndex = 0; + Mix_Chunk* chunk{}; + int channelIndex{}; }; -static ma_engine g_audioEngine = {}; static std::array g_embeddedSoundData = {}; static const std::unordered_map g_embeddedSoundMap = { @@ -122,111 +44,56 @@ static const std::unordered_map g_embeddedSound static void PlayEmbeddedSound(EmbeddedSound s) { EmbeddedSoundData &data = g_embeddedSoundData[size_t(s)]; - int pickedIndex = -1; - for (int i = 0; (i < EmbeddedSoundData::SimultaneousLimit) && (pickedIndex < 0); i++) + if (data.chunk == nullptr) { - if (data.sounds[i] == nullptr) + // The sound hasn't been created yet, create it and pick it. + const void *soundData = nullptr; + size_t soundDataSize = 0; + switch (s) { - // The sound hasn't been created yet, create it and pick it. - const void *soundData = nullptr; - size_t soundDataSize = 0; - switch (s) - { - case EmbeddedSound::SysWorldMapCursor: - soundData = g_sys_worldmap_cursor; - soundDataSize = sizeof(g_sys_worldmap_cursor); - break; - case EmbeddedSound::SysWorldMapFinalDecide: - soundData = g_sys_worldmap_finaldecide; - soundDataSize = sizeof(g_sys_worldmap_finaldecide); - break; - case EmbeddedSound::SysActStgPauseCansel: - soundData = g_sys_actstg_pausecansel; - soundDataSize = sizeof(g_sys_actstg_pausecansel); - break; - case EmbeddedSound::SysActStgPauseCursor: - soundData = g_sys_actstg_pausecursor; - soundDataSize = sizeof(g_sys_actstg_pausecursor); - break; - case EmbeddedSound::SysActStgPauseDecide: - soundData = g_sys_actstg_pausedecide; - soundDataSize = sizeof(g_sys_actstg_pausedecide); - break; - case EmbeddedSound::SysActStgPauseWinClose: - soundData = g_sys_actstg_pausewinclose; - soundDataSize = sizeof(g_sys_actstg_pausewinclose); - break; - case EmbeddedSound::SysActStgPauseWinOpen: - soundData = g_sys_actstg_pausewinopen; - soundDataSize = sizeof(g_sys_actstg_pausewinopen); - break; - default: - assert(false && "Unknown embedded sound."); - return; - } - - ma_decoding_backend_vtable* pCustomBackendVTables[] = - { - &g_ma_decoding_backend_vtable_libvorbis - }; - - ma_decoder_config decoderConfig = ma_decoder_config_init_default(); - decoderConfig.pCustomBackendUserData = NULL; - decoderConfig.ppCustomBackendVTables = pCustomBackendVTables; - decoderConfig.customBackendCount = std::size(pCustomBackendVTables); - - ma_result res; - data.decoders[i] = std::make_unique(); - res = ma_decoder_init_memory(soundData, soundDataSize, &decoderConfig, data.decoders[i].get()); - if (res != MA_SUCCESS) - { - fprintf(stderr, "ma_decoder_init_memory failed with error code %d.\n", res); - return; - } - - data.sounds[i] = std::make_unique(); - res = ma_sound_init_from_data_source(&g_audioEngine, data.decoders[i].get(), MA_SOUND_FLAG_DECODE, nullptr, data.sounds[i].get()); - if (res != MA_SUCCESS) - { - fprintf(stderr, "ma_sound_init_from_data_source failed with error code %d.\n", res); - return; - } - - pickedIndex = i; - } - else if (ma_sound_at_end(data.sounds[i].get())) - { - // A sound has reached the end, pick it. - pickedIndex = i; + case EmbeddedSound::SysWorldMapCursor: + soundData = g_sys_worldmap_cursor; + soundDataSize = sizeof(g_sys_worldmap_cursor); + break; + case EmbeddedSound::SysWorldMapFinalDecide: + soundData = g_sys_worldmap_finaldecide; + soundDataSize = sizeof(g_sys_worldmap_finaldecide); + break; + case EmbeddedSound::SysActStgPauseCansel: + soundData = g_sys_actstg_pausecansel; + soundDataSize = sizeof(g_sys_actstg_pausecansel); + break; + case EmbeddedSound::SysActStgPauseCursor: + soundData = g_sys_actstg_pausecursor; + soundDataSize = sizeof(g_sys_actstg_pausecursor); + break; + case EmbeddedSound::SysActStgPauseDecide: + soundData = g_sys_actstg_pausedecide; + soundDataSize = sizeof(g_sys_actstg_pausedecide); + break; + case EmbeddedSound::SysActStgPauseWinClose: + soundData = g_sys_actstg_pausewinclose; + soundDataSize = sizeof(g_sys_actstg_pausewinclose); + break; + case EmbeddedSound::SysActStgPauseWinOpen: + soundData = g_sys_actstg_pausewinopen; + soundDataSize = sizeof(g_sys_actstg_pausewinopen); + break; + default: + assert(false && "Unknown embedded sound."); + return; } + + data.chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(soundData, soundDataSize), 1); } - if (pickedIndex < 0) - { - // No free slots are available, pick the oldest one. - pickedIndex = data.oldestIndex; - data.oldestIndex = (data.oldestIndex + 1) % EmbeddedSoundData::SimultaneousLimit; - } - - if (data.sounds[pickedIndex] != nullptr) - { - ma_sound_set_volume(data.sounds[pickedIndex].get(), Config::EffectsVolume); - ma_sound_seek_to_pcm_frame(data.sounds[pickedIndex].get(), 0); - ma_sound_start(data.sounds[pickedIndex].get()); - } + Mix_PlayChannel(data.channelIndex % EmbeddedSoundData::SimultaneousLimit, data.chunk, 0); + ++data.channelIndex; } void EmbeddedPlayer::Init() { - ma_engine_config engineConfig = ma_engine_config_init(); - engineConfig.channels = XAUDIO_NUM_CHANNELS; - engineConfig.sampleRate = XAUDIO_SAMPLES_HZ; - - ma_result res = ma_engine_init(&engineConfig, &g_audioEngine); - if (res != MA_SUCCESS) - { - fprintf(stderr, "ma_engine_init failed with error code %d.\n", res); - } + Mix_OpenAudio(XAUDIO_SAMPLES_HZ, AUDIO_F32SYS, XAUDIO_NUM_CHANNELS, 256); s_isActive = true; } @@ -241,11 +108,6 @@ void EmbeddedPlayer::Play(const char *name) return; } - if (g_audioEngine.pDevice == nullptr) - { - return; - } - PlayEmbeddedSound(it->second); } @@ -253,37 +115,12 @@ void EmbeddedPlayer::Shutdown() { for (EmbeddedSoundData &data : g_embeddedSoundData) { - for (auto &sound : data.sounds) - { - if (sound != nullptr) - { - if (sound->pDataSource != nullptr) - { - ma_sound_uninit(sound.get()); - } - - sound.reset(); - } - } - - for (auto &decoder : data.decoders) - { - if (decoder != nullptr) - { - if (decoder->pBackend != nullptr) - { - ma_decoder_uninit(decoder.get()); - } - - decoder.reset(); - } - } + if (data.chunk != nullptr) + Mix_FreeChunk(data.chunk); } - if (g_audioEngine.pDevice != nullptr) - { - ma_engine_uninit(&g_audioEngine); - } + Mix_CloseAudio(); + Mix_Quit(); s_isActive = false; } diff --git a/UnleashedRecomp/cpu/guest_thread.cpp b/UnleashedRecomp/cpu/guest_thread.cpp index 32412b40..290fc51c 100644 --- a/UnleashedRecomp/cpu/guest_thread.cpp +++ b/UnleashedRecomp/cpu/guest_thread.cpp @@ -32,6 +32,7 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber) 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.r13.u64 = g_memory.MapVirtual(thread); + ppcContext.fpscr.loadFromHost(); assert(GetPPCContext() == nullptr); SetPPCContext(ppcContext); @@ -77,7 +78,7 @@ uint32_t GuestThread::Start(const GuestThreadParams& params) GuestThreadContext ctx(cpuNumber); ctx.ppcContext.r3.u64 = params.value; - GuestCode::Run(g_codeCache.Find(params.function), &ctx.ppcContext, g_memory.Translate(0)); + reinterpret_cast(g_codeCache.Find(params.function))(ctx.ppcContext, reinterpret_cast(g_memory.base)); return ctx.ppcContext.r3.u32; } diff --git a/UnleashedRecomp/kernel/imports.cpp b/UnleashedRecomp/kernel/imports.cpp index d350b318..cffd6136 100644 --- a/UnleashedRecomp/kernel/imports.cpp +++ b/UnleashedRecomp/kernel/imports.cpp @@ -76,16 +76,16 @@ static std::atomic g_keSetEventGeneration; struct Semaphore final : KernelObject, HostObject { - std::atomic count; + std::counting_semaphore<> semaphore; uint32_t maximumCount; Semaphore(XKSEMAPHORE* semaphore) - : count(semaphore->Header.SignalState), maximumCount(semaphore->Limit) + : semaphore(semaphore->Header.SignalState), maximumCount(semaphore->Limit) { } Semaphore(uint32_t count, uint32_t maximumCount) - : count(count), maximumCount(maximumCount) + : semaphore(count), maximumCount(maximumCount) { } @@ -93,32 +93,11 @@ struct Semaphore final : KernelObject, HostObject { if (timeout == 0) { - uint32_t currentCount = count.load(); - if (currentCount != 0) - { - if (count.compare_exchange_weak(currentCount, currentCount - 1)) - return STATUS_SUCCESS; - } - - return STATUS_TIMEOUT; + return semaphore.try_acquire() ? STATUS_SUCCESS : STATUS_TIMEOUT; } else if (timeout == INFINITE) { - uint32_t currentCount; - while (true) - { - currentCount = count.load(); - if (currentCount != 0) - { - if (count.compare_exchange_weak(currentCount, currentCount - 1)) - return STATUS_SUCCESS; - } - else - { - count.wait(0); - } - } - + semaphore.acquire(); return STATUS_SUCCESS; } else @@ -130,13 +109,7 @@ struct Semaphore final : KernelObject, HostObject void Release(uint32_t releaseCount, uint32_t* previousCount) { - if (previousCount != nullptr) - *previousCount = count; - - assert(count + releaseCount <= maximumCount); - - count += releaseCount; - count.notify_all(); + semaphore.release(releaseCount); } }; @@ -546,7 +519,13 @@ uint32_t KeDelayExecutionThread(uint32_t WaitMode, bool Alertable, be* if (Alertable) return STATUS_USER_APC; - std::this_thread::sleep_for(std::chrono::milliseconds(GuestTimeoutToMilliseconds(Timeout))); + uint32_t timeout = GuestTimeoutToMilliseconds(Timeout); + +#ifdef _WIN32 + Sleep(timeout); +#else + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); +#endif return STATUS_SUCCESS; } diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index 47fae078..2387886e 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -137,6 +137,10 @@ uint32_t LdrLoadModule(const std::filesystem::path &path) int main(int argc, char *argv[]) { +#ifdef _WIN32 + timeBeginPeriod(1); +#endif + os::logger::Init(); bool forceInstaller = false; diff --git a/UnleashedRecomp/stdafx.cpp b/UnleashedRecomp/stdafx.cpp index 90aaf593..7a2e063c 100644 --- a/UnleashedRecomp/stdafx.cpp +++ b/UnleashedRecomp/stdafx.cpp @@ -1,10 +1,4 @@ #define STB_IMAGE_IMPLEMENTATION #include -#define MINIAUDIO_IMPLEMENTATION -#include - -#define ma_offset_pcm_frames_ptr (char*)ma_offset_pcm_frames_ptr -#include - #include "stdafx.h" diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index a0b541ca..929f0f58 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -36,6 +36,7 @@ using Microsoft::WRL::ComPtr; #include #include #include +#include #include #include #include @@ -43,10 +44,9 @@ using Microsoft::WRL::ComPtr; #include #include #include -#include -#include #include #include +#include #include "framework.h" #include "mutex.h" diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 28f000da..4ace5405 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,11 +1,22 @@ +cmake_policy(SET CMP0077 NEW) + set(MSDF_ATLAS_BUILD_STANDALONE OFF) set(MSDF_ATLAS_USE_SKIA OFF) set(MSDF_ATLAS_NO_ARTERY_FONT ON) set(MSDFGEN_DISABLE_PNG ON) +set(SDL2MIXER_DEPS_SHARED OFF) +set(SDL2MIXER_VENDORED ON) +set(SDL2MIXER_FLAC OFF) +set(SDL2MIXER_MOD OFF) +set(SDL2MIXER_MP3 OFF) +set(SDL2MIXER_MIDI OFF) +set(SDL2MIXER_OPUS OFF) +set(SDL2MIXER_VORBIS "VORBISFILE") +set(SDL2MIXER_WAVPACK OFF) + add_subdirectory("${SWA_THIRDPARTY_ROOT}/msdf-atlas-gen") add_subdirectory("${SWA_THIRDPARTY_ROOT}/nativefiledialog-extended") -add_subdirectory("${SWA_THIRDPARTY_ROOT}/ogg") add_subdirectory("${SWA_THIRDPARTY_ROOT}/o1heap") add_subdirectory("${SWA_THIRDPARTY_ROOT}/SDL") -add_subdirectory("${SWA_THIRDPARTY_ROOT}/vorbis") +add_subdirectory("${SWA_THIRDPARTY_ROOT}/SDL_mixer") diff --git a/thirdparty/SDL_mixer b/thirdparty/SDL_mixer new file mode 160000 index 00000000..43799269 --- /dev/null +++ b/thirdparty/SDL_mixer @@ -0,0 +1 @@ +Subproject commit 437992692cf9300f2b2f04be35adc7445a9055bf diff --git a/thirdparty/miniaudio b/thirdparty/miniaudio deleted file mode 160000 index 12a8d4e4..00000000 --- a/thirdparty/miniaudio +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 12a8d4e4911c5ab4f4c089b4d039433975ed8a66 diff --git a/thirdparty/ogg b/thirdparty/ogg deleted file mode 160000 index 7cf42ea1..00000000 --- a/thirdparty/ogg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7cf42ea17aef7bc1b7b21af70724840a96c2e7d0 diff --git a/thirdparty/vorbis b/thirdparty/vorbis deleted file mode 160000 index 84c02369..00000000 --- a/thirdparty/vorbis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 84c023699cdf023a32fa4ded32019f194afcdad0