From f5ce58ca7f818bfc7100929381324b86923ae646 Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 01:38:28 -0700 Subject: [PATCH 01/20] reverb proof of concept --- CMakeLists.txt | 8 +- include/dusk/settings.h | 2 +- libs/freeverb/CMakeLists.txt | 13 ++ libs/freeverb/allpass.cpp | 36 +++++ libs/freeverb/allpass.hpp | 48 ++++++ libs/freeverb/comb.cpp | 48 ++++++ libs/freeverb/comb.hpp | 55 +++++++ libs/freeverb/denormals.h | 15 ++ libs/freeverb/revmodel.cpp | 252 +++++++++++++++++++++++++++++++ libs/freeverb/revmodel.hpp | 87 +++++++++++ libs/freeverb/tuning.h | 60 ++++++++ src/dusk/audio/DuskDsp.cpp | 54 +++++-- src/dusk/audio/DuskDsp.hpp | 4 + src/dusk/imgui/ImGuiMenuGame.cpp | 4 +- src/dusk/settings.cpp | 1 + 15 files changed, 668 insertions(+), 19 deletions(-) create mode 100644 libs/freeverb/CMakeLists.txt create mode 100644 libs/freeverb/allpass.cpp create mode 100644 libs/freeverb/allpass.hpp create mode 100644 libs/freeverb/comb.cpp create mode 100644 libs/freeverb/comb.hpp create mode 100644 libs/freeverb/denormals.h create mode 100644 libs/freeverb/revmodel.cpp create mode 100644 libs/freeverb/revmodel.hpp create mode 100644 libs/freeverb/tuning.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 248dfcf6b1..272ff76db3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) +add_subdirectory(libs/freeverb) + option(DUSK_BUILD_WARNINGS "If off, compiler warnings will be suppressed") option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.") option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON) @@ -108,14 +110,14 @@ target_include_directories(game_debug PUBLIC extern ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include build/${DUSK_TP_VERSION}/include) -target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card) +target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card freeverb) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES} src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiAudio.cpp) -target_link_libraries(game PRIVATE game_debug cxxopts::cxxopts absl::flat_hash_map) +target_link_libraries(game PRIVATE game_debug cxxopts::cxxopts absl::flat_hash_map freeverb) if (DUSK_MOVIE_SUPPORT_REAL) if (TARGET libjpeg-turbo::turbojpeg-static) message(STATUS "dusk: Linking against libjpeg-turbo static library") @@ -132,7 +134,7 @@ target_precompile_headers(game PRIVATE "$<$:${CMAKE_SOURCE add_executable(dusk src/dusk/main.cpp) target_compile_definitions(dusk PRIVATE TARGET_PC AVOID_UB=1 VERSION=0) target_include_directories(dusk PRIVATE include) -target_link_libraries(dusk PRIVATE game aurora::main) +target_link_libraries(dusk PRIVATE game aurora::main freeverb) add_custom_command(TARGET dusk POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory diff --git a/include/dusk/settings.h b/include/dusk/settings.h index daba1287d8..64fee289ba 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -20,6 +20,7 @@ struct UserSettings { float subMusicVolume; float soundEffectsVolume; float fanfareVolume; + bool enableReverb; } audio; // Game settings @@ -68,4 +69,3 @@ TransientSettings& getTransientSettings(); } #endif // DUSK_CONFIG_H - diff --git a/libs/freeverb/CMakeLists.txt b/libs/freeverb/CMakeLists.txt new file mode 100644 index 0000000000..c4f4d4ed95 --- /dev/null +++ b/libs/freeverb/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.10) + +project(freeverb LANGUAGES CXX) + +add_library(freeverb + comb.cpp + allpass.cpp + revmodel.cpp +) + +target_include_directories(freeverb PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/libs/freeverb/allpass.cpp b/libs/freeverb/allpass.cpp new file mode 100644 index 0000000000..5d80eda2bd --- /dev/null +++ b/libs/freeverb/allpass.cpp @@ -0,0 +1,36 @@ +// Allpass filter implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "allpass.hpp" + +allpass::allpass() +{ + bufidx = 0; +} + +void allpass::setbuffer(float *buf, int size) +{ + buffer = buf; + bufsize = size; +} + +void allpass::mute() +{ + for (int i=0; i=bufsize) bufidx = 0; + + return output; +} + +#endif//_allpass + +//ends \ No newline at end of file diff --git a/libs/freeverb/comb.cpp b/libs/freeverb/comb.cpp new file mode 100644 index 0000000000..c05f5069c8 --- /dev/null +++ b/libs/freeverb/comb.cpp @@ -0,0 +1,48 @@ +// Comb filter implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "comb.hpp" + +comb::comb() +{ + filterstore = 0; + bufidx = 0; +} + +void comb::setbuffer(float *buf, int size) +{ + buffer = buf; + bufsize = size; +} + +void comb::mute() +{ + for (int i=0; i=bufsize) bufidx = 0; + + return output; +} + +#endif //_comb_ + +//ends diff --git a/libs/freeverb/denormals.h b/libs/freeverb/denormals.h new file mode 100644 index 0000000000..f871412714 --- /dev/null +++ b/libs/freeverb/denormals.h @@ -0,0 +1,15 @@ +// Macro for killing denormalled numbers +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// Based on IS_DENORMAL macro by Jon Watte +// This code is public domain + +#ifndef _denormals_ +#define _denormals_ + +#define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f + +#endif//_denormals_ + +//ends diff --git a/libs/freeverb/revmodel.cpp b/libs/freeverb/revmodel.cpp new file mode 100644 index 0000000000..feaa3bc04c --- /dev/null +++ b/libs/freeverb/revmodel.cpp @@ -0,0 +1,252 @@ +// Reverb model implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "revmodel.hpp" + +revmodel::revmodel() +{ + // Tie the components to their buffers + combL[0].setbuffer(bufcombL1,combtuningL1); + combR[0].setbuffer(bufcombR1,combtuningR1); + combL[1].setbuffer(bufcombL2,combtuningL2); + combR[1].setbuffer(bufcombR2,combtuningR2); + combL[2].setbuffer(bufcombL3,combtuningL3); + combR[2].setbuffer(bufcombR3,combtuningR3); + combL[3].setbuffer(bufcombL4,combtuningL4); + combR[3].setbuffer(bufcombR4,combtuningR4); + combL[4].setbuffer(bufcombL5,combtuningL5); + combR[4].setbuffer(bufcombR5,combtuningR5); + combL[5].setbuffer(bufcombL6,combtuningL6); + combR[5].setbuffer(bufcombR6,combtuningR6); + combL[6].setbuffer(bufcombL7,combtuningL7); + combR[6].setbuffer(bufcombR7,combtuningR7); + combL[7].setbuffer(bufcombL8,combtuningL8); + combR[7].setbuffer(bufcombR8,combtuningR8); + allpassL[0].setbuffer(bufallpassL1,allpasstuningL1); + allpassR[0].setbuffer(bufallpassR1,allpasstuningR1); + allpassL[1].setbuffer(bufallpassL2,allpasstuningL2); + allpassR[1].setbuffer(bufallpassR2,allpasstuningR2); + allpassL[2].setbuffer(bufallpassL3,allpasstuningL3); + allpassR[2].setbuffer(bufallpassR3,allpasstuningR3); + allpassL[3].setbuffer(bufallpassL4,allpasstuningL4); + allpassR[3].setbuffer(bufallpassR4,allpasstuningR4); + + // Set default values + allpassL[0].setfeedback(0.5f); + allpassR[0].setfeedback(0.5f); + allpassL[1].setfeedback(0.5f); + allpassR[1].setfeedback(0.5f); + allpassL[2].setfeedback(0.5f); + allpassR[2].setfeedback(0.5f); + allpassL[3].setfeedback(0.5f); + allpassR[3].setfeedback(0.5f); + setwet(initialwet); + setroomsize(initialroom); + setdry(initialdry); + setdamp(initialdamp); + setwidth(initialwidth); + setmode(initialmode); + + // Buffer will be full of rubbish - so we MUST mute them + mute(); +} + +void revmodel::mute() +{ + if (getmode() >= freezemode) + return; + + for (int i=0;i 0) + { + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(int i=0; i 0) + { + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(int i=0; i= freezemode) + { + roomsize1 = 1; + damp1 = 0; + gain = muted; + } + else + { + roomsize1 = roomsize; + damp1 = damp; + gain = fixedgain; + } + + for(i=0; i= freezemode) + return 1; + else + return 0; +} + +//ends diff --git a/libs/freeverb/revmodel.hpp b/libs/freeverb/revmodel.hpp new file mode 100644 index 0000000000..10fe7c67d5 --- /dev/null +++ b/libs/freeverb/revmodel.hpp @@ -0,0 +1,87 @@ +// Reverb model declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _revmodel_ +#define _revmodel_ + +#include "comb.hpp" +#include "allpass.hpp" +#include "tuning.h" + +class revmodel +{ +public: + revmodel(); + void mute(); + void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); + void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); + void setroomsize(float value); + float getroomsize(); + void setdamp(float value); + float getdamp(); + void setwet(float value); + float getwet(); + void setdry(float value); + float getdry(); + void setwidth(float value); + float getwidth(); + void setmode(float value); + float getmode(); +private: + void update(); +private: + float gain; + float roomsize,roomsize1; + float damp,damp1; + float wet,wet1,wet2; + float dry; + float width; + float mode; + + // The following are all declared inline + // to remove the need for dynamic allocation + // with its subsequent error-checking messiness + + // Comb filters + comb combL[numcombs]; + comb combR[numcombs]; + + // Allpass filters + allpass allpassL[numallpasses]; + allpass allpassR[numallpasses]; + + // Buffers for the combs + float bufcombL1[combtuningL1]; + float bufcombR1[combtuningR1]; + float bufcombL2[combtuningL2]; + float bufcombR2[combtuningR2]; + float bufcombL3[combtuningL3]; + float bufcombR3[combtuningR3]; + float bufcombL4[combtuningL4]; + float bufcombR4[combtuningR4]; + float bufcombL5[combtuningL5]; + float bufcombR5[combtuningR5]; + float bufcombL6[combtuningL6]; + float bufcombR6[combtuningR6]; + float bufcombL7[combtuningL7]; + float bufcombR7[combtuningR7]; + float bufcombL8[combtuningL8]; + float bufcombR8[combtuningR8]; + + // Buffers for the allpasses + float bufallpassL1[allpasstuningL1]; + float bufallpassR1[allpasstuningR1]; + float bufallpassL2[allpasstuningL2]; + float bufallpassR2[allpasstuningR2]; + float bufallpassL3[allpasstuningL3]; + float bufallpassR3[allpasstuningR3]; + float bufallpassL4[allpasstuningL4]; + float bufallpassR4[allpasstuningR4]; +}; + +#endif//_revmodel_ + +//ends \ No newline at end of file diff --git a/libs/freeverb/tuning.h b/libs/freeverb/tuning.h new file mode 100644 index 0000000000..baaa9ce004 --- /dev/null +++ b/libs/freeverb/tuning.h @@ -0,0 +1,60 @@ +// Reverb model tuning values +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _tuning_ +#define _tuning_ + +const int numcombs = 8; +const int numallpasses = 4; +const float muted = 0; +const float fixedgain = 0.015f; +const float scalewet = 3; +const float scaledry = 2; +const float scaledamp = 0.4f; +const float scaleroom = 0.28f; +const float offsetroom = 0.7f; +const float initialroom = 0.5f; +const float initialdamp = 0.5f; +const float initialwet = 1/scalewet; +const float initialdry = 0; +const float initialwidth = 1; +const float initialmode = 0; +const float freezemode = 0.5f; +const int stereospread = 23; + +// These values assume 44.1KHz sample rate +// they will probably be OK for 48KHz sample rate +// but would need scaling for 96KHz (or other) sample rates. +// The values were obtained by listening tests. +const int combtuningL1 = 1116; +const int combtuningR1 = 1116+stereospread; +const int combtuningL2 = 1188; +const int combtuningR2 = 1188+stereospread; +const int combtuningL3 = 1277; +const int combtuningR3 = 1277+stereospread; +const int combtuningL4 = 1356; +const int combtuningR4 = 1356+stereospread; +const int combtuningL5 = 1422; +const int combtuningR5 = 1422+stereospread; +const int combtuningL6 = 1491; +const int combtuningR6 = 1491+stereospread; +const int combtuningL7 = 1557; +const int combtuningR7 = 1557+stereospread; +const int combtuningL8 = 1617; +const int combtuningR8 = 1617+stereospread; +const int allpasstuningL1 = 556; +const int allpasstuningR1 = 556+stereospread; +const int allpasstuningL2 = 441; +const int allpasstuningR2 = 441+stereospread; +const int allpasstuningL3 = 341; +const int allpasstuningR3 = 341+stereospread; +const int allpasstuningL4 = 225; +const int allpasstuningR4 = 225+stereospread; + +#endif//_tuning_ + +//ends + diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index 7cf1c44cd8..fd1ae66620 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -19,6 +19,7 @@ ChannelAuxData dusk::audio::ChannelAux[DSP_CHANNELS] = {}; f32 dusk::audio::MasterVolume = 1.0f; f32 dusk::audio::PrevMasterVolume = 1.0f; +bool dusk::audio::EnableReverb = true; /** * Validate that a DSP channel's format is actually something we know how to play. @@ -112,32 +113,47 @@ void dusk::audio::DspRender(OutputSubframe& subframe) { auto& channel = channels[i]; auto& channelAux = ChannelAux[i]; - if (!channel.mIsActive) { - continue; - } + bool skipRender = false; - if (channel.mPauseFlag) { + if (!channel.mIsActive) { + skipRender = true; + } + else if (channel.mPauseFlag) { // Not really sure what the practical difference between pause and // deactivation is. Either avoids clearing state or allows the DSP to avoid popping? - continue; + skipRender = true; } - - if (channel.mForcedStop) { + else if (channel.mForcedStop) { channel.mIsFinished = true; - continue; + skipRender = true; } - - if (channel.mWaveAramAddress == 0) { + else if (channel.mWaveAramAddress == 0) { // I think these are oscillator channels? Not backed by audio. // No idea how to implement these yet, so skip them. channel.mIsFinished = true; - continue; + skipRender = true; } - ValidateChannel(channel); - OutputSubframe channelSubframe = {}; - RenderChannel(channel, channelAux, channelSubframe); + + if (!skipRender) { + ValidateChannel(channel); + RenderChannel(channel, channelAux, channelSubframe); + // todo figure out an actual way to convert this accurately to dry/wet + channelAux.reverb.setwet(((channel.mAutoMixerFxMix >> 8) / 255.0f)); + channelAux.reverb.setdry(1.0f - channelAux.reverb.getwet()); + } + + if (EnableReverb) { + channelAux.reverb.processreplace( + channelSubframe.channels[0].data(), + channelSubframe.channels[1].data(), + channelSubframe.channels[0].data(), + channelSubframe.channels[1].data(), + DSP_SUBFRAME_SIZE, + 1 + ); + } for (int o = 0; o < subframe.channels.size(); o++) { MixSubframe(subframe.channels[o], channelSubframe.channels[o]); @@ -463,6 +479,16 @@ static void RenderChannel( } void dusk::audio::DspInit() { + for (int i = 0; i < DSP_CHANNELS; i++) { + auto& channelAux = ChannelAux[i]; + channelAux.reverb.setwet(0.0f); + channelAux.reverb.setdry(1.0f); + channelAux.reverb.setroomsize(0.2f); + channelAux.reverb.setdamp(0.3f); + channelAux.reverb.setwidth(1.0f); + channelAux.reverb.setmode(0.0f); + channelAux.reverb.mute(); + } } void dusk::audio::ApplyVolume( diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp index 35b6ccabc9..3c414375f3 100644 --- a/src/dusk/audio/DuskDsp.hpp +++ b/src/dusk/audio/DuskDsp.hpp @@ -8,6 +8,8 @@ #include "SDL3/SDL_audio.h" #include +#include "revmodel.hpp" + // ReSharper disable once CppUnusedIncludeDirective #include "global.h" @@ -29,6 +31,7 @@ namespace dusk::audio { // Used for debugging tools. u32 resetCount; + revmodel reverb; /** * Previous volume values, per output channel. @@ -118,4 +121,5 @@ namespace dusk::audio { extern f32 MasterVolume; extern f32 PrevMasterVolume; + extern bool EnableReverb; } diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 91aa0314df..7bdea47862 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -6,6 +6,7 @@ #include #include "JSystem/JUtility/JUTGamePad.h" +#include "dusk/audio/DuskDsp.hpp" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/hotkeys.h" #include "dusk/settings.h" @@ -34,7 +35,7 @@ namespace dusk { if (ImGui::BeginMenu("Audio")) { ImGui::Text("Master Volume"); ImGui::SliderFloat("##masterVolume", &getSettings().audio.masterVolume, 0.0f, 1.0f, ""); - + ImGui::Checkbox("Enable Reverb", &getSettings().audio.enableReverb); /* // TODO: implement additional settings ImGui::Text("Main Music Volume"); @@ -55,6 +56,7 @@ namespace dusk { */ audio::SetMasterVolume(getSettings().audio.masterVolume); + audio::EnableReverb = getSettings().audio.enableReverb; ImGui::EndMenu(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 9a5bb20c8c..ed2071ca30 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -17,6 +17,7 @@ UserSettings g_userSettings = { .subMusicVolume = 1.0f, .soundEffectsVolume = 1.0f, .fanfareVolume = 1.0f, + .enableReverb = true }, // Game settings From 1862e3a0e43aa05500ab182fdea3955d4a698107 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 11:36:15 -0400 Subject: [PATCH 02/20] Non-Stop Midna's Lament Audio Enhancement --- include/dusk/settings.h | 3 +++ src/Z2AudioLib/Z2SoundObjMgr.cpp | 7 +++++++ src/dusk/imgui/ImGuiMenuEnhancements.cpp | 9 +++++++++ src/dusk/settings.cpp | 3 +++ 4 files changed, 22 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 582c5a1872..d6e7ac2791 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -45,6 +45,9 @@ struct UserSettings { bool enableBloom; bool useWaterProjectionOffset; + // Audio + bool midnasLamentNonStop; + // Cheats bool enableFastIronBoots; diff --git a/src/Z2AudioLib/Z2SoundObjMgr.cpp b/src/Z2AudioLib/Z2SoundObjMgr.cpp index 6b080134fb..9fd9c4addb 100644 --- a/src/Z2AudioLib/Z2SoundObjMgr.cpp +++ b/src/Z2AudioLib/Z2SoundObjMgr.cpp @@ -107,6 +107,13 @@ static Z2EnemyInfo mEnemyInfo[64] = { void Z2SoundObjMgr::searchEnemy() { twilightBattle_ = 0; + #if TARGET_PC + if (Z2GetSeqMgr()->checkBgmIDPlaying(Z2BGM_MIDNA_SOS)) { + Z2GetSeqMgr()->changeSubBgmStatus(0); + return; + } + #endif + if (!Z2GetLink()) { Z2GetSeqMgr()->stopBattleBgm(1, 1); return; diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index cf7fcc41d7..a0559c89b4 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -67,6 +67,15 @@ namespace dusk { ImGui::EndMenu(); } + if (ImGui::BeginMenu("Audio")) { + ImGui::Checkbox("Non-Stop Midna's Lament", &getSettings().game.midnasLamentNonStop); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing."); + } + + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Cheats")) { ImGui::Checkbox("Fast Iron Boots", &getSettings().game.enableFastIronBoots); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index ea17eef374..7a11101906 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -41,6 +41,9 @@ UserSettings g_userSettings = { .enableBloom = true, .useWaterProjectionOffset = false, + // Audio + .midnasLamentNonStop = false, + // Cheats .enableFastIronBoots = false, From 6f76a52545e3cb304c19a1ee1078d0f2222de842 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 11:57:42 -0400 Subject: [PATCH 03/20] oops, forgot to check the box --- src/Z2AudioLib/Z2SoundObjMgr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Z2AudioLib/Z2SoundObjMgr.cpp b/src/Z2AudioLib/Z2SoundObjMgr.cpp index 9fd9c4addb..19099c7675 100644 --- a/src/Z2AudioLib/Z2SoundObjMgr.cpp +++ b/src/Z2AudioLib/Z2SoundObjMgr.cpp @@ -108,7 +108,9 @@ void Z2SoundObjMgr::searchEnemy() { twilightBattle_ = 0; #if TARGET_PC - if (Z2GetSeqMgr()->checkBgmIDPlaying(Z2BGM_MIDNA_SOS)) { + if (Z2GetSeqMgr()->checkBgmIDPlaying(Z2BGM_MIDNA_SOS) && + dusk::getSettings().game.midnasLamentNonStop) + { Z2GetSeqMgr()->changeSubBgmStatus(0); return; } From 0ccf5e8771e58c7887fcb4bba27930808f5cf2e2 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 11:59:08 -0400 Subject: [PATCH 04/20] No Climbing Miss Animation toggle, similar to TPHD --- include/dusk/settings.h | 1 + src/d/actor/d_a_alink_hang.inc | 12 ++++++++++++ src/dusk/imgui/ImGuiMenuEnhancements.cpp | 6 ++++++ src/dusk/settings.cpp | 1 + 4 files changed, 20 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 582c5a1872..ffd1016c48 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -35,6 +35,7 @@ struct UserSettings { int damageMultiplier; bool instantDeath; bool fastClimbing; + bool noMissClimbing; bool fastTears; // Preferences diff --git a/src/d/actor/d_a_alink_hang.inc b/src/d/actor/d_a_alink_hang.inc index a98020ce4f..89f11fc940 100644 --- a/src/d/actor/d_a_alink_hang.inc +++ b/src/d/actor/d_a_alink_hang.inc @@ -285,7 +285,11 @@ int daAlink_c::procHangStartInit() { offNoResetFlg2(FLG2_UNK_2000); if (checkHangFootWall()) { + #if TARGET_PC + if (!is_prev_hangReady && cM_rnd() < 0.7f && !dusk::getSettings().game.noMissClimbing) { + #else if (!is_prev_hangReady && cM_rnd() < 0.7f) { + #endif setSingleAnimeParam(ANM_CLIMB_HANG_MISS, &mpHIO->mLadder.m.mWallAttachMissAnm); field_0x3478 = mpHIO->mLadder.m.mWallAttachMissAnm.mCancelFrame; voiceStart(Z2SE_AL_V_FOOT_MISS); @@ -2084,7 +2088,11 @@ int daAlink_c::procClimbUpStartInit(int param_0) { speed.y = 0.0f; mNormalSpeed = 0.0f; + #if TARGET_PC + if (param_0 || var_r29 || cM_rnd() < 0.3f || dusk::getSettings().game.noMissClimbing) { + #else if (param_0 || var_r29 || cM_rnd() < 0.3f) { + #endif setSingleAnimeParam(ANM_CLIMB_HANG, &mpHIO->mLadder.m.mWallAttachAnm); field_0x3478 = mpHIO->mLadder.m.mWallAttachAnm.mCancelFrame; voiceStart(Z2SE_AL_V_JUMP_HANG); @@ -2161,7 +2169,11 @@ int daAlink_c::procClimbDownStartInit(s16 param_0) { deleteEquipItem(TRUE, FALSE); + #if TARGET_PC + if (cM_rnd() < 0.7f || dusk::getSettings().game.noMissClimbing) { + #else if (cM_rnd() < 0.7f) { + #endif setSingleAnimeParam(ANM_CLIMB_HANG, &mpHIO->mLadder.m.mWallAttachAnm); field_0x3478 = mpHIO->mLadder.m.mWallAttachAnm.mCancelFrame; mProcVar0.field_0x3008 = 0; diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index cf7fcc41d7..ec0a249f9f 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -37,6 +37,12 @@ namespace dusk { ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version"); } + ImGui::Checkbox("No Climbing Miss Animation", &getSettings().game.noMissClimbing); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Prevents Link from playing a struggle animation\n" + "when using the Clawshot on vines at a weird angle."); + } + ImGui::Checkbox("Faster Tears of Light", &getSettings().game.fastTears); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version"); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index ea17eef374..f39c4fd5b3 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -31,6 +31,7 @@ UserSettings g_userSettings = { .damageMultiplier = 1, .instantDeath = false, .fastClimbing = false, + .noMissClimbing = false, .fastTears = false, // Preferences From dca35f8b910ab7d402e3c555860d3ead3c0559c7 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 14:30:42 -0400 Subject: [PATCH 05/20] Can transform anywhere + Refactored checks to see if you can Quick Transform --- include/dusk/settings.h | 1 + src/d/actor/d_a_alink_dusk.cpp | 50 +++++++++++++----------- src/d/actor/d_a_midna.cpp | 11 ++++-- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 6 +++ src/dusk/settings.cpp | 1 + 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 582c5a1872..2de5b376eb 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -47,6 +47,7 @@ struct UserSettings { // Cheats bool enableFastIronBoots; + bool canTransformAnywhere; // Technical bool restoreWiiGlitches; diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 83a5d592a5..95218268ac 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -19,28 +19,6 @@ void daAlink_c::handleQuickTransform() { return; } - // Make sure Link isn't riding anything (horse, boar, etc.) - if (checkRide()) { - return; - } - - switch (mProcID) { - // Make sure Link is not underwater or talking to someone. - case PROC_TALK: - case PROC_SWIM_UP: - case PROC_SWIM_DIVE: - return; - // If Link is targeting or pulling a chain, we don't want to remove the ability to use items in combat accidently. - case PROC_ATN_ACTOR_MOVE: - case PROC_ATN_ACTOR_WAIT: - case PROC_WOLF_ATN_AC_MOVE: - break; - default: - // Disable the input that was just pressed, as sometimes it could cause items to be used or Wolf Link to dig. - mDoCPd_c::getCpadInfo(PAD_1).mPressedButtonFlags = 0; - break; - } - // Ensure there is a proper pointer to the mMeterClass and mpMeterDraw structs in g_meter2_info. const auto meterClassPtr = g_meter2_info.getMeterClass(); if (!meterClassPtr) { @@ -52,18 +30,46 @@ void daAlink_c::handleQuickTransform() { return; } + mDoCPd_c::getCpadInfo(PAD_1).mPressedButtonFlags = 0; + // Ensure that the Z Button is not dimmed if (meterDrawPtr->getButtonZAlpha() != 1.f) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); return; } // The game will crash if trying to quick transform while holding the Ball and Chain if (mEquipItem == dItemNo_IRONBALL_e) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); return; } // Use the game's default checks for if the player can currently transform if (!m_midnaActor->checkMetamorphoseEnableBase()) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + return; + } + + bool canTransform = false; + + if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { + if (!checkForestOldCentury()) { + if (checkMidnaRide()) { + if ((checkWolf() && + (checkModeFlg(MODE_UNK_1000) || dComIfGp_checkPlayerStatus0(0, 0x10))) || + (!checkWolf() && + (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && + (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) + { + canTransform = true; + } + } + } + } + + if (!canTransform) + { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); return; } diff --git a/src/d/actor/d_a_midna.cpp b/src/d/actor/d_a_midna.cpp index 88a5bb38bb..c63f4e5251 100644 --- a/src/d/actor/d_a_midna.cpp +++ b/src/d/actor/d_a_midna.cpp @@ -3046,12 +3046,17 @@ void daMidna_c::setMidnaNoDrawFlg() { BOOL daMidna_c::checkMetamorphoseEnableBase() { BOOL tmp; - if ( - !daAlink_getAlinkActorClass()->checkMidnaRide() || (g_env_light.mEvilInitialized & 0x80) || + if (!daAlink_getAlinkActorClass()->checkMidnaRide() || (g_env_light.mEvilInitialized & 0x80) || /* dSv_event_flag_c::M_077 - Main Event - Get shadow crystal (can now transform) */ !dComIfGs_isEventBit(0xD04) || +#if TARGET_PC + (fopAcIt_Judge((fopAcIt_JudgeFunc)daMidna_searchNpc, &tmp) && + !dusk::getSettings().game.canTransformAnywhere) +#else fopAcIt_Judge((fopAcIt_JudgeFunc)daMidna_searchNpc, &tmp) - ) { +#endif + ) + { return FALSE; } return TRUE; diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index cf7fcc41d7..7f96becd75 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -70,6 +70,12 @@ namespace dusk { if (ImGui::BeginMenu("Cheats")) { ImGui::Checkbox("Fast Iron Boots", &getSettings().game.enableFastIronBoots); + ImGui::Checkbox("Can Transform Anywhere", + &getSettings().game.canTransformAnywhere); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Allows you to transform between forms even if NPCs are looking"); + } + ImGui::EndMenu(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index ea17eef374..1ac11bdeb7 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -43,6 +43,7 @@ UserSettings g_userSettings = { // Cheats .enableFastIronBoots = false, + .canTransformAnywhere = false, // Technical .restoreWiiGlitches = false, From 35337d556969b12ab7b9ca5640f8d4552d8e0c3a Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 14:31:16 -0400 Subject: [PATCH 06/20] removed period in description --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index a0559c89b4..6a84e020c4 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -70,7 +70,7 @@ namespace dusk { if (ImGui::BeginMenu("Audio")) { ImGui::Checkbox("Non-Stop Midna's Lament", &getSettings().game.midnasLamentNonStop); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing."); + ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing"); } ImGui::EndMenu(); From d0afac0fba1cac5468451b73ddab97b71e410e3f Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 14:31:40 -0400 Subject: [PATCH 07/20] removed period in description --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index ec0a249f9f..20ba760e83 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -40,7 +40,7 @@ namespace dusk { ImGui::Checkbox("No Climbing Miss Animation", &getSettings().game.noMissClimbing); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Prevents Link from playing a struggle animation\n" - "when using the Clawshot on vines at a weird angle."); + "when using the Clawshot on vines at a weird angle"); } ImGui::Checkbox("Faster Tears of Light", &getSettings().game.fastTears); From 3dca79e3754e8e155b8296dde975ab86d375922f Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 4 Apr 2026 14:47:39 -0400 Subject: [PATCH 08/20] No Low HP Sound Enhancement --- include/dusk/settings.h | 3 +++ src/Z2AudioLib/Z2AudioMgr.cpp | 7 +++++++ src/dusk/imgui/ImGuiMenuEnhancements.cpp | 9 +++++++++ src/dusk/settings.cpp | 3 +++ 4 files changed, 22 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 582c5a1872..aaff862284 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -45,6 +45,9 @@ struct UserSettings { bool enableBloom; bool useWaterProjectionOffset; + // Audio + bool noLowHpSound; + // Cheats bool enableFastIronBoots; diff --git a/src/Z2AudioLib/Z2AudioMgr.cpp b/src/Z2AudioLib/Z2AudioMgr.cpp index 985c500aec..d6d78fb4b7 100644 --- a/src/Z2AudioLib/Z2AudioMgr.cpp +++ b/src/Z2AudioLib/Z2AudioMgr.cpp @@ -155,7 +155,14 @@ void Z2AudioMgr::zeldaGFrameWork() { mSpeechMgr.framework(); processSeFramework(); processBgmFramework(); + + #if TARGET_PC + if (!dusk::getSettings().game.noLowHpSound) { + processHeartGaugeSound(); + } + #else processHeartGaugeSound(); + #endif #if DEBUG mDebugSys.debugframework(); diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index cf7fcc41d7..b7309e0846 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -67,6 +67,15 @@ namespace dusk { ImGui::EndMenu(); } + if (ImGui::BeginMenu("Audio")) { + ImGui::Checkbox("No Low HP Sound", &getSettings().game.noLowHpSound); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Disable the beeping sound when having low health"); + } + + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Cheats")) { ImGui::Checkbox("Fast Iron Boots", &getSettings().game.enableFastIronBoots); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index ea17eef374..625fb114ed 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -41,6 +41,9 @@ UserSettings g_userSettings = { .enableBloom = true, .useWaterProjectionOffset = false, + // Audio + .noLowHpSound = false, + // Cheats .enableFastIronBoots = false, From ebc37b934d5c08e597e0134f65a217314a0bb9ed Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 15:59:18 -0700 Subject: [PATCH 09/20] better reverb --- src/dusk/audio/DuskDsp.cpp | 36 ++++++++++++++++++++++++------------ src/dusk/audio/DuskDsp.hpp | 2 +- src/dusk/settings.cpp | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index fd1ae66620..3ca34bfa20 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -139,20 +139,32 @@ void dusk::audio::DspRender(OutputSubframe& subframe) { if (!skipRender) { ValidateChannel(channel); RenderChannel(channel, channelAux, channelSubframe); - // todo figure out an actual way to convert this accurately to dry/wet - channelAux.reverb.setwet(((channel.mAutoMixerFxMix >> 8) / 255.0f)); - channelAux.reverb.setdry(1.0f - channelAux.reverb.getwet()); } if (EnableReverb) { + // scale the input to the reverb rather than using wet/dry on the output. + // this way the reverb's internal buffers accumulate energy proportional to mAutoMixerFxMix, + // so any tail always decays at the correct level regardless of mAutoMixerFxMix changes + // prevents transients when the next sound starts playing with a different reverb level + // 700.0f was pulled out of my ass and just sounds good enough for console + f32 inputGain = (!skipRender) ? (channel.mAutoMixerFxMix >> 8) / 700.0f : 0.0f; + + OutputSubframe reverbSubframe = {}; + for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { + reverbSubframe.channels[0][j] = channelSubframe.channels[0][j] * inputGain; + reverbSubframe.channels[1][j] = channelSubframe.channels[1][j] * inputGain; + } + channelAux.reverb.processreplace( - channelSubframe.channels[0].data(), - channelSubframe.channels[1].data(), - channelSubframe.channels[0].data(), - channelSubframe.channels[1].data(), - DSP_SUBFRAME_SIZE, - 1 + reverbSubframe.channels[0].data(), reverbSubframe.channels[1].data(), + reverbSubframe.channels[0].data(), reverbSubframe.channels[1].data(), + DSP_SUBFRAME_SIZE, 1 ); + + for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { + channelSubframe.channels[0][j] += reverbSubframe.channels[0][j]; + channelSubframe.channels[1][j] += reverbSubframe.channels[1][j]; + } } for (int o = 0; o < subframe.channels.size(); o++) { @@ -481,10 +493,10 @@ static void RenderChannel( void dusk::audio::DspInit() { for (int i = 0; i < DSP_CHANNELS; i++) { auto& channelAux = ChannelAux[i]; - channelAux.reverb.setwet(0.0f); - channelAux.reverb.setdry(1.0f); + channelAux.reverb.setwet(1.0f); + channelAux.reverb.setdry(0.0f); channelAux.reverb.setroomsize(0.2f); - channelAux.reverb.setdamp(0.3f); + channelAux.reverb.setdamp(0.7f); channelAux.reverb.setwidth(1.0f); channelAux.reverb.setmode(0.0f); channelAux.reverb.mute(); diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp index 3c414375f3..520a948208 100644 --- a/src/dusk/audio/DuskDsp.hpp +++ b/src/dusk/audio/DuskDsp.hpp @@ -54,7 +54,7 @@ namespace dusk::audio { // basically stores our position between resamplePrev and decodeBuf[0] so we don't lose that fractional resampler position next subframe f32 resamplePos; // last consumed sample from decodeBuf - s16 resamplePrev; + s16 resamplePrev; }; extern ChannelAuxData ChannelAux[DSP_CHANNELS]; diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index ed2071ca30..14269e833b 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -12,7 +12,7 @@ UserSettings g_userSettings = { // Audio .audio = { - .masterVolume = 1.0f, + .masterVolume =0.8f, .mainMusicVolume = 1.0f, .subMusicVolume = 1.0f, .soundEffectsVolume = 1.0f, From 37ab09ec1d2f3264036d87c7fdea7ab57525a81d Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 16:07:36 -0700 Subject: [PATCH 10/20] h --- src/dusk/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 14269e833b..db1e9e8b92 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -12,7 +12,7 @@ UserSettings g_userSettings = { // Audio .audio = { - .masterVolume =0.8f, + .masterVolume = 0.8f, .mainMusicVolume = 1.0f, .subMusicVolume = 1.0f, .soundEffectsVolume = 1.0f, From 29ea44fc1d934ae5bf5e9f35b40576b8e014edad Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 17:14:09 -0700 Subject: [PATCH 11/20] dump audio and bigger room size --- src/dusk/audio/DuskAudioSystem.cpp | 16 ------------ src/dusk/audio/DuskDsp.cpp | 40 +++++++++++++++++++++++++++++- src/dusk/audio/DuskDsp.hpp | 1 + src/dusk/imgui/ImGuiAudio.cpp | 2 ++ 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/dusk/audio/DuskAudioSystem.cpp b/src/dusk/audio/DuskAudioSystem.cpp index 93e161512f..c7313749c2 100644 --- a/src/dusk/audio/DuskAudioSystem.cpp +++ b/src/dusk/audio/DuskAudioSystem.cpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include "JSystem/JAudio2/JASAiCtrl.h" @@ -17,8 +15,6 @@ #include "JSystem/JAudio2/JASAudioThread.h" #include "JSystem/JAudio2/JASDriverIF.h" -// #define DUSK_DUMP_AUDIO - using namespace dusk::audio; static OutputSubframe OutBuffer; @@ -91,10 +87,6 @@ void SDLCALL GetNewAudio( } } -#if defined(DUSK_DUMP_AUDIO) -static std::ofstream outRaw("guh.raw", std::ios_base::out | std::ios_base::binary); -#endif - int RenderNewAudioFrame() { JASCriticalSection section; const u32 countSubframes = JASDriver::getSubFrames(); @@ -107,10 +99,6 @@ int RenderNewAudioFrame() { JASAudioThread::snIntCount -= 1; } -#if defined(DUSK_DUMP_AUDIO) - outRaw.flush(); -#endif - return static_cast(countSubframes) * DSP_SUBFRAME_SIZE; } @@ -147,10 +135,6 @@ void RenderAudioSubframe() { } } -#if defined(DUSK_DUMP_AUDIO) - outRaw.write((const char*)OutInterleaveBuffer.data(), sizeof(OutInterleaveBuffer)); -#endif - SDL_PutAudioStreamData(PlaybackStream, &OutInterleaveBuffer, sizeof(OutInterleaveBuffer)); } diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index 3ca34bfa20..e104749991 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "Adpcm.hpp" @@ -17,9 +18,30 @@ using namespace dusk::audio; ChannelAuxData dusk::audio::ChannelAux[DSP_CHANNELS] = {}; +static bool sDumpWasActive = false; +static FILE* sChannelDumpFiles[DSP_CHANNELS] = {}; + +static void OpenChannelDumpFiles() { + char name[32]; + for (int i = 0; i < DSP_CHANNELS; i++) { + snprintf(name, sizeof(name), "channel_%02d.raw", i); + sChannelDumpFiles[i] = fopen(name, "wb"); + } +} + +static void CloseChannelDumpFiles() { + for (int i = 0; i < DSP_CHANNELS; i++) { + if (sChannelDumpFiles[i]) { + fclose(sChannelDumpFiles[i]); + sChannelDumpFiles[i] = nullptr; + } + } +} + f32 dusk::audio::MasterVolume = 1.0f; f32 dusk::audio::PrevMasterVolume = 1.0f; bool dusk::audio::EnableReverb = true; +bool dusk::audio::DumpAudio = false; /** * Validate that a DSP channel's format is actually something we know how to play. @@ -107,6 +129,15 @@ static void MixSubframe(DspSubframe& dst, const DspSubframe& src) { } void dusk::audio::DspRender(OutputSubframe& subframe) { + if (DumpAudio != sDumpWasActive) { + sDumpWasActive = DumpAudio; + if (DumpAudio) { + OpenChannelDumpFiles(); + } else { + CloseChannelDumpFiles(); + } + } + std::span channels(JASDsp::CH_BUF, DSP_CHANNELS); for (int i = 0; i < channels.size(); i++) { @@ -167,6 +198,13 @@ void dusk::audio::DspRender(OutputSubframe& subframe) { } } + if (DumpAudio && sChannelDumpFiles[i]) { + for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { + fwrite(&channelSubframe.channels[0][j], sizeof(f32), 1, sChannelDumpFiles[i]); + fwrite(&channelSubframe.channels[1][j], sizeof(f32), 1, sChannelDumpFiles[i]); + } + } + for (int o = 0; o < subframe.channels.size(); o++) { MixSubframe(subframe.channels[o], channelSubframe.channels[o]); } @@ -495,7 +533,7 @@ void dusk::audio::DspInit() { auto& channelAux = ChannelAux[i]; channelAux.reverb.setwet(1.0f); channelAux.reverb.setdry(0.0f); - channelAux.reverb.setroomsize(0.2f); + channelAux.reverb.setroomsize(0.4f); channelAux.reverb.setdamp(0.7f); channelAux.reverb.setwidth(1.0f); channelAux.reverb.setmode(0.0f); diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp index 520a948208..036a4bb9f0 100644 --- a/src/dusk/audio/DuskDsp.hpp +++ b/src/dusk/audio/DuskDsp.hpp @@ -122,4 +122,5 @@ namespace dusk::audio { extern f32 MasterVolume; extern f32 PrevMasterVolume; extern bool EnableReverb; + extern bool DumpAudio; } diff --git a/src/dusk/imgui/ImGuiAudio.cpp b/src/dusk/imgui/ImGuiAudio.cpp index ae01f119f4..3328d1b97c 100644 --- a/src/dusk/imgui/ImGuiAudio.cpp +++ b/src/dusk/imgui/ImGuiAudio.cpp @@ -8,6 +8,7 @@ #include "JSystem/JAudio2/JASDSPInterface.h" #include "JSystem/JAudio2/JASTrack.h" #include "dusk/audio/DuskAudioSystem.h" +#include "dusk/audio/DuskDsp.hpp" static std::array channelSortIndices = {}; static std::array lastResetCounts = {}; @@ -102,6 +103,7 @@ static void ShowAllDspChannels() { } ImGui::Text("Active channels: %d", activeChannels); + ImGui::Checkbox("Dump channels to disk", &dusk::audio::DumpAudio); ImGui::Checkbox("Sort by update count", &sortUpdateCount); if (sortUpdateCount) { From cf30230501c458b4f1e7edd74036d30271e6719f Mon Sep 17 00:00:00 2001 From: Irastris Date: Sun, 5 Apr 2026 01:19:53 -0400 Subject: [PATCH 12/20] Fix building again & minor reformatting --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 805334b1a0..5f8ec912a2 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -52,11 +52,16 @@ namespace dusk { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Hides the TV calibration screen shown when loading a save"); } + ImGui::EndMenu(); } if (ImGui::BeginMenu("Preferences")) { ImGui::Checkbox("Mirror Mode", &getSettings().game.enableMirrorMode); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Mirrors the world, matching the Wii version of the game"); + } + ImGui::Checkbox("Invert Camera X Axis", &getSettings().game.invertCameraXAxis); ImGui::EndMenu(); @@ -64,10 +69,11 @@ namespace dusk { if (ImGui::BeginMenu("Graphics")) { ImGui::Checkbox("Native Bloom", &getSettings().game.enableBloom); + ImGui::Checkbox("Water Projection Offset", &getSettings().game.useWaterProjectionOffset); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n" - "that causes ~6px ghost artifacts in water reflections"); + "that causes ~6px ghost artifacts in water reflections"); } ImGui::EndMenu(); @@ -77,7 +83,8 @@ namespace dusk { ImGui::Checkbox("No Low HP Sound", &getSettings().game.noLowHpSound); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Disable the beeping sound when having low health"); - + } + ImGui::Checkbox("Non-Stop Midna's Lament", &getSettings().game.midnasLamentNonStop); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing"); @@ -89,10 +96,10 @@ namespace dusk { if (ImGui::BeginMenu("Cheats")) { ImGui::Checkbox("Fast Iron Boots", &getSettings().game.enableFastIronBoots); - ImGui::Checkbox("Can Transform Anywhere", - &getSettings().game.canTransformAnywhere); + ImGui::Checkbox("Can Transform Anywhere", &getSettings().game.canTransformAnywhere); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Allows you to transform between forms even if NPCs are looking"); + ImGui::SetTooltip( + "Allows you to transform between forms even if NPCs are looking"); } ImGui::EndMenu(); @@ -100,6 +107,7 @@ namespace dusk { if (ImGui::BeginMenu("Difficulty")) { ImGui::SliderInt("Damage Multiplier", &getSettings().game.damageMultiplier, 1, 8, "x%d"); + ImGui::Checkbox("Instant Death", &getSettings().game.instantDeath); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Any hit will instantly kill you"); @@ -111,13 +119,12 @@ namespace dusk { if (ImGui::BeginMenu("Technical")) { ImGui::Checkbox("Restore Wii 1.0 Glitches", &getSettings().game.restoreWiiGlitches); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0, the first released version"); + ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" + "the first released version"); } ImGui::EndMenu(); } - - ImGui::EndMenu(); } } } From 6857c54695e448aad2770039b1fc39c3c7531f1f Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 22:22:18 -0700 Subject: [PATCH 13/20] fix .clangd on vscode --- CMakeLists.txt | 1 + compile_flags.txt | 12 ++++++++++++ extern/aurora | 2 +- libs/freeverb/CMakeLists.txt | 4 ---- src/dusk/audio/DuskDsp.hpp | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 compile_flags.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 272ff76db3..a8a861514f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,7 @@ target_include_directories(game_debug PUBLIC src assets/${DUSK_TP_VERSION} libs/JSystem/include + libs extern/aurora/include/dolphin extern ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000000..120832b8cb --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,12 @@ +--std=c++20 +-DTARGET_PC +-DAVOID_UB=1 +-DVERSION=0 +-Iinclude +-Isrc +-Ilibs/JSystem/include +-Ilibs +-Iextern/aurora/include/dolphin +-Iextern/aurora/include +-Iextern +-Ibuild/GZ2E01/include diff --git a/extern/aurora b/extern/aurora index b17da31593..37631c3bf3 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit b17da315932b85d7d708eaf3e44914f70045a44e +Subproject commit 37631c3bf382c1564d3f29c4c3f2dc6cf7617fa9 diff --git a/libs/freeverb/CMakeLists.txt b/libs/freeverb/CMakeLists.txt index c4f4d4ed95..c0c12da293 100644 --- a/libs/freeverb/CMakeLists.txt +++ b/libs/freeverb/CMakeLists.txt @@ -7,7 +7,3 @@ add_library(freeverb allpass.cpp revmodel.cpp ) - -target_include_directories(freeverb PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} -) diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp index 036a4bb9f0..728234b75c 100644 --- a/src/dusk/audio/DuskDsp.hpp +++ b/src/dusk/audio/DuskDsp.hpp @@ -8,7 +8,7 @@ #include "SDL3/SDL_audio.h" #include -#include "revmodel.hpp" +#include "freeverb/revmodel.hpp" // ReSharper disable once CppUnusedIncludeDirective #include "global.h" From 78e7c3ced9c2e7d678fe77c445e61275b6ab834f Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 22:22:34 -0700 Subject: [PATCH 14/20] a --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 37631c3bf3..b17da31593 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 37631c3bf382c1564d3f29c4c3f2dc6cf7617fa9 +Subproject commit b17da315932b85d7d708eaf3e44914f70045a44e From a52dffe9a87967b1318588241e14ba985c6fd761 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sun, 5 Apr 2026 01:23:49 -0400 Subject: [PATCH 15/20] I hate you VS --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 5f8ec912a2..3607214f4b 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -98,8 +98,7 @@ namespace dusk { ImGui::Checkbox("Can Transform Anywhere", &getSettings().game.canTransformAnywhere); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip( - "Allows you to transform between forms even if NPCs are looking"); + ImGui::SetTooltip("Allows you to transform even if NPCs are looking"); } ImGui::EndMenu(); From 05b1b29cb9ee0c3aed3c09bafa3d12ddf0e96381 Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 22:45:00 -0700 Subject: [PATCH 16/20] fix clangd for vscode and remove win platform variants since thats done through environment on windows --- .vscode/settings.json | 10 +++++++--- cmake-variants.yaml | 16 ---------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4573e4a21c..bacff1eb9b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,10 @@ { - "cmake.buildDirectory": "${workspaceFolder}/build/dusk/${buildType}/${variant:platform}/${variant:tp_version}", + "cmake.buildDirectory": "${workspaceFolder}/build/dusk/${buildType}/${variant:tp_version}", + "cmake.generator": "Ninja", + "cmake.configureSettings": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + }, + "cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json", "[c]": { "files.encoding": "utf8", "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" @@ -44,8 +49,7 @@ "build.ninja": true, ".ninja_*": true, "objdiff.json": true, - ".cache/**": true, - "compile_commands.json": true, + ".cache/**": true }, "clangd.arguments": [ "--function-arg-placeholders=0", diff --git a/cmake-variants.yaml b/cmake-variants.yaml index f9f6ad51bd..62d2642311 100644 --- a/cmake-variants.yaml +++ b/cmake-variants.yaml @@ -14,22 +14,6 @@ buildType: long: Optimized, with debug symbols buildType: RelWithDebInfo -platform: - default: win64 - description: Target platform - choices: - win32: - short: Win32 - long: Windows 32-bit (MSVC) - settings: - CMAKE_GENERATOR_PLATFORM: Win32 - - win64: - short: Win64 - long: Windows 64-bit (MSVC) - settings: - CMAKE_GENERATOR_PLATFORM: x64 - tp_version: default: GZ2E01 description: TP Version From de038222acd3ac4ab2f3273111a9ac7cef487d85 Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 22:45:35 -0700 Subject: [PATCH 17/20] no longer needed --- compile_flags.txt | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 compile_flags.txt diff --git a/compile_flags.txt b/compile_flags.txt deleted file mode 100644 index 120832b8cb..0000000000 --- a/compile_flags.txt +++ /dev/null @@ -1,12 +0,0 @@ ---std=c++20 --DTARGET_PC --DAVOID_UB=1 --DVERSION=0 --Iinclude --Isrc --Ilibs/JSystem/include --Ilibs --Iextern/aurora/include/dolphin --Iextern/aurora/include --Iextern --Ibuild/GZ2E01/include From a8e136c2c9a6de88f42ea564c96bd34c916e4f6e Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Sun, 5 Apr 2026 07:46:28 +0200 Subject: [PATCH 18/20] Fixes #207 (A bug I brought myself in :( ) --- src/d/d_kankyo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index eb1900dc4e..ec35ee8bc7 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -9696,7 +9696,7 @@ void dKy_ParticleColor_get_base(cXyz* param_0, dKy_tevstr_c* param_1, GXColor* p f32 var_f31; #if AVOID_UB - var_f31 = 0; + var_f31 = 100000000.0f; #endif if (dKy_SunMoon_Light_Check() == TRUE && i <= 1) { From 1d98db6d131c7bc1bcaa5fa84f752d8ced215d77 Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 4 Apr 2026 23:04:08 -0700 Subject: [PATCH 19/20] make the reverb sound slightly more accurate --- src/dusk/audio/DuskDsp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp index e104749991..3e32d3e7ff 100644 --- a/src/dusk/audio/DuskDsp.cpp +++ b/src/dusk/audio/DuskDsp.cpp @@ -177,8 +177,8 @@ void dusk::audio::DspRender(OutputSubframe& subframe) { // this way the reverb's internal buffers accumulate energy proportional to mAutoMixerFxMix, // so any tail always decays at the correct level regardless of mAutoMixerFxMix changes // prevents transients when the next sound starts playing with a different reverb level - // 700.0f was pulled out of my ass and just sounds good enough for console - f32 inputGain = (!skipRender) ? (channel.mAutoMixerFxMix >> 8) / 700.0f : 0.0f; + // 600.0f was pulled out of my ass and just sounds good enough for console + f32 inputGain = (!skipRender) ? (channel.mAutoMixerFxMix >> 8) / 600.0f : 0.0f; OutputSubframe reverbSubframe = {}; for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { @@ -533,7 +533,7 @@ void dusk::audio::DspInit() { auto& channelAux = ChannelAux[i]; channelAux.reverb.setwet(1.0f); channelAux.reverb.setdry(0.0f); - channelAux.reverb.setroomsize(0.4f); + channelAux.reverb.setroomsize(0.5f); channelAux.reverb.setdamp(0.7f); channelAux.reverb.setwidth(1.0f); channelAux.reverb.setmode(0.0f); From 574d980b23173236c38a65957cdc8d9714f85456 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sun, 5 Apr 2026 02:23:55 -0400 Subject: [PATCH 20/20] Fix enhancements menu v3_reallyforreal_final_v02 --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 3607214f4b..3069d9b3f6 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -124,6 +124,8 @@ namespace dusk { ImGui::EndMenu(); } + + ImGui::EndMenu(); } } }