From 7015cbef54e8db19d44d6755b73059f494101170 Mon Sep 17 00:00:00 2001 From: Caturria Date: Fri, 25 Aug 2023 14:38:41 -0400 Subject: [PATCH 1/4] Unhook accessibility integration completely (will reintegrate via game-interactor). --- soh/soh/OTRGlobals.cpp | 53 +++--------------------------------- soh/soh/OTRGlobals.h | 5 ---- soh/src/code/code_800F9280.c | 2 -- soh/src/code/main.c | 5 ++-- soh/src/code/z_play.c | 11 -------- 5 files changed, 6 insertions(+), 70 deletions(-) diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index ff42aad3b..6c7d5eec5 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -112,7 +112,7 @@ CrowdControl* CrowdControl::Instance; #include "soh/resource/importer/BackgroundFactory.h" #include "soh/config/ConfigUpdaters.h" -#include "soh/Enhancements/accessible-actors/ActorAccessibility.h" + OTRGlobals* OTRGlobals::Instance; SaveManager* SaveManager::Instance; CustomMessageManager* CustomMessageManager::Instance; @@ -230,11 +230,6 @@ OTRGlobals::OTRGlobals() { } } } - std::string sohAccessibilityPath = LUS::Context::GetPathRelativeToAppDirectory("accessibility.otr"); - if (std::filesystem::exists(sohAccessibilityPath)) { - OTRFiles.push_back(sohAccessibilityPath); - } - std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, @@ -400,13 +395,9 @@ void OTRAudio_Thread() { // 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); - // Give accessibility a chance to merge its own audio in. - ActorAccessibility_MixAccessibleAudioWithGameAudio( - audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), num_audio_samples); - + 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; @@ -1026,7 +1017,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { last_update_rate = R_UPDATE_RATE; { - std::unique_lock Lock(audio.mutex); + std::unique_lock Lock(audio.mutex); while (audio.processing) { audio.cv_from_thread.wait(Lock); } @@ -2199,39 +2190,3 @@ extern "C" void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex) { extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement) { gfx_register_blended_texture(name, mask, replacement); } - -void OTRAudio_SfxCaptureThread() { - 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); - ActorAccessibility_DoSoundExtractionStep(); - audio.processing = false; - audio.cv_from_thread.notify_one(); - } -} - - extern "C" void OTRAudio_InstallSfxCaptureThread() { - OTRAudio_Exit(); - audio.running = true; - audio.thread = std::thread(OTRAudio_SfxCaptureThread); - - } - extern "C" void OTRAudio_UninstallSfxCaptureThread() - { - OTRAudio_Exit(); - audio.running = true; - audio.thread = std::thread(OTRAudio_Thread); - } - std::unique_lock OTRAudio_Lock() - { - return std::unique_lock(audio.mutex); - } \ No newline at end of file diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 86b7fec7f..29d4a3f84 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -156,19 +156,14 @@ void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); void SaveManager_ThreadPoolWait(); int32_t GetGIID(uint32_t itemID); - #endif #ifdef __cplusplus extern "C" { #endif uint64_t GetUnixTimestamp(); -void OTRAudio_InstallSfxCaptureThread(); -void OTRAudio_UninstallSfxCaptureThread(); #ifdef __cplusplus }; -std::unique_lock OTRAudio_Lock(); - #endif #endif diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index bd64aec2b..4b519dc77 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -371,8 +371,6 @@ extern f32 D_80130F28; void Audio_QueueSeqCmd(u32 cmd) { - if (CVarGetInteger("gExtractSfx", 0)) - return; u8 op = cmd >> 28; if (op == 0 || op == 2 || op == 12) { u8 seqId = cmd & 0xFF; diff --git a/soh/src/code/main.c b/soh/src/code/main.c index 3fff1bbf4..b59a825c1 100644 --- a/soh/src/code/main.c +++ b/soh/src/code/main.c @@ -10,7 +10,7 @@ #include #include "soh/CrashHandlerExp.h" -#include + s32 gScreenWidth = SCREEN_WIDTH; s32 gScreenHeight = SCREEN_HEIGHT; size_t gSystemHeapSize = 0; @@ -60,14 +60,13 @@ int main(int argc, char** argv) #endif GameConsole_Init(); - ActorAccessibility_Init();//Needs to happen before OTR. InitOTR(); // TODO: Was moved to below InitOTR because it requires window to be setup. But will be late to catch crashes. CrashHandlerRegisterCallback(CrashHandler_PrintSohData); BootCommands_Init(); + Main(0); DeinitOTR(); - ActorAccessibility_Shutdown(); return 0; } diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index fb4131af6..beef71e9c 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -753,17 +753,6 @@ void Play_Update(PlayState* play) { Input* input; u32 i; s32 pad2; - //Support locking down the game on the title screen for the purposes of SFX extraction. Be careful to avoid checking CVars every frame. - static int sfxExtractionMode = -1; - if (play->sceneNum == 81) // Title screen. - { - if (sfxExtractionMode != 0) - sfxExtractionMode = CVarGetInteger("gExtractSfx", 0); - if (sfxExtractionMode == 1) { - ActorAccessibility_HandleSoundExtractionMode(play); - return; - } - } input = play->state.input; From 70da2c97639f8f1eec5cb904166bfbad84dc17cd Mon Sep 17 00:00:00 2001 From: Caturria Date: Fri, 25 Aug 2023 14:40:10 -0400 Subject: [PATCH 2/4] One file was forgotten. --- soh/src/code/z_actor.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index b0cc159a8..796fc6d71 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -77,7 +77,7 @@ #include "textures/place_title_cards/g_pn_56.h" #include "textures/place_title_cards/g_pn_57.h" #endif -#include + static CollisionPoly* sCurCeilingPoly; static s32 sCurCeilingBgId; @@ -2613,8 +2613,6 @@ void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { func_8002C7BC(&actorCtx->targetCtx, player, actor, play); TitleCard_Update(play, &actorCtx->titleCtx); DynaPoly_UpdateBgActorTransforms(play, &play->colCtx.dyna); - ActorAccessibility_RunAccessibilityForAllActors(play); - } void Actor_FaultPrint(Actor* actor, char* command) { @@ -3215,7 +3213,6 @@ Actor* Actor_Spawn(ActorContext* actorCtx, PlayState* play, s16 actorId, f32 pos temp = gSegments[6]; Actor_Init(actor, play); gSegments[6] = temp; - ActorAccessibility_TrackNewActor(actor); return actor; } @@ -3324,9 +3321,7 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) { dbEntry->numLoaded--; Actor_FreeOverlay(dbEntry); -ActorAccessibility_RemoveTrackedActor(actor); - - return newHead; + return newHead; } s32 func_80032880(PlayState* play, Actor* actor) { From 1a07a3e810027d2396e622a42a21b68f45e0db30 Mon Sep 17 00:00:00 2001 From: Caturria Date: Fri, 25 Aug 2023 22:21:31 -0400 Subject: [PATCH 3/4] Reintegrate accessibility using game-interactor. --- .../accessible-actors/ActorAccessibility.cpp | 54 +++++++++++++++--- .../accessible-actors/SfxExtractor.cpp | 11 +++- .../accessible-actors/SfxExtractor.h | 2 + .../game-interactor/GameInteractor.h | 3 + .../game-interactor/GameInteractor_Hooks.cpp | 9 ++- .../game-interactor/GameInteractor_Hooks.h | 4 ++ soh/soh/OTRGlobals.cpp | 57 +++++++++++++++++-- soh/soh/OTRGlobals.h | 5 ++ soh/src/code/code_800F9280.c | 4 ++ soh/src/code/z_actor.c | 2 + soh/src/code/z_play.c | 7 ++- 11 files changed, 140 insertions(+), 18 deletions(-) diff --git a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp index d1745e84b..66bbaa15a 100644 --- a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp +++ b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp @@ -16,6 +16,11 @@ #include #include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h" #include "soh/Enhancements/tts/tts.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +extern "C" { +extern PlayState* gPlayState; +extern bool freezeGame; +} const char* GetLanguageCode(); @@ -50,7 +55,7 @@ typedef struct { class ActorAccessibility { public: bool isOn = false; - uint64_t nextActorID; + uint64_t nextActorID = 0; SupportedActors_t supportedActors; TrackedActors_t trackedActors; AccessibleActorList_t accessibleActorList; @@ -59,7 +64,7 @@ class ActorAccessibility { AccessibleAudioEngine* audioEngine; SfxExtractor sfxExtractor; std::unordered_map sfxMap;//Maps internal sfx to external (prerendered) resources. - + int extractSfx = 0; }; static ActorAccessibility* aa; @@ -68,12 +73,45 @@ uint64_t ActorAccessibility_GetNextID() { aa->nextActorID++; return result; } -void ActorAccessibility_Init() { - aa = new ActorAccessibility(); - ActorAccessibility_InitAudio(); - ActorAccessibility_InitActors(); + +// Hooks for game-interactor. +void ActorAccessibility_OnActorInit(void* actor) { + ActorAccessibility_TrackNewActor((Actor*)actor); +} +void ActorAccessibility_OnGameFrameUpdate() { + if (gPlayState == NULL) + return; + + ActorAccessibility_RunAccessibilityForAllActors(gPlayState); +} +void ActorAccessibility_OnActorDestroy(void* actor) +{ + ActorAccessibility_RemoveTrackedActor((Actor*) actor); } +void ActorAccessibility_OnGameStillFrozen() +{ + if (gPlayState == NULL) + return; + if (aa->extractSfx) + ActorAccessibility_HandleSoundExtractionMode(gPlayState); + +} + void ActorAccessibility_Init() { + + aa = new ActorAccessibility(); + aa->extractSfx = CVarGetInteger("gExtractSfx", 0); + if (aa->extractSfx) + freezeGame = true; + ActorAccessibility_InitAudio(); + ActorAccessibility_InitActors(); + GameInteractor::Instance->RegisterGameHook(ActorAccessibility_OnActorInit); + GameInteractor::Instance->RegisterGameHook(ActorAccessibility_OnActorDestroy); + + GameInteractor::Instance->RegisterGameHook(ActorAccessibility_OnGameFrameUpdate); + GameInteractor::Instance->RegisterGameHook(ActorAccessibility_OnGameStillFrozen); + + } void ActorAccessibility_Shutdown() { ActorAccessibility_ShutdownAudio(); delete aa; @@ -114,7 +152,7 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) { } -void ActorAccessibility_TrackNewActor(Actor* actor) { + void ActorAccessibility_TrackNewActor(Actor * actor) { // Don't track actors for which no accessibility policy has been configured. ActorAccessibilityPolicy* policy = ActorAccessibility_GetPolicyForActor(actor->id); if (policy == NULL) @@ -525,5 +563,3 @@ return NULL;//Resource doesn't exist, user's gotta run the extractor. } - - \ No newline at end of file diff --git a/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp b/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp index b2c5df51a..5fcb1067d 100644 --- a/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp +++ b/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp @@ -14,9 +14,10 @@ extern f32 D_801333E0; extern s8 D_801333E8; extern u8 D_801333F0; void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); +extern bool freezeGame; } enum { - STEP_SETUP, + STEP_SETUP = 0, STEP_MAIN, STEP_FINISHED, STEP_ERROR, @@ -92,6 +93,9 @@ void SfxExtractor::renderOutput() { } void SfxExtractor::setup() { try { + ogMusicVolume = CVarGetFloat("gMainMusicVolume", 1.0); + CVarSetFloat("gMainMusicVolume", 0.0); + SpeechSynthesizer::Instance->Speak("Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode()); // Kill the audio thread so we can take control. captureThreadState = CT_WAITING; @@ -167,6 +171,8 @@ void SfxExtractor::finished() { SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode()); } else Audio_PlayFanfare(NA_BGM_ITEM_GET); + freezeGame = false; + } void SfxExtractor::maybeGiveProgressReport() { size_t ripsRemaining = sfxToRip.size() + 1; @@ -182,7 +188,8 @@ void SfxExtractor::maybeGiveProgressReport() { SfxExtractor::SfxExtractor() { currentStep = STEP_SETUP; } -void SfxExtractor::frameCallback() { + + void SfxExtractor::frameCallback() { switch (currentStep) { case STEP_SETUP: setup(); diff --git a/soh/soh/Enhancements/accessible-actors/SfxExtractor.h b/soh/soh/Enhancements/accessible-actors/SfxExtractor.h index da8312831..28703f2a7 100644 --- a/soh/soh/Enhancements/accessible-actors/SfxExtractor.h +++ b/soh/soh/Enhancements/accessible-actors/SfxExtractor.h @@ -10,6 +10,7 @@ class SfxExtractor { s16 currentSfx; std::vector tempStorage; // Stores raw audio data for the sfx currently being ripped. int16_t* tempBuffer; // Raw pointer to the above vector. + f32 ogMusicVolume; int progressMilestones[9]; // Implements progress reports after every 10 percent. // Check if a buffer contains meaningful audio output. bool isAllZero(int16_t* buffer, size_t count); @@ -23,6 +24,7 @@ class SfxExtractor { void maybeGiveProgressReport(); public: SfxExtractor(); + void frameCallback(); void prime(); // The below is called by the (hijacked) audio thread. diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 79a2cb465..a353f42d2 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -153,6 +153,8 @@ public: DEFINE_HOOK(OnOcarinaSongAction, void()); DEFINE_HOOK(OnActorInit, void(void* actor)); DEFINE_HOOK(OnActorUpdate, void(void* actor)); + DEFINE_HOOK(OnActorDestroy, void(void* actor)); + DEFINE_HOOK(OnPlayerBonk, void()); DEFINE_HOOK(OnPlayDestroy, void()); DEFINE_HOOK(OnPlayDrawEnd, void()); @@ -180,6 +182,7 @@ public: DEFINE_HOOK(OnUpdateFileNameSelection, void(int16_t charCode)); DEFINE_HOOK(OnSetGameLanguage, void()); + DEFINE_HOOK(OnGameStillFrozen, void()); // Helpers static bool IsSaveLoaded(); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index e96474996..14de569cd 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -49,8 +49,11 @@ void GameInteractor_ExecuteOnActorInit(void* actor) { void GameInteractor_ExecuteOnActorUpdate(void* actor) { GameInteractor::Instance->ExecuteHooks(actor); } +void GameInteractor_ExecuteOnActorDestroy(void* actor) { + GameInteractor::Instance->ExecuteHooks(actor); +} -void GameInteractor_ExecuteOnPlayerBonk() { + void GameInteractor_ExecuteOnPlayerBonk() { GameInteractor::Instance->ExecuteHooks(); } @@ -149,3 +152,7 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode) { void GameInteractor_ExecuteOnSetGameLanguage() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnGameStillFrozen() +{ + GameInteractor::Instance->ExecuteHooks(); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index c69a8ec24..563c88ed8 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -15,7 +15,10 @@ void GameInteractor_ExecuteOnSceneSpawnActors(); void GameInteractor_ExecuteOnPlayerUpdate(); void GameInteractor_ExecuteOnOcarinaSongAction(); void GameInteractor_ExecuteOnActorInit(void* actor); +void GameInteractor_ExecuteOnActorInit(void* actor); void GameInteractor_ExecuteOnActorUpdate(void* actor); +void GameInteractor_ExecuteOnActorDestroy(void* actor); + void GameInteractor_ExecuteOnPlayerBonk(); void GameInteractor_ExecuteOnOcarinaSongAction(); void GameInteractor_ExecuteOnPlayDestroy(); @@ -48,6 +51,7 @@ void GameInteractor_ExecuteOnUpdateFileNameSelection(int16_t charCode); // MARK: - Game void GameInteractor_ExecuteOnSetGameLanguage(); +void GameInteractor_ExecuteOnGameStillFrozen(); #ifdef __cplusplus } #endif diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 6c7d5eec5..a599cb41d 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -112,7 +112,8 @@ CrowdControl* CrowdControl::Instance; #include "soh/resource/importer/BackgroundFactory.h" #include "soh/config/ConfigUpdaters.h" - +#include "soh/Enhancements/accessible-actors/ActorAccessibility.h" +#include "Enhancements//accessible-actors/ActorAccessibility.h" OTRGlobals* OTRGlobals::Instance; SaveManager* SaveManager::Instance; CustomMessageManager* CustomMessageManager::Instance; @@ -230,6 +231,11 @@ OTRGlobals::OTRGlobals() { } } } + std::string sohAccessibilityPath = LUS::Context::GetPathRelativeToAppDirectory("accessibility.otr"); + if (std::filesystem::exists(sohAccessibilityPath)) { + OTRFiles.push_back(sohAccessibilityPath); + } + std::unordered_set ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, @@ -395,9 +401,13 @@ void OTRAudio_Thread() { // 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); - } + AudioMgr_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * NUM_AUDIO_CHANNELS), + num_audio_samples); + // Give accessibility a chance to merge its own audio in. + ActorAccessibility_MixAccessibleAudioWithGameAudio( + 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; @@ -774,6 +784,7 @@ extern "C" void InitOTR() { clearMtx = (uintptr_t)&gMtxClear; OTRMessage_Init(); + ActorAccessibility_Init(); OTRAudio_Init(); OTRExtScanner(); VanillaItemTable_Init(); @@ -817,7 +828,7 @@ extern "C" void DeinitOTR() { CrowdControl::Instance->Disable(); CrowdControl::Instance->Shutdown(); #endif - + ActorAccessibility_Shutdown(); // Destroying gui here because we have shared ptrs to LUS objects which output to SPDLOG which is destroyed before these shared ptrs. SohGui::Destroy(); @@ -1017,7 +1028,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { last_update_rate = R_UPDATE_RATE; { - std::unique_lock Lock(audio.mutex); + std::unique_lock Lock(audio.mutex); while (audio.processing) { audio.cv_from_thread.wait(Lock); } @@ -2190,3 +2201,39 @@ extern "C" void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex) { extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement) { gfx_register_blended_texture(name, mask, replacement); } + +void OTRAudio_SfxCaptureThread() { + 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); + ActorAccessibility_DoSoundExtractionStep(); + audio.processing = false; + audio.cv_from_thread.notify_one(); + } +} + + extern "C" void OTRAudio_InstallSfxCaptureThread() { + OTRAudio_Exit(); + audio.running = true; + audio.thread = std::thread(OTRAudio_SfxCaptureThread); + + } + extern "C" void OTRAudio_UninstallSfxCaptureThread() + { + OTRAudio_Exit(); + audio.running = true; + audio.thread = std::thread(OTRAudio_Thread); + } + std::unique_lock OTRAudio_Lock() + { + return std::unique_lock(audio.mutex); + } \ No newline at end of file diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 29d4a3f84..86b7fec7f 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -156,14 +156,19 @@ void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); void SaveManager_ThreadPoolWait(); int32_t GetGIID(uint32_t itemID); + #endif #ifdef __cplusplus extern "C" { #endif uint64_t GetUnixTimestamp(); +void OTRAudio_InstallSfxCaptureThread(); +void OTRAudio_UninstallSfxCaptureThread(); #ifdef __cplusplus }; +std::unique_lock OTRAudio_Lock(); + #endif #endif diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index 4b519dc77..91fc77c72 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -3,6 +3,7 @@ #include "soh/mixer.h" #include "soh/Enhancements/audio/AudioEditor.h" +extern bool freezeGame; typedef struct { u8 unk_0; @@ -371,6 +372,9 @@ extern f32 D_80130F28; void Audio_QueueSeqCmd(u32 cmd) { + if (freezeGame) + return;//No music during SFX rip. + u8 op = cmd >> 28; if (op == 0 || op == 2 || op == 12) { u8 seqId = cmd & 0xFF; diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 796fc6d71..742408422 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -1224,6 +1224,7 @@ void Actor_Init(Actor* actor, PlayState* play) { } void Actor_Destroy(Actor* actor, PlayState* play) { + GameInteractor_ExecuteOnActorDestroy(actor); if (actor->destroy != NULL) { actor->destroy(actor, play); actor->destroy = NULL; @@ -2476,6 +2477,7 @@ u32 D_80116068[ACTORCAT_MAX] = { }; void Actor_UpdateAll(PlayState* play, ActorContext* actorCtx) { + Actor* refActor; Actor* actor; Player* player; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index beef71e9c..e0b8143dd 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -16,7 +16,7 @@ #include #include - +bool freezeGame = false;//Used for SFX ripper. void* D_8012D1F0 = NULL; //UNK_TYPE D_8012D1F4 = 0; // unused Input* D_8012D1F8 = NULL; @@ -753,6 +753,11 @@ void Play_Update(PlayState* play) { Input* input; u32 i; s32 pad2; + if (freezeGame) { + GameInteractor_ExecuteOnGameStillFrozen(); + return; + } + input = play->state.input; From 56c6cc38488c3743a626d9ea3b7a17f4fdd53fb2 Mon Sep 17 00:00:00 2001 From: Caturria Date: Tue, 29 Aug 2023 00:03:28 -0400 Subject: [PATCH 4/4] Finish re-integration. Also support playback of raw samples as external sounds. --- .../accessible-actors/AccessibleActorList.cpp | 5 +- .../accessible-actors/ActorAccessibility.cpp | 91 ++++++++++++++++--- .../accessible-actors/ActorAccessibility.h | 5 + .../accessible-actors/SfxExtractor.cpp | 5 +- .../accessible-actors/SfxExtractor.h | 1 - 5 files changed, 89 insertions(+), 18 deletions(-) diff --git a/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp b/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp index 601a71feb..398bca94f 100644 --- a/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp +++ b/soh/soh/Enhancements/accessible-actors/AccessibleActorList.cpp @@ -296,7 +296,10 @@ void accessible_goma(AccessibleActor* actor) { } void accessible_door_of_time(AccessibleActor* actor) { - ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false); + ActorAccessibility_PlaySampleForActor(actor, 0, "Chanting", false); + ActorAccessibility_SetSoundPitch(actor, 0, 1.0); + + //ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false); } void accessible_sticks(AccessibleActor* actor) { diff --git a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp index 66bbaa15a..4b4e58a62 100644 --- a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp +++ b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.cpp @@ -17,6 +17,7 @@ #include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h" #include "soh/Enhancements/tts/tts.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/audio/AudioDecoder.h" extern "C" { extern PlayState* gPlayState; extern bool freezeGame; @@ -48,13 +49,15 @@ typedef std::map VAZones_t;//Maps room/ scene indices to their co typedef std::unordered_set SceneList_t;//A list of scenes which have already been visited (since the game was launched). Used to prevent re-creation of terrain VAs every time the player reloads a scene. typedef struct { - std::string hexName; + std::string path; std::shared_ptr resource; + std::shared_ptr decodedSample;//Set if the record is for a raw sample as opposed to a SFX. + }SfxRecord; class ActorAccessibility { public: - bool isOn = false; + int isOn = 0; uint64_t nextActorID = 0; SupportedActors_t supportedActors; TrackedActors_t trackedActors; @@ -64,6 +67,7 @@ class ActorAccessibility { AccessibleAudioEngine* audioEngine; SfxExtractor sfxExtractor; std::unordered_map sfxMap;//Maps internal sfx to external (prerendered) resources. + std::unordered_map sampleMap;//Similar to above, but this one maps raw audio samples as opposed to SFX. int extractSfx = 0; }; static ActorAccessibility* aa; @@ -100,6 +104,9 @@ void ActorAccessibility_OnGameStillFrozen() void ActorAccessibility_Init() { aa = new ActorAccessibility(); + aa->isOn = CVarGetInteger("gA11yAudioInteraction", 0); + if (!aa->isOn) + return; aa->extractSfx = CVarGetInteger("gExtractSfx", 0); if (aa->extractSfx) freezeGame = true; @@ -126,7 +133,7 @@ void ActorAccessibility_Shutdown() { policy->pitch = 1.5; policy->runsAlways = false; policy->sound = sfx; - policy->volume = 1.0; + policy->volume = 0.5; policy->initUserData = NULL; policy->cleanupUserData = NULL; policy->pitchModifier = 0.1; @@ -216,12 +223,23 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) { Audio_PlaySoundGeneral(sfxId, &actor->projectedPos, 4, &actor->currentPitch, &actor->currentVolume, &actor->currentReverb); } const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId); - void ActorAccessibility_PlaySound(void* handle, int slot, s16 sfxId, bool looping) { const char* path = ActorAccessibility_MapSfxToExternalAudio(sfxId); + if (path == NULL) + return; aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping); } + const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name); + + void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping) + { + const char* path = ActorAccessibility_MapRawSampleToExternalAudio(name); + if (path == NULL) + return; + aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping); + + } void ActorAccessibility_StopSound(void* handle, int slot) { aa->audioEngine->stopSound((uintptr_t) handle, slot); @@ -269,17 +287,29 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) { aa->audioEngine->seekSound((uintptr_t)handle, slot, offset); } + void ActorAccessibility_ConfigureSoundForActor(AccessibleActor* actor, int slot) + { + ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch); + ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier); + ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xyzDistToPlayer, + actor->policy.distance); + ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume); + actor->managedSoundSlots[slot] = true; + } void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping) { if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS) return; ActorAccessibility_PlaySound(actor, slot, sfxId, looping); - ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch); - ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier); - ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xzDistToPlayer, - actor->policy.distance); - ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume); - actor->managedSoundSlots[slot] = true; + ActorAccessibility_ConfigureSoundForActor(actor, slot); + + } + void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping) + { + if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS) + return; + ActorAccessibility_PlayRawSample(actor, slot, name, looping); + ActorAccessibility_ConfigureSoundForActor(actor, slot); } void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot) @@ -509,9 +539,14 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) { return true; } void ActorAccessibility_ShutdownAudio() { + if (aa->isOn == 0) + return; delete aa->audioEngine; } void ActorAccessibility_MixAccessibleAudioWithGameAudio(int16_t* ogBuffer, uint32_t nFrames) { + if (aa->isOn == 0) + return; + aa->audioEngine->mix(ogBuffer, nFrames); } @@ -532,18 +567,48 @@ return NULL;//Resource doesn't exist, user's gotta run the extractor. tempRecord.resource = res; std::stringstream ss; ss << std::setw(4) << std::setfill('0') << std::hex << sfxId; - tempRecord.hexName = ss.str(); + tempRecord.path = ss.str(); aa->sfxMap[sfxId] = tempRecord; record = &aa->sfxMap[sfxId]; - aa->audioEngine->cacheDecodedSample(record->hexName, record->resource->Buffer.data(), + aa->audioEngine->cacheDecodedSample(record->path, record->resource->Buffer.data(), record->resource->Buffer.size()); } else record = &it->second; - return record->hexName.c_str(); + return record->path.c_str(); } +//Map the path to a raw sample to the external audio engine. + const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name) + { + SfxRecord* record; + std::string key(name); + auto it = aa->sampleMap.find(key); + if (it == aa->sampleMap.end()) { + SfxRecord tempRecord; + std::stringstream ss; + ss << "audio/samples/" << key; + std::string fullPath = ss.str(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResource(fullPath); + if (res == nullptr) +return NULL; // Resource doesn't exist, user's gotta run the extractor. + AudioDecoder decoder; + decoder.setSample((LUS::AudioSample*)res.get()); + s16* wav; + size_t wavSize = decoder.decodeToWav(&wav); + + tempRecord.path = key; + tempRecord.decodedSample = std::make_shared(wav); + aa->sampleMap[key] = tempRecord; + record = &aa->sampleMap[key]; + aa->audioEngine->cacheDecodedSample(record->path, wav, + wavSize); + } else + record = &it->second; + + return record->path.c_str(); + } // Call once per frame to tell the audio engine to start working on the latest batch of queued instructions. void ActorAccessibility_PrepareNextAudioFrame() { diff --git a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h index a363cf803..f8ebe7851 100644 --- a/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h +++ b/soh/soh/Enhancements/accessible-actors/ActorAccessibility.h @@ -99,6 +99,9 @@ void ActorAccessibility_PlaySpecialSound(AccessibleActor* actor, s16 sfxId); *looping: whether to play the sound just once or on a continuous loop. */ void ActorAccessibility_PlaySound(void* actor, int slot, s16 sfxId, bool looping); +//Play one of the game's internal samples. + void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping); +// //Stop a sound. Todo: consider making this a short fade instead of just cutting it off. void ActorAccessibility_StopSound(void* handle, int slot); void ActorAccessibility_StopAllSounds(void* handle); @@ -121,6 +124,8 @@ void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset); * */ void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping); +void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping); + void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot); void ActorAccessibility_StopAllSoundsForActor(AccessibleActor* actor); f32 ActorAccessibility_ComputeCurrentVolume(f32 maxDistance, f32 xzDistToPlayer); diff --git a/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp b/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp index 5fcb1067d..0202ac5a9 100644 --- a/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp +++ b/soh/soh/Enhancements/accessible-actors/SfxExtractor.cpp @@ -93,8 +93,6 @@ void SfxExtractor::renderOutput() { } void SfxExtractor::setup() { try { - ogMusicVolume = CVarGetFloat("gMainMusicVolume", 1.0); - CVarSetFloat("gMainMusicVolume", 0.0); SpeechSynthesizer::Instance->Speak("Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode()); // Kill the audio thread so we can take control. @@ -158,6 +156,8 @@ void SfxExtractor::finished() { CVarClear("gExtractSfx"); CVarSave(); archive = nullptr; + freezeGame = false; + Audio_QueueSeqCmd(NA_BGM_TITLE); if (currentStep == STEP_ERROR || currentStep == STEP_ERROR_OTR) { @@ -171,7 +171,6 @@ void SfxExtractor::finished() { SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode()); } else Audio_PlayFanfare(NA_BGM_ITEM_GET); - freezeGame = false; } void SfxExtractor::maybeGiveProgressReport() { diff --git a/soh/soh/Enhancements/accessible-actors/SfxExtractor.h b/soh/soh/Enhancements/accessible-actors/SfxExtractor.h index 28703f2a7..98087d37c 100644 --- a/soh/soh/Enhancements/accessible-actors/SfxExtractor.h +++ b/soh/soh/Enhancements/accessible-actors/SfxExtractor.h @@ -10,7 +10,6 @@ class SfxExtractor { s16 currentSfx; std::vector tempStorage; // Stores raw audio data for the sfx currently being ripped. int16_t* tempBuffer; // Raw pointer to the above vector. - f32 ogMusicVolume; int progressMilestones[9]; // Implements progress reports after every 10 percent. // Check if a buffer contains meaningful audio output. bool isAllZero(int16_t* buffer, size_t count);