Sfx Editor - 3rd Pass (#1873)

* First pass on SFX Editor

* Fix crash at night in Colossus (and probably other undocumented issues)

The SFX editor was swapping out the bytes corresponding to the sequence
to be played regardless of the audio command being issued. This fix
ensures the swap will only happen on commands which actually treat those
bytes as a sequence identifier.

* enabling a few more songs/fanfares

* Removing a few broken bgms, fixing the preview button returning to the wrong bgm

* Fixes restoration from miniboss music to previous one

* add timed minigame into the sounds pool

* A few small tweaks

* More cleanup and add instruments

* adjust usage of getReverseReplacementSeq

* Changes from feedback and prefix external methods with SfxEditor

Co-authored-by: RaelCappra <rael.cappra@gmail.com>
This commit is contained in:
Garrett Cox 2022-11-02 11:27:05 -05:00 committed by GitHub
parent fab52d323b
commit 897e70b6fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 415 additions and 0 deletions

View File

@ -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}

View File

@ -0,0 +1,359 @@
#include "SfxEditor.h"
#include "sequence.h"
#include <string>
#include <map>
#include <libultraship/Cvar.h>
#include <libultraship/ImGuiImpl.h>
#include <functions.h>
#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<u16, std::tuple<std::string, std::string, SeqType>> 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<u16, std::tuple<std::string, std::string, SeqType>>& 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<u16> 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<u16>(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<u16>(id);
}
}
return static_cast<u16>(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);
}

View File

@ -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,
};

View File

@ -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);

View File

@ -33,6 +33,7 @@
#include <libultraship/AudioPlayer.h>
#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();

View File

@ -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);

View File

@ -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);

View File

@ -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;
}