diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 5b8498b6b..faf6012d1 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -173,6 +173,11 @@ set(Header_Files__soh__Enhancements__cosmetics ) source_group("Header Files\\soh\\Enhancements\\cosmetics" FILES ${Header_Files__soh__Enhancements__cosmetics}) +set(Header_Files__soh__Enhancements__sfx_editor + "soh/Enhancements/sfx-editor/SfxEditor.h" +) +source_group("Header Files\\soh\\Enhancements\\sfx-editor" FILES ${Header_Files__soh__Enhancements__sfx_editor}) + set(Header_Files__soh__Enhancements__debugger "soh/Enhancements/debugger/actorViewer.h" "soh/Enhancements/debugger/colViewer.h" @@ -294,6 +299,11 @@ set(Source_Files__soh__Enhancements__cosmetics ) source_group("Source Files\\soh\\Enhancements\\cosmetics" FILES ${Source_Files__soh__Enhancements__cosmetics}) +set(Source_Files__soh__Enhancements__sfx_editor + "soh/Enhancements/sfx-editor/SfxEditor.cpp" +) +source_group("Source Files\\soh\\Enhancements\\sfx-editor" FILES ${Source_Files__soh__Enhancements__sfx_editor}) + set(Source_Files__soh__Enhancements__debugger "soh/Enhancements/debugger/actorViewer.cpp" "soh/Enhancements/debugger/colViewer.cpp" @@ -1599,6 +1609,7 @@ set(ALL_FILES ${Header_Files__soh__Enhancements} ${Header_Files__soh__Enhancements__controls} ${Header_Files__soh__Enhancements__cosmetics} + ${Header_Files__soh__Enhancements__sfx_editor} ${Header_Files__soh__Enhancements__debugger} ${Header_Files__soh__Enhancements__randomizer} ${Header_Files__soh__Enhancements__randomizer__3drando} @@ -1609,6 +1620,7 @@ set(ALL_FILES ${Source_Files__soh__Enhancements} ${Source_Files__soh__Enhancements__controls} ${Source_Files__soh__Enhancements__cosmetics} + ${Source_Files__soh__Enhancements__sfx_editor} ${Source_Files__soh__Enhancements__debugger} ${Source_Files__soh__Enhancements__randomizer} ${Source_Files__soh__Enhancements__randomizer__3drando} diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp new file mode 100644 index 000000000..aa66ad45b --- /dev/null +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp @@ -0,0 +1,359 @@ +#include "SfxEditor.h" +#include "sequence.h" +#include +#include +#include +#include +#include +#include "../randomizer/3drando/random.hpp" + +Vec3f pos = { 0.0f, 0.0f, 0.0f }; +f32 freqScale = 1.0f; +s8 reverbAdd = 0; + +// {originalSequenceId, {label, sfxKey, category}, +const std::map> sequenceMap = { + {NA_BGM_FIELD_LOGIC, {"Hyrule Field", "NA_BGM_FIELD_LOGIC", SEQ_BGM_WORLD}}, + {NA_BGM_DUNGEON, {"Dodongo's Cavern", "NA_BGM_DUNGEON", SEQ_BGM_WORLD}}, + {NA_BGM_KAKARIKO_ADULT, {"Kakariko Village (Adult)", "NA_BGM_KAKARIKO_ADULT", SEQ_BGM_WORLD}}, + {NA_BGM_ENEMY, {"Battle", "NA_BGM_ENEMY", SEQ_BGM_BATTLE}}, + {NA_BGM_BOSS, {"Boss Battle", "NA_BGM_BOSS", SEQ_BGM_BATTLE}}, + {NA_BGM_INSIDE_DEKU_TREE, {"Inside the Deku Tree", "NA_BGM_INSIDE_DEKU_TREE", SEQ_BGM_WORLD}}, + {NA_BGM_MARKET, {"Market", "NA_BGM_MARKET", SEQ_BGM_WORLD}}, + {NA_BGM_TITLE, {"Title Theme", "NA_BGM_TITLE", SEQ_BGM_WORLD}}, + {NA_BGM_LINK_HOUSE, {"House", "NA_BGM_LINK_HOUSE", SEQ_BGM_WORLD}}, + {NA_BGM_GAME_OVER, {"Game Over", "NA_BGM_GAME_OVER", SEQ_FANFARE}}, + {NA_BGM_BOSS_CLEAR, {"Boss Clear", "NA_BGM_BOSS_CLEAR", SEQ_FANFARE}}, + {NA_BGM_ITEM_GET, {"Obtain Item", "NA_BGM_ITEM_GET", SEQ_FANFARE}}, + {NA_BGM_OPENING_GANON, {"Enter Ganondorf", "NA_BGM_OPENING_GANON", SEQ_FANFARE}}, + {NA_BGM_HEART_GET, {"Obtain Heart Container", "NA_BGM_HEART_GET", SEQ_FANFARE}}, + {NA_BGM_OCA_LIGHT, {"Prelude of Light", "NA_BGM_OCA_LIGHT", SEQ_OCARINA}}, + {NA_BGM_JABU_JABU, {"Inside Jabu-Jabu's Belly", "NA_BGM_JABU_JABU", SEQ_BGM_WORLD}}, + {NA_BGM_KAKARIKO_KID, {"Kakariko Village (Child)", "NA_BGM_KAKARIKO_KID", SEQ_BGM_WORLD}}, + {NA_BGM_GREAT_FAIRY, {"Great Fairy's Fountain", "NA_BGM_GREAT_FAIRY", SEQ_BGM_EVENT}}, + {NA_BGM_ZELDA_THEME, {"Zelda's Theme", "NA_BGM_ZELDA_THEME", SEQ_BGM_EVENT}}, + {NA_BGM_FIRE_TEMPLE, {"Fire Temple", "NA_BGM_FIRE_TEMPLE", SEQ_BGM_WORLD}}, + {NA_BGM_OPEN_TRE_BOX, {"Open Treasure Chest", "NA_BGM_OPEN_TRE_BOX", SEQ_FANFARE}}, + {NA_BGM_FOREST_TEMPLE, {"Forest Temple", "NA_BGM_FOREST_TEMPLE", SEQ_BGM_WORLD}}, + {NA_BGM_COURTYARD, {"Hyrule Castle Courtyard", "NA_BGM_COURTYARD", SEQ_BGM_WORLD}}, + {NA_BGM_GANON_TOWER, {"Ganondorf's Theme", "NA_BGM_GANON_TOWER", SEQ_BGM_WORLD}}, + {NA_BGM_LONLON, {"Lon Lon Ranch", "NA_BGM_LONLON", SEQ_BGM_WORLD}}, + {NA_BGM_GORON_CITY, {"Goron City", "NA_BGM_GORON_CITY", SEQ_BGM_WORLD}}, + {NA_BGM_FIELD_MORNING, {"Hyrule Field Morning Theme", "NA_BGM_FIELD_MORNING", SEQ_BGM_WORLD}}, + {NA_BGM_SPIRITUAL_STONE, {"Spiritual Stone Get", "NA_BGM_SPIRITUAL_STONE", SEQ_FANFARE}}, + {NA_BGM_OCA_BOLERO, {"Bolero of Fire", "NA_BGM_OCA_BOLERO", SEQ_OCARINA}}, + {NA_BGM_OCA_MINUET, {"Minuet of Forest", "NA_BGM_OCA_MINUET", SEQ_OCARINA}}, + {NA_BGM_OCA_SERENADE, {"Serenade of Water", "NA_BGM_OCA_SERENADE", SEQ_OCARINA}}, + {NA_BGM_OCA_REQUIEM, {"Requiem of Spirit", "NA_BGM_OCA_REQUIEM", SEQ_OCARINA}}, + {NA_BGM_OCA_NOCTURNE, {"Nocturne of Shadow", "NA_BGM_OCA_NOCTURNE", SEQ_OCARINA}}, + {NA_BGM_MINI_BOSS, {"Mini-Boss Battle", "NA_BGM_MINI_BOSS", SEQ_BGM_BATTLE}}, + {NA_BGM_SMALL_ITEM_GET, {"Obtain Small Item", "NA_BGM_SMALL_ITEM_GET", SEQ_FANFARE}}, + {NA_BGM_TEMPLE_OF_TIME, {"Temple of Time", "NA_BGM_TEMPLE_OF_TIME", SEQ_BGM_WORLD}}, + {NA_BGM_EVENT_CLEAR, {"Escape from Lon Lon Ranch", "NA_BGM_EVENT_CLEAR", SEQ_FANFARE}}, + {NA_BGM_KOKIRI, {"Kokiri Forest", "NA_BGM_KOKIRI", SEQ_BGM_WORLD}}, + {NA_BGM_OCA_FAIRY_GET, {"Obtain Fairy Ocarina", "NA_BGM_OCA_FAIRY_GET", SEQ_FANFARE}}, + {NA_BGM_SARIA_THEME, {"Lost Woods", "NA_BGM_SARIA_THEME", SEQ_BGM_WORLD}}, + {NA_BGM_SPIRIT_TEMPLE, {"Spirit Temple", "NA_BGM_SPIRIT_TEMPLE", SEQ_BGM_WORLD}}, + {NA_BGM_HORSE, {"Horse Race", "NA_BGM_HORSE", SEQ_BGM_EVENT}}, + {NA_BGM_HORSE_GOAL, {"Horse Race Goal", "NA_BGM_HORSE_GOAL", SEQ_FANFARE}}, + {NA_BGM_INGO, {"Ingo's Theme", "NA_BGM_INGO", SEQ_BGM_WORLD}}, + {NA_BGM_MEDALLION_GET, {"Obtain Medallion", "NA_BGM_MEDALLION_GET", SEQ_FANFARE}}, + {NA_BGM_OCA_SARIA, {"Ocarina Saria's Song", "NA_BGM_OCA_SARIA", SEQ_OCARINA}}, + {NA_BGM_OCA_EPONA, {"Ocarina Epona's Song", "NA_BGM_OCA_EPONA", SEQ_OCARINA}}, + {NA_BGM_OCA_ZELDA, {"Ocarina Zelda's Lullaby", "NA_BGM_OCA_ZELDA", SEQ_OCARINA}}, + {NA_BGM_OCA_SUNS, {"Ocarina Sun's Song", "NA_BGM_OCA_SUNS", SEQ_OCARINA}}, + {NA_BGM_OCA_TIME, {"Ocarina Song of Time", "NA_BGM_OCA_TIME", SEQ_OCARINA}}, + {NA_BGM_OCA_STORM, {"Ocarina Song of Storms", "NA_BGM_OCA_STORM", SEQ_OCARINA}}, + {NA_BGM_NAVI_OPENING, {"Fairy Flying", "NA_BGM_NAVI_OPENING", SEQ_BGM_EVENT}}, + {NA_BGM_DEKU_TREE_CS, {"Deku Tree", "NA_BGM_DEKU_TREE_CS", SEQ_BGM_EVENT}}, + {NA_BGM_WINDMILL, {"Windmill Hut", "NA_BGM_WINDMILL", SEQ_BGM_WORLD}}, + {NA_BGM_HYRULE_CS, {"Legend of Hyrule", "NA_BGM_HYRULE_CS", SEQ_BGM_EVENT}}, + {NA_BGM_MINI_GAME, {"Shooting Gallery", "NA_BGM_MINI_GAME", SEQ_BGM_EVENT}}, + {NA_BGM_SHEIK, {"Sheik's Theme", "NA_BGM_SHEIK", SEQ_BGM_EVENT}}, + {NA_BGM_ZORA_DOMAIN, {"Zora's Domain", "NA_BGM_ZORA_DOMAIN", SEQ_BGM_WORLD}}, + {NA_BGM_APPEAR, {"Enter Zelda", "NA_BGM_APPEAR", SEQ_FANFARE}}, + {NA_BGM_ADULT_LINK, {"Goodbye to Zelda", "NA_BGM_ADULT_LINK", SEQ_BGM_EVENT}}, + {NA_BGM_MASTER_SWORD, {"Master Sword", "NA_BGM_MASTER_SWORD", SEQ_FANFARE}}, + {NA_BGM_INTRO_GANON, {"Ganon Intro", "NA_BGM_INTRO_GANON", SEQ_BGM_EVENT}}, + {NA_BGM_SHOP, {"Shop", "NA_BGM_SHOP", SEQ_BGM_WORLD}}, + {NA_BGM_CHAMBER_OF_SAGES, {"Chamber of the Sages", "NA_BGM_CHAMBER_OF_SAGES", SEQ_BGM_EVENT}}, + {NA_BGM_FILE_SELECT, {"File Select", "NA_BGM_FILE_SELECT", SEQ_BGM_WORLD}}, + {NA_BGM_ICE_CAVERN, {"Ice Cavern", "NA_BGM_ICE_CAVERN", SEQ_BGM_WORLD}}, + {NA_BGM_DOOR_OF_TIME, {"Open Door of Temple of Time", "NA_BGM_DOOR_OF_TIME", SEQ_BGM_EVENT}}, + {NA_BGM_OWL, {"Kaepora Gaebora's Theme", "NA_BGM_OWL", SEQ_BGM_EVENT}}, + {NA_BGM_SHADOW_TEMPLE, {"Shadow Temple", "NA_BGM_SHADOW_TEMPLE", SEQ_BGM_WORLD}}, + {NA_BGM_WATER_TEMPLE, {"Water Temple", "NA_BGM_WATER_TEMPLE", SEQ_BGM_WORLD}}, + {NA_BGM_BRIDGE_TO_GANONS, {"Ganon's Castle Bridge", "NA_BGM_BRIDGE_TO_GANONS", SEQ_BGM_EVENT}}, + {NA_BGM_OCARINA_OF_TIME, {"Ocarina of Time", "NA_BGM_OCARINA_OF_TIME", SEQ_FANFARE}}, + {NA_BGM_GERUDO_VALLEY, {"Gerudo Valley", "NA_BGM_GERUDO_VALLEY", SEQ_BGM_WORLD}}, + {NA_BGM_POTION_SHOP, {"Potion Shop", "NA_BGM_POTION_SHOP", SEQ_BGM_WORLD}}, + {NA_BGM_KOTAKE_KOUME, {"Kotake & Koume's Theme", "NA_BGM_KOTAKE_KOUME", SEQ_BGM_EVENT}}, + {NA_BGM_ESCAPE, {"Escape from Ganon's Castle", "NA_BGM_ESCAPE", SEQ_BGM_EVENT}}, + {NA_BGM_UNDERGROUND, {"Ganon's Castle Under Ground", "NA_BGM_UNDERGROUND", SEQ_BGM_WORLD}}, + {NA_BGM_GANONDORF_BOSS, {"Ganondorf Battle", "NA_BGM_GANONDORF_BOSS", SEQ_BGM_BATTLE}}, + {NA_BGM_GANON_BOSS, {"Ganon Battle", "NA_BGM_GANON_BOSS", SEQ_BGM_BATTLE}}, + {NA_BGM_END_DEMO, {"Seal of Six Sages", "NA_BGM_END_DEMO", SEQ_BGM_WORLD}}, + {NA_BGM_STAFF_1, {"End Credits I", "NA_BGM_STAFF_1", SEQ_BGM_WORLD}}, + {NA_BGM_STAFF_2, {"End Credits II", "NA_BGM_STAFF_2", SEQ_NOSHUFFLE}}, + {NA_BGM_STAFF_3, {"End Credits III", "NA_BGM_STAFF_3", SEQ_BGM_WORLD}}, + {NA_BGM_STAFF_4, {"End Credits IV", "NA_BGM_STAFF_4", SEQ_BGM_WORLD}}, + {NA_BGM_FIRE_BOSS, {"King Dodongo & Volvagia Boss Battle", "NA_BGM_FIRE_BOSS", SEQ_BGM_BATTLE}}, + {NA_BGM_TIMED_MINI_GAME, {"Mini-Game", "NA_BGM_TIMED_MINI_GAME", SEQ_BGM_EVENT}}, + {INSTRUMENT_OFFSET + 1, {"Ocarina", "OCARINA_INSTRUMENT_DEFAULT", SEQ_INSTRUMENT}}, + {INSTRUMENT_OFFSET + 2, {"Malon", "OCARINA_INSTRUMENT_MALON", SEQ_INSTRUMENT}}, + {INSTRUMENT_OFFSET + 3, {"Whistle", "OCARINA_INSTRUMENT_WHISTLE", SEQ_INSTRUMENT}}, + {INSTRUMENT_OFFSET + 4, {"Harp", "OCARINA_INSTRUMENT_HARP", SEQ_INSTRUMENT}}, + {INSTRUMENT_OFFSET + 5, {"Organ", "OCARINA_INSTRUMENT_GRIND_ORGAN", SEQ_INSTRUMENT}}, + {INSTRUMENT_OFFSET + 6, {"Flute", "OCARINA_INSTRUMENT_FLUTE", SEQ_INSTRUMENT}}, + {NA_SE_EV_SMALL_DOG_BARK, {"Bark", "NA_SE_EV_SMALL_DOG_BARK", SEQ_SFX}}, + {NA_SE_EN_AWA_BOUND, {"Bomb Bounce", "NA_SE_EN_AWA_BOUND", SEQ_SFX}}, + {NA_SE_EN_SHADEST_TAIKO_LOW, {"Bongo Bongo Low", "NA_SE_EN_SHADEST_TAIKO_LOW", SEQ_SFX}}, + {NA_SE_EN_NUTS_FAINT, {"Business Scrub", "NA_SE_EN_NUTS_FAINT", SEQ_SFX}}, + {NA_SE_SY_CARROT_RECOVER, {"Carrot Refill", "NA_SE_SY_CARROT_RECOVER", SEQ_SFX}}, + {NA_SE_EV_CHICKEN_CRY_N, {"Cluck", "NA_SE_EV_CHICKEN_CRY_N", SEQ_SFX}}, + {NA_SE_EV_BRIDGE_OPEN_STOP, {"Drawbridge Set", "NA_SE_EV_BRIDGE_OPEN_STOP", SEQ_SFX}}, + {NA_SE_EN_KAICHO_CRY, {"Guay", "NA_SE_EN_KAICHO_CRY", SEQ_SFX}}, + {NA_SE_SY_HITPOINT_ALARM, {"Low HP Beep", "NA_SE_SY_HITPOINT_ALARM", SEQ_SFX}}, + {NA_SE_SY_HP_RECOVER, {"HP Recover", "NA_SE_SY_HP_RECOVER", SEQ_SFX}}, + {NA_SE_EV_HORSE_RUN, {"Horse Trot", "NA_SE_EV_HORSE_RUN", SEQ_SFX}}, + {NA_SE_PL_WALK_HEAVYBOOTS, {"Iron Boots", "NA_SE_PL_WALK_HEAVYBOOTS", SEQ_SFX}}, + {NA_SE_EV_COW_CRY, {"Moo", "NA_SE_EV_COW_CRY", SEQ_SFX}}, + {NA_SE_VO_KZ_MOVE, {"Mweep!", "NA_SE_VO_KZ_MOVE", SEQ_SFX}}, + {NA_SE_VO_NA_HELLO_2, {"Navi Hey!", "NA_SE_VO_NA_HELLO_2", SEQ_SFX}}, + {NA_SE_VO_SK_LAUGH, {"Navi Listen!", "NA_SE_VO_SK_LAUGH", SEQ_SFX}}, + {NA_SE_EV_POT_BROKEN, {"Pot Shattering", "NA_SE_EV_POT_BROKEN", SEQ_SFX}}, + {NA_SE_EV_FROG_CRY_0, {"Ribbit", "NA_SE_EV_FROG_CRY_0", SEQ_SFX}}, + {NA_SE_EV_FIVE_COUNT_LUPY, {"Rupee (Silver)", "NA_SE_EV_FIVE_COUNT_LUPY", SEQ_SFX}}, + {NA_SE_EV_FOOT_SWITCH, {"Switch", "NA_SE_EV_FOOT_SWITCH", SEQ_SFX}}, + {NA_SE_IT_WALL_HIT_SOFT, {"Sword Bonk", "NA_SE_IT_WALL_HIT_SOFT", SEQ_SFX}}, + {NA_SE_SY_METRONOME, {"Tambourine", "NA_SE_SY_METRONOME", SEQ_SFX}}, + {NA_SE_VO_Z1_SURPRISE, {"Zelda Gasp (Adult)", "NA_SE_VO_Z1_SURPRISE", SEQ_SFX}}, + {NA_SE_EN_AMOS_VOICE, {"Armos", "NA_SE_EN_AMOS_VOICE", SEQ_SFX}}, + {NA_SE_VO_LI_FALL_L_KID, {"Child Scream", "NA_SE_VO_LI_FALL_L_KID", SEQ_SFX}}, + {NA_SE_VO_FR_LAUGH_0, {"Great Fairy", "NA_SE_VO_FR_LAUGH_0", SEQ_SFX}}, + {NA_SE_EN_REDEAD_AIM, {"Redead Scream", "NA_SE_EN_REDEAD_AIM", SEQ_SFX}}, + {NA_SE_VO_RT_LAUGH_0, {"Ruto Giggle", "NA_SE_VO_RT_LAUGH_0", SEQ_SFX}}, + {NA_SE_EN_STALKID_ATTACK, {"Stalchild Attack", "NA_SE_EN_STALKID_ATTACK", SEQ_SFX}}, + {NA_SE_EV_CHICKEN_CRY_M, {"Cockadoodiedoo", "NA_SE_EV_CHICKEN_CRY_M", SEQ_SFX}}, + {NA_SE_SY_KINSTA_MARK_APPEAR, {"Gold Skulltula Token", "NA_SE_SY_KINSTA_MARK_APPEAR", SEQ_SFX}}, + {NA_SE_EN_REDEAD_CRY, {"Redead Moan", "NA_SE_EN_REDEAD_CRY", SEQ_SFX}}, + {NA_SE_VO_TA_SLEEP, {"Talon Snore", "NA_SE_VO_TA_SLEEP", SEQ_SFX}}, + {NA_SE_EV_LIGHTNING, {"Thunder", "NA_SE_EV_LIGHTNING", SEQ_SFX}}, + {NA_SE_OC_ABYSS, {"Cartoon Fall", "NA_SE_OC_ABYSS", SEQ_SFX}}, + {NA_SE_EN_FLAME_LAUGH, {"Flare Dancer Laugh", "NA_SE_EN_FLAME_LAUGH", SEQ_SFX}}, + {NA_SE_EN_AWA_BREAK, {"Shabom Pop", "NA_SE_EN_AWA_BREAK", SEQ_SFX}}, + {NA_SE_EN_SHADEST_TAIKO_HIGH, {"Bongo Bongo High", "NA_SE_EN_SHADEST_TAIKO_HIGH", SEQ_SFX}}, + {NA_SE_EV_BOTTLE_CAP_OPEN, {"Bottle Cork", "NA_SE_EV_BOTTLE_CAP_OPEN", SEQ_SFX}}, + {NA_SE_IT_BOW_FLICK, {"Bow Twang", "NA_SE_IT_BOW_FLICK", SEQ_SFX}}, + {NA_SE_EN_BUBLE_LAUGH, {"Bubble Laugh", "NA_SE_EN_BUBLE_LAUGH", SEQ_SFX}}, + {NA_SE_VO_LI_BREATH_DRINK_KID, {"Child Pant", "NA_SE_VO_LI_BREATH_DRINK_KID", SEQ_SFX}}, + {NA_SE_EN_DEKU_JR_MOUTH, {"Deku Baba", "NA_SE_EN_DEKU_JR_MOUTH", SEQ_SFX}}, + {NA_SE_EV_DOG_CRY_EVENING, {"Dusk Howl", "NA_SE_EV_DOG_CRY_EVENING", SEQ_SFX}}, + {NA_SE_EN_FLAME_DAMAGE, {"Flare Dancer Startled", "NA_SE_EN_FLAME_DAMAGE", SEQ_SFX}}, + {NA_SE_EN_GANON_AT_RETURN, {"Ganondorf Teh!", "NA_SE_EN_GANON_AT_RETURN", SEQ_SFX}}, + {NA_SE_EN_GOMA_JR_CRY, {"Gohma Larva Croak", "NA_SE_EN_GOMA_JR_CRY", SEQ_SFX}}, + {NA_SE_EN_GOLON_WAKE_UP, {"Goron Wake", "NA_SE_EN_GOLON_WAKE_UP", SEQ_SFX}}, + {NA_SE_SY_START_SHOT, {"Gunshot", "NA_SE_SY_START_SHOT", SEQ_SFX}}, + {NA_SE_IT_HAMMER_HIT, {"Hammer Bonk", "NA_SE_IT_HAMMER_HIT", SEQ_SFX}}, + {NA_SE_EN_IRONNACK_SWING_AXE, {"Iron Knuckle", "NA_SE_EN_IRONNACK_SWING_AXE", SEQ_SFX}}, + {NA_SE_EN_FANTOM_ST_LAUGH, {"Phantom Ganon Laugh", "NA_SE_EN_FANTOM_ST_LAUGH", SEQ_SFX}}, + {NA_SE_EV_PLANT_BROKEN, {"Plant Explode", "NA_SE_EV_PLANT_BROKEN", SEQ_SFX}}, + {NA_SE_SY_GET_RUPY, {"Rupee", "NA_SE_SY_GET_RUPY", SEQ_SFX}}, + {NA_SE_VO_RT_CRASH, {"Ruto Crash", "NA_SE_VO_RT_CRASH", SEQ_SFX}}, + {NA_SE_VO_RT_LIFT, {"Ruto Lift", "NA_SE_VO_RT_LIFT", SEQ_SFX}}, + {NA_SE_VO_RT_THROW, {"Ruto Thrown", "NA_SE_VO_RT_THROW", SEQ_SFX}}, + {NA_SE_EN_NUTS_UP, {"Scrub Emerge", "NA_SE_EN_NUTS_UP", SEQ_SFX}}, + {NA_SE_EN_AWA_BOUND, {"Shabom Bounce", "NA_SE_EN_AWA_BOUND", SEQ_SFX}}, + {NA_SE_EN_SHELL_MOUTH, {"Shellblade", "NA_SE_EN_SHELL_MOUTH", SEQ_SFX}}, + {NA_SE_EN_STALTU_DAMAGE, {"Skulltula Damage", "NA_SE_EN_STALTU_DAMAGE", SEQ_SFX}}, + {NA_SE_EN_NUTS_THROW, {"Spit Nut", "NA_SE_EN_NUTS_THROW", SEQ_SFX}}, + {NA_SE_VO_TA_CRY_0, {"Talon Hmm", "NA_SE_VO_TA_CRY_0", SEQ_SFX}}, + {NA_SE_VO_TA_SURPRISE, {"Talon Surprised", "NA_SE_VO_TA_SURPRISE", SEQ_SFX}}, + {NA_SE_SY_LOCK_ON, {"Target Enemy", "NA_SE_SY_LOCK_ON", SEQ_SFX}}, + {NA_SE_SY_LOCK_ON_HUMAN, {"Target Neutral", "NA_SE_SY_LOCK_ON_HUMAN", SEQ_SFX}}, + {NA_SE_SY_FSEL_CURSOR, {"File Select Cursor", "NA_SE_SY_FSEL_CURSOR", SEQ_SFX}}, + {NA_SE_SY_FSEL_DECIDE_L, {"File Select Choose", "NA_SE_SY_FSEL_DECIDE_L", SEQ_SFX}}, + {NA_SE_SY_FSEL_CLOSE, {"File Select Back", "NA_SE_SY_FSEL_CLOSE", SEQ_SFX}}, + {NA_SE_IT_BOMB_EXPLOSION, {"Bomb Explosion", "NA_SE_IT_BOMB_EXPLOSION", SEQ_SFX}}, + {NA_SE_EV_CHICKEN_CRY_A, {"Chicken Cry", "NA_SE_EV_CHICKEN_CRY_A", SEQ_SFX}}, +}; + +void Draw_SfxTab(const std::string& tabId, const std::map>& map, SeqType type) { + const std::string hiddenTabId = "##" + tabId; + const std::string resetAllButton = "Reset All" + hiddenTabId; + const std::string randomizeAllButton = "Randomize All" + hiddenTabId; + if (ImGui::Button(resetAllButton.c_str())) { + for (const auto& [defaultValue, seqData] : map) { + const auto& [name, sfxKey, seqType] = seqData; + if (seqType == type) { + const std::string cvarKey = "gSfxEditor_" + sfxKey; + CVar_SetS32(cvarKey.c_str(), defaultValue); + } + } + SohImGui::RequestCvarSaveOnNextTick(); + } + ImGui::SameLine(); + if (ImGui::Button(randomizeAllButton.c_str())) { + std::vector values; + for (const auto& [value, seqData] : map) { + if (std::get<2>(seqData) == type) { + values.push_back(value); + } + } + Shuffle(values); + for (const auto& [defaultValue, seqData] : map) { + const auto& [name, sfxKey, seqType] = seqData; + const std::string cvarKey = "gSfxEditor_" + sfxKey; + if (seqType == type) { + const int randomValue = values.back(); + CVar_SetS32(cvarKey.c_str(), randomValue); + values.pop_back(); + } + } + SohImGui::RequestCvarSaveOnNextTick(); + } + + ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 110.0f); + for (const auto& [defaultValue, seqData] : map) { + const auto& [name, sfxKey, seqType] = seqData; + + if (seqType != type) { + continue; + } + + const std::string cvarKey = "gSfxEditor_" + sfxKey; + const std::string hiddenKey = "##" + cvarKey; + const std::string stopButton = " Stop " + hiddenKey; + const std::string previewButton = "Preview" + hiddenKey; + const std::string resetButton = "Reset" + hiddenKey; + const int currentValue = CVar_GetS32(cvarKey.c_str(), defaultValue); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text(name.c_str()); + ImGui::TableNextColumn(); + ImGui::PushItemWidth(-FLT_MIN); + if (ImGui::BeginCombo(hiddenKey.c_str(), std::get<0>(map.at(currentValue)).c_str())) { + for (const auto& [value, seqData] : map) { + const auto& [name, sfxKey, seqType] = seqData; + if (seqType != type) { + continue; + } + + if (ImGui::Selectable(std::get<0>(seqData).c_str())) { + CVar_SetS32(cvarKey.c_str(), value); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + + ImGui::EndCombo(); + } + ImGui::TableNextColumn(); + ImGui::PushItemWidth(-FLT_MIN); + if (CVar_GetS32("gSfxEditor_playing", 0) == currentValue) { + if (ImGui::Button(stopButton.c_str())) { + func_800F5C2C(); + CVar_SetS32("gSfxEditor_playing", 0); + } + } else { + if (ImGui::Button(previewButton.c_str())) { + if (CVar_GetS32("gSfxEditor_playing", 0) != 0) { + func_800F5C2C(); + CVar_SetS32("gSfxEditor_playing", 0); + } else { + if (type == SEQ_SFX) { + Audio_PlaySoundGeneral(defaultValue, &pos, 4, &freqScale, &freqScale, &reverbAdd); + } else if (type == SEQ_INSTRUMENT) { + Audio_OcaSetInstrument(defaultValue - INSTRUMENT_OFFSET); + Audio_OcaSetSongPlayback(9, 1); + } else { + // TODO: Cant do both here, so have to click preview button twice + func_800F5ACC(defaultValue); + CVar_SetS32("gSfxEditor_playing", currentValue); + } + } + } + } + ImGui::SameLine(); + ImGui::PushItemWidth(-FLT_MIN); + if (ImGui::Button(resetButton.c_str())) { + CVar_SetS32(cvarKey.c_str(), defaultValue); + SohImGui::RequestCvarSaveOnNextTick(); + } + } + ImGui::EndTable(); +} + +extern "C" u16 SfxEditor_GetReplacementSeq(u16 seqId) { + if (sequenceMap.find(seqId) == sequenceMap.end()) { + return seqId; + } + + const auto& [name, sfxKey, seqType] = sequenceMap.at(seqId); + const std::string cvarKey = "gSfxEditor_" + sfxKey; + const int replacementSeq = CVar_GetS32(cvarKey.c_str(), seqId); + + return static_cast(replacementSeq); +} + +extern "C" u16 SfxEditor_GetReverseReplacementSeq(u16 seqId) { + for (const auto& [id, nameAndsfxKey] : sequenceMap) { + const auto& [name, sfxKey, seqType] = sequenceMap.at(id); + const std::string cvarKey = "gSfxEditor_" + sfxKey; + if (CVar_GetS32(cvarKey.c_str(), id) == seqId){ + return static_cast(id); + } + } + + return static_cast(seqId); +} + +void DrawSfxEditor(bool& open) { + if (!open) { + CVar_SetS32("gSfxEditor", 0); + return; + } + ImGui::SetNextWindowSize(ImVec2(465, 630), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("SFX Editor", &open)) { + ImGui::End(); + return; + } + + if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { + if (ImGui::BeginTabItem("Background Music")) { + Draw_SfxTab("backgroundMusic", sequenceMap, SEQ_BGM_WORLD); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Fanfares")) { + Draw_SfxTab("fanfares", sequenceMap, SEQ_FANFARE); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Events")) { + Draw_SfxTab("event", sequenceMap, SEQ_BGM_EVENT); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Battle Music")) { + Draw_SfxTab("battleMusic", sequenceMap, SEQ_BGM_BATTLE); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Ocarina")) { + Draw_SfxTab("instrument", sequenceMap, SEQ_INSTRUMENT); + Draw_SfxTab("ocarina", sequenceMap, SEQ_OCARINA); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Sound Effects")) { + Draw_SfxTab("sfx", sequenceMap, SEQ_SFX); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::End(); +} + +void InitSfxEditor() { + //Draw the bar in the menu. + SohImGui::AddWindow("Enhancements", "SFX Editor", DrawSfxEditor); +} diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.h b/soh/soh/Enhancements/sfx-editor/SfxEditor.h new file mode 100644 index 000000000..a905b3e4e --- /dev/null +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.h @@ -0,0 +1,17 @@ +#pragma once + +void InitSfxEditor(); + +#define INSTRUMENT_OFFSET 0x81 + +enum SeqType { + SEQ_NOSHUFFLE = 0, + SEQ_BGM_WORLD = 1 << 0, + SEQ_BGM_EVENT = 1 << 1, + SEQ_BGM_BATTLE = 1 << 2, + SEQ_OCARINA = 1 << 3, + SEQ_FANFARE = 1 << 4, + SEQ_BGM_ERROR = 1 << 5, + SEQ_SFX = 1 << 6, + SEQ_INSTRUMENT = 1 << 7, +}; \ No newline at end of file diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index 9e9301df9..2ac4688dd 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -1159,6 +1159,13 @@ namespace GameMenuBar { SohImGui::RequestCvarSaveOnNextTick(); SohImGui::EnableWindow("Cosmetics Editor", CVar_GetS32("gCosmeticsEditorEnabled", 0)); } + if (ImGui::Button(GetWindowButtonText("SFX Editor", CVar_GetS32("gSfxEditor", 0)).c_str(), ImVec2(-1.0f, 0.0f))) + { + bool currentValue = CVar_GetS32("gSfxEditor", 0); + CVar_SetS32("gSfxEditor", !currentValue); + SohImGui::RequestCvarSaveOnNextTick(); + SohImGui::EnableWindow("SFX Editor", CVar_GetS32("gSfxEditor", 0)); + } ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index e3f12065f..15128f9f4 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -33,6 +33,7 @@ #include #include "Enhancements/controls/GameControlEditor.h" #include "Enhancements/cosmetics/CosmeticsEditor.h" +#include "Enhancements/sfx-editor/SfxEditor.h" #include "Enhancements/debugconsole.h" #include "Enhancements/debugger/debugger.h" #include "Enhancements/randomizer/randomizer.h" @@ -440,6 +441,7 @@ extern "C" void InitOTR() { OTRAudio_Init(); InitCosmeticsEditor(); GameControlEditor::Init(); + InitSfxEditor(); DebugConsole_Init(); Debug_Init(); Rando_Init(); diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index f5f1b980e..46cc63683 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -1698,6 +1698,12 @@ void Audio_OcaSetInstrument(u8 arg0) { return; } + u16 sfxEditorId = arg0 + 0x81; + u16 newArg0 = SfxEditor_GetReplacementSeq(sfxEditorId); + if (newArg0 != sfxEditorId) { + arg0 = newArg0 - 0x81; + } + Audio_SeqCmd8(SEQ_PLAYER_SFX, 1, SFX_PLAYER_CHANNEL_OCARINA, arg0); D_80130F10 = arg0; if (arg0 == 0) { @@ -4580,6 +4586,7 @@ s32 func_800F5A58(u8 arg0) { */ void func_800F5ACC(u16 seqId) { u16 curSeqId = func_800FA0B4(SEQ_PLAYER_BGM_MAIN); + curSeqId = SfxEditor_GetReverseReplacementSeq(curSeqId); if ((curSeqId & 0xFF) != NA_BGM_GANON_TOWER && (curSeqId & 0xFF) != NA_BGM_ESCAPE && curSeqId != seqId) { Audio_SetSequenceMode(SEQ_MODE_IGNORE); diff --git a/soh/src/code/code_800F7260.c b/soh/src/code/code_800F7260.c index 4a6189947..816550618 100644 --- a/soh/src/code/code_800F7260.c +++ b/soh/src/code/code_800F7260.c @@ -221,6 +221,7 @@ void Audio_ProcessSoundRequest(void) if (req->sfxId == 0) { return; } + req->sfxId = SfxEditor_GetReplacementSeq(req->sfxId); bankId = SFX_BANK(req->sfxId); if ((1 << bankId) & D_801333F0) { AudioDebug_ScrPrt((const s8*)D_80133340, req->sfxId); diff --git a/soh/src/code/code_800F9280.c b/soh/src/code/code_800F9280.c index 5fa3d50fa..66d3cec31 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -368,6 +368,16 @@ extern f32 D_80130F28; void Audio_QueueSeqCmd(u32 cmd) { + u8 op = cmd >> 28; + if (op == 0 || op == 2 || op == 12){ + u16 oldSeqId = cmd & 0xFFFF; + u16 newSeqId = SfxEditor_GetReplacementSeq(oldSeqId); + if (newSeqId != oldSeqId) { + cmd &= ~0xFFFF; + cmd |= newSeqId; + } + } + sAudioSeqCmds[sSeqCmdWrPos++] = cmd; }