diff --git a/soh/soh/Enhancements/audio/AudioEditor.cpp b/soh/soh/Enhancements/audio/AudioEditor.cpp index 18b5cec1a..c64ed7b42 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.cpp +++ b/soh/soh/Enhancements/audio/AudioEditor.cpp @@ -842,18 +842,17 @@ void RegisterAudioWidgets() { "the area for the effect to kick in.")); SohGui::mSohMenu->AddSearchWidget({ leadingMusic, "Enhancements", "Audio Editor", "Audio Options" }); - displaySeqName = { .name = "Display Sequence Name on Overlay", .type = WidgetType::WIDGET_CVAR_CHECKBOX }; - displaySeqName.CVar(CVAR_AUDIO("SeqNameOverlay")) + displaySeqName = { .name = "Display Sequence Name in Notifications", .type = WidgetType::WIDGET_CVAR_CHECKBOX }; + displaySeqName.CVar(CVAR_AUDIO("SeqNameNotification")) .Options(CheckboxOptions() .Color(THEME_COLOR) - .Tooltip("Displays the name of the current sequence in the corner of the screen whenever a new " - "sequence " - "is loaded to the main sequence player (does not apply to fanfares or enemy BGM).")); + .Tooltip("Emits a notification with the current song name whenever it changes. " + "(does not apply to fanfares or enemy BGM).")); SohGui::mSohMenu->AddSearchWidget({ displaySeqName, "Enhancements", "Audio Editor", "Audio Options" }); - ovlDuration = { .name = "Overlay Duration: %d seconds", .type = WidgetType::WIDGET_CVAR_SLIDER_INT }; - ovlDuration.CVar(CVAR_AUDIO("SeqNameOverlayDuration")) - .Options(IntSliderOptions().Color(THEME_COLOR).Min(1).Max(10).DefaultValue(5).Size(ImVec2(300.0f, 0.0f))); + ovlDuration = { .name = "Sequence Notification Duration: %d seconds", .type = WidgetType::WIDGET_CVAR_SLIDER_INT }; + ovlDuration.CVar(CVAR_AUDIO("SeqNameNotificationDuration")) + .Options(IntSliderOptions().Color(THEME_COLOR).Min(1).Max(20).DefaultValue(10).Size(ImVec2(300.0f, 0.0f))); SohGui::mSohMenu->AddSearchWidget({ ovlDuration, "Enhancements", "Audio Editor", "Audio Options" }); voicePitch = { .name = "Link's Voice Pitch Multiplier", .type = WidgetType::WIDGET_CVAR_SLIDER_FLOAT }; diff --git a/soh/soh/Enhancements/audio/AudioHooks.cpp b/soh/soh/Enhancements/audio/AudioHooks.cpp new file mode 100644 index 000000000..d2d6aa279 --- /dev/null +++ b/soh/soh/Enhancements/audio/AudioHooks.cpp @@ -0,0 +1,43 @@ +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" +#include "AudioCollection.h" +#include +#include + +extern "C" { +#include "variables.h" + +extern PlayState* gPlayState; +} + +#define CVAR_SEQOVERLAY_NAME CVAR_AUDIO("SeqNameNotification") +#define CVAR_SEQOVERLAY_DEFAULT 0 +#define CVAR_SEQOVERLAY_VALUE CVarGetInteger(CVAR_SEQOVERLAY_NAME, CVAR_SEQOVERLAY_DEFAULT) + +void NotifySequenceName(int32_t playerIdx, int32_t seqId) { + // Keep track of the previous sequence/scene so we don't repeat notifications + static uint16_t previousSeqId = UINT16_MAX; + static int16_t previousSceneNum = INT16_MAX; + if (playerIdx == SEQ_PLAYER_BGM_MAIN && + (seqId != previousSeqId || (gPlayState != NULL && gPlayState->sceneNum != previousSceneNum))) { + + previousSeqId = seqId; + if (gPlayState != NULL) { + previousSceneNum = gPlayState->sceneNum; + } + const char* sequenceName = AudioCollection::Instance->GetSequenceName(seqId); + if (sequenceName != NULL) { + Notification::Emit({ + .message = ICON_FA_MUSIC " " + std::string(sequenceName), + .remainingTime = static_cast(CVarGetInteger(CVAR_AUDIO("SeqNameNotificationDuration"), 10)), + .mute = true, + }); + } + } +} + +void RegisterAudioNotificationHooks() { + COND_HOOK(OnSeqPlayerInit, CVAR_SEQOVERLAY_VALUE, NotifySequenceName); +} + +static RegisterShipInitFunc notifInitFunc(RegisterAudioNotificationHooks, { CVAR_SEQOVERLAY_NAME }); \ No newline at end of file diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index b5b1cfbfe..0f694660c 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -74,3 +74,6 @@ DEFINE_HOOK(OnGenerationCompletion, ()); DEFINE_HOOK(OnSetGameLanguage, ()); DEFINE_HOOK(OnAssetAltChange, ()); DEFINE_HOOK(OnKaleidoUpdate, ()); + +// Audio +DEFINE_HOOK(OnSeqPlayerInit, (int32_t playerIdx, int32_t seqId)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index f374aa2d7..7d5a243d2 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -327,3 +327,8 @@ void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)) { void GameInteractor_ExecuteOnKaleidoUpdate() { GameInteractor::Instance->ExecuteHooks(); } + +// Mark: Audio +void GameInteractor_ExecuteOnSeqPlayerInit(int32_t playerIdx, int32_t seqId) { + GameInteractor::Instance->ExecuteHooks(playerIdx, seqId); +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index e22d12dbd..4c3a600e7 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -86,6 +86,9 @@ void GameInteractor_RegisterOnAssetAltChange(void (*fn)(void)); // Mark: - Pause Menu void GameInteractor_ExecuteOnKaleidoUpdate(); +// Mark: - Audio +void GameInteractor_ExecuteOnSeqPlayerInit(int32_t playerIdx, int32_t seqId); + #ifdef __cplusplus } #endif diff --git a/soh/soh/Notification/Notification.cpp b/soh/soh/Notification/Notification.cpp index 14873b068..c70841960 100644 --- a/soh/soh/Notification/Notification.cpp +++ b/soh/soh/Notification/Notification.cpp @@ -131,8 +131,10 @@ void Emit(Options notification) { notification.remainingTime = CVarGetFloat(CVAR_SETTING("Notifications.Duration"), 10.0f); } notifications.push_back(notification); - Audio_PlaySoundGeneral(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + if (!notification.mute) { + Audio_PlaySoundGeneral(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); + } } } // namespace Notification diff --git a/soh/soh/Notification/Notification.h b/soh/soh/Notification/Notification.h index 7eb4bb2d7..bf1d4ec04 100644 --- a/soh/soh/Notification/Notification.h +++ b/soh/soh/Notification/Notification.h @@ -17,6 +17,7 @@ struct Options { std::string suffix = ""; ImVec4 suffixColor = ImVec4(1.0f, 0.5f, 0.5f, 1.0f); float remainingTime = 0.0f; // Seconds + bool mute = false; // whether notification should make a noise }; class Window final : public Ship::GuiWindow { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 963a5b00d..a0ffdc1d1 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1237,6 +1237,7 @@ extern "C" void InitOTR() { conf->RegisterVersionUpdater(std::make_shared()); conf->RegisterVersionUpdater(std::make_shared()); conf->RegisterVersionUpdater(std::make_shared()); + conf->RegisterVersionUpdater(std::make_shared()); conf->RunVersionUpdates(); SohGui::SetupGuiElements(); diff --git a/soh/soh/config/ConfigMigrators.h b/soh/soh/config/ConfigMigrators.h index ee7e91792..54a0dc236 100644 --- a/soh/soh/config/ConfigMigrators.h +++ b/soh/soh/config/ConfigMigrators.h @@ -1520,4 +1520,9 @@ std::vector version3Migrations = { { MigrationAction::Remove, "gPreset0" }, { MigrationAction::Remove, "gPreset1" }, }; + +std::vector version4Migrations = { + { MigrationAction::Rename, "gAudioEditor.SeqNameOverlay", "gAudioEditor.SeqNameNotification" }, + { MigrationAction::Rename, "gAudioEditor.SeqNameOverlayDuration", "gAudioEditor.SeqNameNotificationDuration" }, +}; } // namespace SOH diff --git a/soh/soh/config/ConfigUpdaters.cpp b/soh/soh/config/ConfigUpdaters.cpp index ff451d98c..a7c50a845 100644 --- a/soh/soh/config/ConfigUpdaters.cpp +++ b/soh/soh/config/ConfigUpdaters.cpp @@ -9,6 +9,8 @@ ConfigVersion2Updater::ConfigVersion2Updater() : ConfigVersionUpdater(2) { } ConfigVersion3Updater::ConfigVersion3Updater() : ConfigVersionUpdater(3) { } +ConfigVersion4Updater::ConfigVersion4Updater() : ConfigVersionUpdater(4) { +} void ConfigVersion1Updater::Update(Ship::Config* conf) { if (conf->GetInt("Window.Width", 640) == 640) { @@ -111,4 +113,13 @@ void ConfigVersion3Updater::Update(Ship::Config* conf) { CVarClear(migration.from.c_str()); } } + +void ConfigVersion4Updater::Update(Ship::Config* conf) { + for (Migration migration : version4Migrations) { + if (migration.action == MigrationAction::Rename) { + CVarCopy(migration.from.c_str(), migration.to.value().c_str()); + } + CVarClear(migration.from.c_str()); + } +} } // namespace SOH diff --git a/soh/soh/config/ConfigUpdaters.h b/soh/soh/config/ConfigUpdaters.h index 7912be7de..948188c19 100644 --- a/soh/soh/config/ConfigUpdaters.h +++ b/soh/soh/config/ConfigUpdaters.h @@ -18,4 +18,10 @@ class ConfigVersion3Updater final : public Ship::ConfigVersionUpdater { ConfigVersion3Updater(); void Update(Ship::Config* conf); }; + +class ConfigVersion4Updater final : public Ship::ConfigVersionUpdater { + public: + ConfigVersion4Updater(); + void Update(Ship::Config* conf); +}; } // namespace SOH diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index 52efa4016..f5d24756d 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -8,6 +8,7 @@ #include "soh/Enhancements/audio/AudioCollection.h" #include "soh/Enhancements/audio/AudioEditor.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include #ifdef _MSC_VER #define strdup _strdup @@ -630,19 +631,7 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { AudioSeq_SkipForwardSequence(seqPlayer); //! @bug missing return (but the return value is not used so it's not UB) - // Keep track of the previous sequence/scene so we don't repeat notifications - static uint16_t previousSeqId = UINT16_MAX; - static int16_t previousSceneNum = INT16_MAX; - if (CVarGetInteger(CVAR_AUDIO("SeqNameOverlay"), 0) && playerIdx == SEQ_PLAYER_BGM_MAIN && - (seqId != previousSeqId || (gPlayState != NULL && gPlayState->sceneNum != previousSceneNum))) { - - previousSeqId = seqId; - if (gPlayState != NULL) { - previousSceneNum = gPlayState->sceneNum; - } - - AudioCollection_EmitSongNameNotification(seqId); - } + GameInteractor_ExecuteOnSeqPlayerInit(playerIdx, seqId); } u8* AudioLoad_SyncLoadSeq(s32 seqId) {