diff --git a/soh/include/z64audio.h b/soh/include/z64audio.h index f1e44a7e8..6b4613fff 100644 --- a/soh/include/z64audio.h +++ b/soh/include/z64audio.h @@ -22,6 +22,8 @@ #define CALC_RESAMPLE_FREQ(sampleRate) ((float)sampleRate / (s32)gAudioContext.audioBufferParameters.frequency) +#define MAX_SEQUENCES 0x400 + extern char* fontMap[256]; typedef enum { @@ -259,7 +261,7 @@ typedef struct { /* 0x001 */ u8 state; /* 0x002 */ u8 noteAllocPolicy; /* 0x003 */ u8 muteBehavior; - /* 0x004 */ u8 seqId; + /* 0x004 */ u16 seqId; /* 0x005 */ u8 defaultFont; /* 0x006 */ u8 unk_06[1]; /* 0x007 */ s8 playerIdx; @@ -913,7 +915,7 @@ typedef struct { /* 0x342C */ AudioPoolSplit3 temporaryCommonPoolSplit; /* 0x3438 */ u8 sampleFontLoadStatus[0x30]; /* 0x3468 */ u8 fontLoadStatus[0x30]; - /* 0x3498 */ u8 seqLoadStatus[0x80]; + /* 0x3498 */ u8 seqLoadStatus[MAX_SEQUENCES]; /* 0x3518 */ volatile u8 resetStatus; /* 0x3519 */ u8 audioResetSpecIdToLoad; /* 0x351C */ s32 audioResetFadeOutFramesLeft; @@ -941,6 +943,8 @@ typedef struct { /* 0x5C3C */ OSMesg audioResetMesgs[1]; /* 0x5C40 */ OSMesg cmdProcMsgs[4]; /* 0x5C50 */ AudioCmd cmdBuf[0x100]; + u16 seqToPlay[4]; + u8 seqReplaced[4]; } AudioContext; // size = 0x6450 typedef struct { @@ -1105,7 +1109,7 @@ typedef enum { typedef struct { char* seqData; int32_t seqDataSize; - uint8_t seqNumber; + uint16_t seqNumber; uint8_t medium; uint8_t cachePolicy; int32_t numFonts; diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp index 71d6ee36b..3efce43e6 100644 --- a/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.cpp @@ -6,13 +6,16 @@ #include #include #include "../randomizer/3drando/random.hpp" +#include "../../OTRGlobals.h" +#include +#include "../../UIWidgets.hpp" Vec3f pos = { 0.0f, 0.0f, 0.0f }; f32 freqScale = 1.0f; s8 reverbAdd = 0; // {originalSequenceId, {label, sfxKey, category}, -const std::map> sequenceMap = { +std::map> sfxEditorSequenceMap = { {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}}, @@ -39,7 +42,6 @@ const std::map> sequenceMap = {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}}, @@ -196,7 +198,7 @@ void Draw_SfxTab(const std::string& tabId, const std::map values; for (const auto& [value, seqData] : map) { - if (std::get<2>(seqData) == type) { + if (std::get<2>(seqData) & type) { values.push_back(value); } } @@ -204,7 +206,10 @@ void Draw_SfxTab(const std::string& tabId, const std::map MAX_AUTHENTIC_SEQID) { + continue; + } const int randomValue = values.back(); CVar_SetS32(cvarKey.c_str(), randomValue); values.pop_back(); @@ -216,11 +221,14 @@ void Draw_SfxTab(const std::string& tabId, const std::map= MAX_AUTHENTIC_SEQID) { continue; } @@ -229,6 +237,7 @@ void Draw_SfxTab(const std::string& tabId, const std::map(map.at(currentValue)).c_str())) { + const int initialValue = map.contains(currentValue) ? currentValue : defaultValue; + if (ImGui::BeginCombo(hiddenKey.c_str(), std::get<0>(map.at(initialValue)).c_str())) { for (const auto& [value, seqData] : map) { const auto& [name, sfxKey, seqType] = seqData; - if (seqType != type) { + if (~(seqType) & type) { continue; } @@ -283,25 +293,53 @@ void Draw_SfxTab(const std::string& tabId, const std::map(replacementSeq); } extern "C" u16 SfxEditor_GetReverseReplacementSeq(u16 seqId) { - for (const auto& [id, nameAndsfxKey] : sequenceMap) { - const auto& [name, sfxKey, seqType] = sequenceMap.at(id); + for (const auto& [id, nameAndsfxKey] : sfxEditorSequenceMap) { + const auto& [name, sfxKey, seqType] = sfxEditorSequenceMap.at(id); const std::string cvarKey = "gSfxEditor_" + sfxKey; if (CVar_GetS32(cvarKey.c_str(), id) == seqId){ return static_cast(id); @@ -324,28 +362,56 @@ void DrawSfxEditor(bool& open) { if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) { if (ImGui::BeginTabItem("Background Music")) { - Draw_SfxTab("backgroundMusic", sequenceMap, SEQ_BGM_WORLD); + Draw_SfxTab("backgroundMusic", sfxEditorSequenceMap, SEQ_BGM_WORLD); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Fanfares")) { - Draw_SfxTab("fanfares", sequenceMap, SEQ_FANFARE); + Draw_SfxTab("fanfares", sfxEditorSequenceMap, SEQ_FANFARE); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Events")) { - Draw_SfxTab("event", sequenceMap, SEQ_BGM_EVENT); + Draw_SfxTab("event", sfxEditorSequenceMap, SEQ_BGM_EVENT); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Battle Music")) { - Draw_SfxTab("battleMusic", sequenceMap, SEQ_BGM_BATTLE); + Draw_SfxTab("battleMusic", sfxEditorSequenceMap, SEQ_BGM_BATTLE); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Ocarina")) { - Draw_SfxTab("instrument", sequenceMap, SEQ_INSTRUMENT); - Draw_SfxTab("ocarina", sequenceMap, SEQ_OCARINA); + Draw_SfxTab("instrument", sfxEditorSequenceMap, SEQ_INSTRUMENT); + Draw_SfxTab("ocarina", sfxEditorSequenceMap, SEQ_OCARINA); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Sound Effects")) { - Draw_SfxTab("sfx", sequenceMap, SEQ_SFX); + Draw_SfxTab("sfx", sfxEditorSequenceMap, SEQ_SFX); + ImGui::EndTabItem(); + } + + static ImVec2 cellPadding(8.0f, 8.0f); + if (ImGui::BeginTabItem("Options")) { + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding); + ImGui::BeginTable("Options", 1, ImGuiTableFlags_SizingStretchSame); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) { + ImGui::PushItemWidth(-FLT_MIN); + UIWidgets::EnhancementCheckbox("Disable Enemy Proximity Music", "gEnemyBGMDisable"); + UIWidgets::InsertHelpHoverText( + "Disables the music change when getting close to enemies. Useful for hearing " + "your custom music for each scene more often."); + UIWidgets::PaddedSeparator(); + UIWidgets::PaddedText("The following options are experimental and may cause music\nto sound odd or have other undesireable effects."); + UIWidgets::EnhancementCheckbox("Lower Octaves of Unplayable High Notes", "gExperimentalOctaveDrop"); + UIWidgets::InsertHelpHoverText("Some custom sequences may have notes that are too high for the game's audio " + "engine to play. Enabling this checkbox will cause these notes to drop a " + "couple of octaves so they can still harmonize with the other notes of the " + "sequence."); + ImGui::PopItemWidth(); + } + ImGui::EndChild(); + ImGui::EndTable(); + ImGui::PopStyleVar(1); ImGui::EndTabItem(); } ImGui::EndTabBar(); @@ -357,3 +423,22 @@ void InitSfxEditor() { //Draw the bar in the menu. SohImGui::AddWindow("Enhancements", "SFX Editor", DrawSfxEditor); } + +extern "C" void SfxEditor_AddSequence(char *otrPath, uint16_t seqNum) { + std::vector splitName = StringHelper::Split(otrPath, "/"); + std::string fileName = splitName[splitName.size() - 1]; + std::vector splitFileName = StringHelper::Split(fileName, "_"); + std::string sequenceName = splitFileName[0]; + SeqType type = SEQ_BGM_CUSTOM; + std::string typeString = splitFileName[splitFileName.size() - 1]; + std::locale loc; + for (int i = 0; i < typeString.length(); i++) { + typeString[i] = std::tolower(typeString[i], loc); + } + if (typeString == "fanfare") { + type = SEQ_FANFARE; + } + auto tuple = std::make_tuple( + sequenceName, StringHelper::Replace(StringHelper::Replace(sequenceName, " ", "_"), "~", "-"), type); + sfxEditorSequenceMap.emplace(seqNum, tuple); +} diff --git a/soh/soh/Enhancements/sfx-editor/SfxEditor.h b/soh/soh/Enhancements/sfx-editor/SfxEditor.h index a905b3e4e..a9a856515 100644 --- a/soh/soh/Enhancements/sfx-editor/SfxEditor.h +++ b/soh/soh/Enhancements/sfx-editor/SfxEditor.h @@ -1,8 +1,13 @@ #pragma once +#include "stdint.h" void InitSfxEditor(); +#ifndef __cplusplus +void SfxEditor_AddSequence(char *otrPath, uint16_t seqNum); +#endif #define INSTRUMENT_OFFSET 0x81 +#define MAX_AUTHENTIC_SEQID 110 enum SeqType { SEQ_NOSHUFFLE = 0, @@ -14,4 +19,5 @@ enum SeqType { SEQ_BGM_ERROR = 1 << 5, SEQ_SFX = 1 << 6, SEQ_INSTRUMENT = 1 << 7, + SEQ_BGM_CUSTOM = SEQ_BGM_WORLD | SEQ_BGM_EVENT | SEQ_BGM_BATTLE, }; \ No newline at end of file diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 5b407a9b7..9d7e8b690 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -177,6 +177,10 @@ bool OTRGlobals::HasOriginal() { return hasOriginal; } +std::shared_ptr> OTRGlobals::ListFiles(std::string path) { + return context->GetResourceManager()->ListFiles(path); +} + struct ExtensionEntry { std::string path; std::string ext; diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 126f7c396..09435f5f6 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -10,6 +10,7 @@ #include #include "Enhancements/savestates.h" #include "Enhancements/randomizer/randomizer.h" +#include const std::string customMessageTableID = "BaseGameOverrides"; @@ -27,6 +28,7 @@ public: bool HasMasterQuest(); bool HasOriginal(); + std::shared_ptr> ListFiles(std::string path); private: void CheckSaveFile(size_t sramSize) const; diff --git a/soh/src/code/audio_heap.c b/soh/src/code/audio_heap.c index 189d73133..0e7027510 100644 --- a/soh/src/code/audio_heap.c +++ b/soh/src/code/audio_heap.c @@ -53,7 +53,7 @@ void AudioHeap_ResetLoadStatus(void) { } } - for (i = 0; i < 0x80; i++) { + for (i = 0; i < MAX_SEQUENCES; i++) { if (gAudioContext.seqLoadStatus[i] != 5) { gAudioContext.seqLoadStatus[i] = 0; } diff --git a/soh/src/code/audio_init_params.c b/soh/src/code/audio_init_params.c index f5bae8fd8..12653c6dc 100644 --- a/soh/src/code/audio_init_params.c +++ b/soh/src/code/audio_init_params.c @@ -68,22 +68,22 @@ ReverbSettings D_80133420[][3] = { }; AudioSpec gAudioSpecs[18] = { - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x4000, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[1], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[2], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 23, 4, 0, 0, 2, D_80133420[4], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 23, 4, 0, 0, 2, D_80133420[5], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[6], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[7], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 23, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[9], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 23, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 28, 3, 0, 0, 2, D_80133420[10], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x2800, 0x2880, 0, 0, 0 }, - { 44100, 1, 28, 3, 0, 0, 1, D_80133420[11], 0x300, 0x200, 0x7FFF, 0, 0x4800, 0, 0x4000, 0, 0, 0, 0 }, - { 44100, 1, 28, 3, 0, 0, 1, D_80133420[11], 0x300, 0x200, 0x7FFF, 0, 0, 0, 0x4000, 0x4800, 0, 0, 0 }, - { 44100, 1, 22, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 22, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 16, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 22050, 1, 24, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3800, 0x2880, 0, 0, 0 }, - { 44100, 1, 24, 4, 0, 0, 2, D_80133420[2], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x3600, 0x2600, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[1], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[2], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 23, 4, 0, 0, 2, D_80133420[4], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 23, 4, 0, 0, 2, D_80133420[5], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[6], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[7], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 23, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[9], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 23, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 28, 3, 0, 0, 2, D_80133420[10], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 28, 3, 0, 0, 1, D_80133420[11], 0x300, 0x200, 0x7FFF, 0, 0x4800, 0, 0x5000, 0, 0, 0, 0 }, + { 44100, 1, 28, 3, 0, 0, 1, D_80133420[11], 0x300, 0x200, 0x7FFF, 0, 0, 0, 0x5000, 0x4800, 0, 0, 0 }, + { 44100, 1, 22, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 22, 4, 0, 0, 2, D_80133420[8], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 16, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 22050, 1, 24, 4, 0, 0, 2, D_80133420[0], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2880, 0, 0, 0 }, + { 44100, 1, 24, 4, 0, 0, 2, D_80133420[2], 0x300, 0x200, 0x7FFF, 0x7F0, 0xE00, 0, 0x5000, 0x2600, 0, 0, 0 }, }; diff --git a/soh/src/code/audio_load.c b/soh/src/code/audio_load.c index eff3e5f87..0dfb56691 100644 --- a/soh/src/code/audio_load.c +++ b/soh/src/code/audio_load.c @@ -5,6 +5,7 @@ #include "ultra64.h" #include "global.h" #include "soh/OTRGlobals.h" +#include "soh/Enhancements/sfx-editor/SfxEditor.h" #define MK_ASYNC_MSG(retData, tableType, id, status) (((retData) << 24) | ((tableType) << 16) | ((id) << 8) | (status)) #define ASYNC_TBLTYPE(v) ((u8)(v >> 16)) @@ -76,7 +77,7 @@ void* sUnusedHandler = NULL; s32 gAudioContextInitalized = false; -char* sequenceMap[256]; +char* sequenceMap[MAX_SEQUENCES]; char* fontMap[256]; uintptr_t fontStart; @@ -481,10 +482,14 @@ void AudioLoad_AsyncLoadFont(s32 fontId, s32 arg1, s32 retData, OSMesgQueue* ret u8* AudioLoad_GetFontsForSequence(s32 seqId, u32* outNumFonts) { s32 index; - if (seqId == 255) - return NULL; + if (seqId == NA_BGM_DISABLED) + return NULL; - SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqId]); + u16 newSeqId = SfxEditor_GetReplacementSeq(seqId); + if (!sequenceMap[newSeqId]){ + return NULL; + } + SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[newSeqId]); if (sDat.numFonts == 0) return NULL; @@ -568,9 +573,10 @@ s32 AudioLoad_SyncInitSeqPlayerInternal(s32 playerIdx, s32 seqId, s32 arg2) { AudioSeq_SequencePlayerDisable(seqPlayer); fontId = 0xFF; - //index = ((u16*)gAudioContext.sequenceFontTable)[seqId]; - //numFonts = gAudioContext.sequenceFontTable[index++]; + if (gAudioContext.seqReplaced[playerIdx]) { + seqId = gAudioContext.seqToPlay[playerIdx]; + } SequenceData seqData2 = ResourceMgr_LoadSeqByName(sequenceMap[seqId]); for (int i = 0; i < seqData2.numFonts; i++) @@ -984,7 +990,6 @@ void* AudioLoad_AsyncLoadInner(s32 tableType, s32 id, s32 nChunks, s32 retData, u32 temp_v0; u32 realId; - realId = AudioLoad_GetRealTableIndex(tableType, id); switch (tableType) { case SEQUENCE_TABLE: if (gAudioContext.seqLoadStatus[realId] == 1) { @@ -1211,6 +1216,12 @@ void AudioLoad_InitSwapFont(void) { #undef BASE_ROM_OFFSET +int strcmp_sort( const void *str1, const void *str2 ) { + char *const *pp1 = str1; + char *const *pp2 = str2; + return strcmp(*pp1, *pp2); +} + void AudioLoad_Init(void* heap, size_t heapSize) { char pad[0x48]; s32 numFonts; @@ -1223,6 +1234,8 @@ void AudioLoad_Init(void* heap, size_t heapSize) { gAudioContext.resetTimer = 0; memset(&gAudioContext, 0, sizeof(gAudioContext)); + memset(gAudioContext.seqToPlay, 0, 8); + memset(gAudioContext.seqReplaced, 0, 8); switch (osTvType) { case OS_TV_PAL: @@ -1307,6 +1320,25 @@ void AudioLoad_Init(void* heap, size_t heapSize) { free(seqList); + int customSeqListSize = 0; + int startingSeqNum = MAX_AUTHENTIC_SEQID; // 109 is the highest vanilla sequence + char** customSeqList = ResourceMgr_ListFiles("custom/music/*", &customSeqListSize); + qsort(customSeqList, customSeqListSize, sizeof(char*), strcmp_sort); + + for (size_t i = startingSeqNum; i < startingSeqNum + customSeqListSize; i++) { + int j = i - startingSeqNum; + SfxEditor_AddSequence(customSeqList[j], i); + SequenceData sDat = ResourceMgr_LoadSeqByName(customSeqList[j]); + sDat.seqNumber = i; + + char* str = malloc(strlen(customSeqList[j]) + 1); + strcpy(str, customSeqList[j]); + + sequenceMap[sDat.seqNumber] = str; + } + + free(customSeqList); + int fntListSize = 0; char** fntList = ResourceMgr_ListFiles("audio/fonts*", &fntListSize); @@ -1499,6 +1531,22 @@ s32 AudioLoad_SlowLoadSeq(s32 seqId, u8* ramAddr, s8* isDone) { size_t size; seqId = AudioLoad_GetRealTableIndex(SEQUENCE_TABLE, seqId); + u16 newSeqId = SfxEditor_GetReplacementSeq(seqId); + if (seqId != newSeqId) { + gAudioContext.seqToPlay[SEQ_PLAYER_BGM_MAIN] = newSeqId; + gAudioContext.seqReplaced[SEQ_PLAYER_BGM_MAIN] = 1; + // This sequence command starts playing a sequence specified by seqId on the main BGM seq player. + // The sequence command is a bitpacked u32 where different bits of the number indicated different parameters. + // What those parameters are is dependent on the first 8 bits which represent an operation. + // First two digits (bits 31-24) - Sequence Command Operation (0x0 = play sequence immediately) + // Next two digits (bits 23-16) - Index of the SeqPlayer to operate on. (0, which is the main BGM player.) + // Next two digits (bits 15-8) - Fade Timer (0 in this case, we don't want any fade-in or out here.) + // Last two digits (bits 7-0) - the sequence ID to play. Not actually sure why it is cast to u16 instead of u8, + // copied this from authentic game code and adapted it. I think it might be so that you can choose to encode the + // fade timer into the seqId if you want to for some reason. + Audio_QueueSeqCmd(0x00000000 | ((u8)SEQ_PLAYER_BGM_MAIN << 24) | ((u8)(0) << 16) | (u16)seqId); + return 0; + } seqTable = AudioLoad_GetLoadTable(SEQUENCE_TABLE); slowLoad = &gAudioContext.slowLoads[gAudioContext.slowLoadPos]; if (slowLoad->status == LOAD_STATUS_DONE) { diff --git a/soh/src/code/audio_playback.c b/soh/src/code/audio_playback.c index 5b19796c8..a10034a14 100644 --- a/soh/src/code/audio_playback.c +++ b/soh/src/code/audio_playback.c @@ -120,7 +120,11 @@ void Audio_NoteSetResamplingRate(NoteSubEu* noteSubEu, f32 resamplingRateInput) } else { noteSubEu->bitField1.hasTwoParts = true; if (3.99996f < resamplingRateInput) { - resamplingRate = 1.99998f; + if (CVar_GetS32("gExperimentalOctaveDrop", 0)) { + resamplingRate = resamplingRateInput * 0.25; + } else { + resamplingRate = 1.99998f; + } } else { resamplingRate = resamplingRateInput * 0.5f; } @@ -347,7 +351,7 @@ Instrument* Audio_GetInstrumentInner(s32 fontId, s32 instId) { } Drum* Audio_GetDrum(s32 fontId, s32 drumId) { - Drum* drum; + Drum* drum = NULL; if (fontId == 0xFF) { return NULL; @@ -360,7 +364,9 @@ Drum* Audio_GetDrum(s32 fontId, s32 drumId) { SoundFont* sf = ResourceMgr_LoadAudioSoundFont(fontMap[fontId]); - drum = sf->drums[drumId]; + if (drumId < sf->numDrums) { + drum = sf->drums[drumId]; + } if (drum == NULL) { gAudioContext.audioErrorFlags = ((fontId << 8) + drumId) + 0x5000000; @@ -538,6 +544,9 @@ s32 Audio_BuildSyntheticWave(Note* note, SequenceLayer* layer, s32 waveId) { if (waveId < 128) { waveId = 128; } + if (waveId > 136) { + waveId = 136; + } freqScale = layer->freqScale; if (layer->portamento.mode != 0 && 0.0f < layer->portamento.extent) { diff --git a/soh/src/code/audio_seqplayer.c b/soh/src/code/audio_seqplayer.c index dd9c6e1cc..80a97b97e 100644 --- a/soh/src/code/audio_seqplayer.c +++ b/soh/src/code/audio_seqplayer.c @@ -3,7 +3,7 @@ #include "ultra64.h" #include "global.h" -extern char* sequenceMap[256]; +extern char* sequenceMap[MAX_SEQUENCES]; #define PORTAMENTO_IS_SPECIAL(x) ((x).mode & 0x80) #define PORTAMENTO_MODE(x) ((x).mode & ~0x80) @@ -1063,7 +1063,12 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { if (seqPlayer->defaultFont != 0xFF) { - SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqPlayer->seqId]); + if (gAudioContext.seqReplaced[seqPlayer->playerIdx]) { + seqPlayer->seqId = gAudioContext.seqToPlay[seqPlayer->playerIdx]; + gAudioContext.seqReplaced[seqPlayer->playerIdx] = 0; + } + u16 seqId = SfxEditor_GetReplacementSeq(seqPlayer->seqId); + SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqId]); command = sDat.fonts[sDat.numFonts - result - 1]; } @@ -1175,7 +1180,12 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) { if (seqPlayer->defaultFont != 0xFF) { - SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqPlayer->seqId]); + if (gAudioContext.seqReplaced[seqPlayer->playerIdx]) { + seqPlayer->seqId = gAudioContext.seqToPlay[seqPlayer->playerIdx]; + gAudioContext.seqReplaced[seqPlayer->playerIdx] = 0; + } + u16 seqId = SfxEditor_GetReplacementSeq(seqPlayer->seqId); + SequenceData sDat = ResourceMgr_LoadSeqByName(sequenceMap[seqId]); // The game apparantely would sometimes do negative array lookups, the result of which would get rejected by AudioHeap_SearchCaches, never // changing the actual fontid. diff --git a/soh/src/code/code_800EC960.c b/soh/src/code/code_800EC960.c index 46cc63683..b65fc6492 100644 --- a/soh/src/code/code_800EC960.c +++ b/soh/src/code/code_800EC960.c @@ -134,7 +134,7 @@ u8 sAudioExtraFilter2 = 0; Vec3f* sSariaBgmPtr = NULL; f32 D_80130650 = 2000.0f; u8 sSeqModeInput = 0; -u8 sSeqFlags[0x6E] = { +u8 sSeqFlags[0x6F] = { 0x2, // NA_BGM_GENERAL_SFX 0x1, // NA_BGM_NATURE_BACKGROUND 0, // NA_BGM_FIELD_LOGIC @@ -245,6 +245,7 @@ u8 sSeqFlags[0x6E] = { 0, // NA_BGM_FIRE_BOSS 0x8, // NA_BGM_TIMED_MINI_GAME 0, // NA_BGM_VARIOUS_SFX + 1, // NA_BGM_CUSTOM_SEQ }; s8 sSpecReverbs[20] = { 0, 0, 0, 0, 0, 0, 0, 40, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1701,6 +1702,7 @@ void Audio_OcaSetInstrument(u8 arg0) { u16 sfxEditorId = arg0 + 0x81; u16 newArg0 = SfxEditor_GetReplacementSeq(sfxEditorId); if (newArg0 != sfxEditorId) { + gAudioContext.seqReplaced[SEQ_PLAYER_SFX] = 1; arg0 = newArg0 - 0x81; } @@ -4586,7 +4588,6 @@ 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); @@ -4648,7 +4649,7 @@ void Audio_PlayFanfare(u16 seqId) sp26 = func_800FA0B4(SEQ_PLAYER_FANFARE); sp1C = func_800E5E84(sp26 & 0xFF, &sp20); - sp18 = func_800E5E84(seqId & 0xFF, &sp20); + sp18 = func_800E5E84(seqId, &sp20); if (!sp1C || !sp18) { // disable BGM, we're about to null deref! D_8016B9F4 = 1; diff --git a/soh/src/code/code_800F7260.c b/soh/src/code/code_800F7260.c index 816550618..1aaa8f360 100644 --- a/soh/src/code/code_800F7260.c +++ b/soh/src/code/code_800F7260.c @@ -221,7 +221,11 @@ void Audio_ProcessSoundRequest(void) if (req->sfxId == 0) { return; } - req->sfxId = SfxEditor_GetReplacementSeq(req->sfxId); + u16 newSfxId = SfxEditor_GetReplacementSeq(req->sfxId); + if (req->sfxId != newSfxId) { + gAudioContext.seqReplaced[SEQ_PLAYER_SFX] = 1; + req->sfxId = newSfxId; + } 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 086752a1c..49ca751f1 100644 --- a/soh/src/code/code_800F9280.c +++ b/soh/src/code/code_800F9280.c @@ -106,7 +106,7 @@ void Audio_ProcessSeqCmd(u32 cmd) { u8 op; u8 subOp; u8 playerIdx; - u8 seqId; + u16 seqId; u8 seqArgs; u8 found; u8 port; @@ -369,14 +369,14 @@ 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; + if (op == 0 || op == 2 || op == 12) { + u8 seqId = cmd & 0xFF; + u8 playerIdx = (cmd >> 24) & 0xFF; + u16 newSeqId = SfxEditor_GetReplacementSeq(seqId); + gAudioContext.seqReplaced[playerIdx] = (seqId != newSeqId); + gAudioContext.seqToPlay[playerIdx] = newSeqId; + cmd |= (seqId & 0xFF); } - } sAudioSeqCmds[sSeqCmdWrPos++] = cmd; } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 5bbb42c7d..d6dc9a2a8 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -10271,7 +10271,7 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { seqMode = SEQ_MODE_STILL; } - if (play->actorCtx.targetCtx.bgmEnemy != NULL) { + if (play->actorCtx.targetCtx.bgmEnemy != NULL && !CVar_GetS32("gEnemyBGMDisable", 0)) { seqMode = SEQ_MODE_ENEMY; Audio_SetBgmEnemyVolume(sqrtf(play->actorCtx.targetCtx.bgmEnemy->xyzDistToPlayerSq)); }