From cb2410d9c5920a882f01b6ea4a4736e37438d2ad Mon Sep 17 00:00:00 2001 From: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> Date: Wed, 3 Aug 2022 02:30:39 +0200 Subject: [PATCH] Handle audio thread properly --- .../libultraship/Lib/Fast3D/gfx_dxgi.cpp | 6 +- .../libultraship/Lib/Fast3D/gfx_sdl2.cpp | 7 +- soh/soh/OTRAudio.h | 3 +- soh/soh/OTRGlobals.cpp | 114 ++++++++++-------- soh/src/code/graph.c | 16 --- soh/src/code/main.c | 4 +- 6 files changed, 79 insertions(+), 71 deletions(-) diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp index c80dc4be5..3e81f56fa 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp @@ -239,8 +239,8 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par dxgi.current_height = (uint32_t)(l_param >> 16); break; case WM_DESTROY: - Ship::ExecuteHooks(); - exit(0); + PostQuitMessage(0); + break; case WM_PAINT: if (dxgi.in_paint) { dxgi.recursive_paint_detected = true; @@ -378,6 +378,8 @@ static void gfx_dxgi_main_loop(void (*run_one_game_iter)(void)) { TranslateMessage(&msg); DispatchMessage(&msg); } + + Ship::ExecuteHooks(); } static void gfx_dxgi_get_dimensions(uint32_t *width, uint32_t *height) { diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index 8600aae1f..23cff4698 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -238,6 +238,8 @@ static void gfx_sdl_main_loop(void (*run_one_game_iter)(void)) { Ship::Switch::Exit(); #endif Ship::ExecuteHooks(); + + SDL_Quit(); } static void gfx_sdl_get_dimensions(uint32_t *width, uint32_t *height) { @@ -307,9 +309,8 @@ static void gfx_sdl_handle_events(void) { CVar_Save(); break; case SDL_QUIT: - Ship::ExecuteHooks(); - SDL_Quit(); // bandaid fix for linux window closing issue - exit(0); + is_running = false; + break; } } } diff --git a/soh/soh/OTRAudio.h b/soh/soh/OTRAudio.h index ee0ec46a2..a452fdb29 100644 --- a/soh/soh/OTRAudio.h +++ b/soh/soh/OTRAudio.h @@ -1,8 +1,9 @@ #pragma once static struct { + std::thread thread; std::condition_variable cv_to_thread, cv_from_thread; std::mutex mutex; - bool initialized; + bool running; bool processing; } audio; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 17843ac45..48ecceb07 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -83,11 +83,73 @@ extern "C" void ResourceMgr_CacheDirectory(const char* resName); extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path); std::unordered_map ExtensionCache; +void OTRAudio_Thread() { + while (audio.running) { + { + std::unique_lock Lock(audio.mutex); + while (!audio.processing && audio.running) { + audio.cv_to_thread.wait(Lock); + } + + if (!audio.running) { + break; + } + } + std::unique_lock Lock(audio.mutex); + //AudioMgr_ThreadEntry(&gAudioMgr); + // 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333.. + // in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528 + //#define SAMPLES_HIGH 560 + //#define SAMPLES_LOW 528 + // PAL values + //#define SAMPLES_HIGH 656 + //#define SAMPLES_LOW 624 + + // 44KHZ values + #define SAMPLES_HIGH 752 + #define SAMPLES_LOW 720 + + #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) + #define NUM_AUDIO_CHANNELS 2 + + int samples_left = AudioPlayer_Buffered(); + u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; + + // 3 is the maximum authentic frame divisor. + s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; + for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { + AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); + } + + AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); + + audio.processing = false; + audio.cv_from_thread.notify_one(); + } +} + // C->C++ Bridge extern "C" void OTRAudio_Init() { // Precache all our samples, sequences, etc... ResourceMgr_CacheDirectory("audio"); + + if (!audio.running) { + audio.running = true; + audio.thread = std::thread(OTRAudio_Thread); + } +} + +extern "C" void OTRAudio_Exit() { + // Tell the audio thread to stop + { + std::unique_lock Lock(audio.mutex); + audio.running = false; + } + audio.cv_to_thread.notify_all(); + + // Wait until the audio thread quit + audio.thread.join(); } extern "C" void OTRExtScanner() { @@ -128,6 +190,10 @@ extern "C" void InitOTR() { OTRExtScanner(); } +extern "C" void DeinitOTR() { + OTRAudio_Exit(); +} + #ifdef _WIN32 extern "C" uint64_t GetFrequency() { LARGE_INTEGER nFreq; @@ -227,56 +293,10 @@ extern "C" void Graph_StartFrame() { // C->C++ Bridge extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { -#ifndef __SWITCH__ - if (!audio.initialized) { - audio.initialized = true; - std::thread([]() { - for (;;) { - { - std::unique_lock Lock(audio.mutex); - while (!audio.processing) { - audio.cv_to_thread.wait(Lock); - } - } - std::unique_lock Lock(audio.mutex); - //AudioMgr_ThreadEntry(&gAudioMgr); - // 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333.. - // in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528 - //#define SAMPLES_HIGH 560 - //#define SAMPLES_LOW 528 - // PAL values - //#define SAMPLES_HIGH 656 - //#define SAMPLES_LOW 624 - - // 44KHZ values - #define SAMPLES_HIGH 752 - #define SAMPLES_LOW 720 - - #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) - #define NUM_AUDIO_CHANNELS 2 - - int samples_left = AudioPlayer_Buffered(); - u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; - - // 3 is the maximum authentic frame divisor. - s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; - for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { - AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); - } - - AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); - - audio.processing = false; - audio.cv_from_thread.notify_one(); - } - }).detach(); - } - { std::unique_lock Lock(audio.mutex); audio.processing = true; } -#endif audio.cv_to_thread.notify_one(); std::vector> mtx_replacements; @@ -319,14 +339,12 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { last_fps = fps; last_update_rate = R_UPDATE_RATE; -#ifndef __SWITCH__ { std::unique_lock Lock(audio.mutex); while (audio.processing) { audio.cv_from_thread.wait(Lock); } } -#endif // OTRTODO: FIGURE OUT END FRAME POINT /* if (OTRGlobals::Instance->context->GetWindow()->lastScancode != -1) diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c index cf0a53c76..f4dcf56e8 100644 --- a/soh/src/code/graph.c +++ b/soh/src/code/graph.c @@ -481,22 +481,6 @@ static void RunFrame() uint64_t ticksA, ticksB; ticksA = GetPerfCounter(); -#ifdef __SWITCH__ - #define SAMPLES_HIGH 752 - #define SAMPLES_LOW 720 - - #define AUDIO_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1 ) - #define NUM_AUDIO_CHANNELS 2 - int samples_left = AudioPlayer_Buffered(); - u32 num_audio_samples = samples_left < AudioPlayer_GetDesiredBuffered() ? SAMPLES_HIGH : SAMPLES_LOW; - - s16 audio_buffer[SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 3]; - for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) { - AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); - } - - AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE)); -#endif Graph_StartFrame(); // TODO: Workaround for rumble being too long. Implement os thread functions. diff --git a/soh/src/code/main.c b/soh/src/code/main.c index fd02b016a..ccfdc2019 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -36,12 +36,14 @@ void Main_LogSystemHeap(void) { osSyncPrintf(VT_RST); } -void main(int argc, char** argv) +int main(int argc, char** argv) { GameConsole_Init(); InitOTR(); BootCommands_Init(); Main(0); + DeinitOTR(); + return 0; } void Main(void* arg) {