From 4f9d63d357dfbdf3f08a7294eb2fbc7ccfe790cf Mon Sep 17 00:00:00 2001 From: robojumper Date: Wed, 9 Jul 2025 00:30:48 +0200 Subject: [PATCH] d_snd_bgm_sound_battle OK --- config/SOUE01/symbols.txt | 12 +++--- configure.py | 2 +- include/d/snd/d_snd_bgm_harp_data.h | 4 ++ include/d/snd/d_snd_bgm_mgr.h | 2 +- include/d/snd/d_snd_bgm_seq_config.h | 6 +-- include/d/snd/d_snd_bgm_sound.h | 4 +- include/d/snd/d_snd_bgm_sound_battle.h | 13 +++++- src/d/snd/d_snd_bgm_mgr.cpp | 2 +- src/d/snd/d_snd_bgm_mml_parsers.cpp | 24 +++++------ src/d/snd/d_snd_bgm_sound.cpp | 38 +++++++++-------- src/d/snd/d_snd_bgm_sound_battle.cpp | 58 ++++++++++++++++++++++++-- 11 files changed, 115 insertions(+), 50 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index a76b1ec3..dc814f19 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -20755,12 +20755,12 @@ __ct__20dSndBgmBattleSound_cFv = .text:0x8037B4E0; // type:function size:0x58 cancel__20dSndBgmBattleSound_cFv = .text:0x8037B540; // type:function size:0x44 loadSeqConfig__20dSndBgmBattleSound_cFUl = .text:0x8037B590; // type:function size:0x7C fadeIn__20dSndBgmBattleSound_cFUll = .text:0x8037B610; // type:function size:0xAC -fn_8037B6C0 = .text:0x8037B6C0; // type:function size:0x18 -fn_8037B6E0 = .text:0x8037B6E0; // type:function size:0x18 -fn_8037B700 = .text:0x8037B700; // type:function size:0xB0 +setTrackGroupMuted__20dSndBgmBattleSound_cFUl = .text:0x8037B6C0; // type:function size:0x18 +setTrackGroupUnmuted__20dSndBgmBattleSound_cFUl = .text:0x8037B6E0; // type:function size:0x18 +startMainBattleLoop__20dSndBgmBattleSound_cFv = .text:0x8037B700; // type:function size:0xB0 calcSeqPlaySamplePosition__20dSndBgmBattleSound_cFv = .text:0x8037B7B0; // type:function size:0x134 -postCalc__20dSndBgmBattleSound_cFv = .text:0x8037B8F0; // type:function size:0x10 -isBattleBgmSound__20dSndBgmBattleSound_cCFv = .text:0x8037B900; // type:function size:0x8 +postCalc__20dSndBgmBattleSound_cFv = .text:0x8037B8F0; // type:function size:0x10 scope:weak +isBattleBgmSound__20dSndBgmBattleSound_cCFv = .text:0x8037B900; // type:function size:0x8 scope:weak __ct__21dSndBgmSoundHarpMgr_cFv = .text:0x8037B910; // type:function size:0x54 setSoundId__21dSndBgmSoundHarpMgr_cFUl = .text:0x8037B970; // type:function size:0x8 setLoaded__21dSndBgmSoundHarpMgr_cFv = .text:0x8037B980; // type:function size:0xC @@ -38040,7 +38040,7 @@ lbl_80549068 = .data:0x80549068; // type:object size:0x10 lbl_80549078 = .data:0x80549078; // type:object size:0x10 lbl_80549088 = .data:0x80549088; // type:object size:0x34 __vt__14dSndBgmSound_c = .data:0x805490BC; // type:object size:0x44 -__vt__20dSndBgmBattleSound_c = .data:0x80549100; // type:object size:0x48 +__vt__20dSndBgmBattleSound_c = .data:0x80549100; // type:object size:0x44 __vt__37SndMgrDisposer<19dSndBgmSeqDataMgr_c> = .data:0x80549148; // type:object size:0xC scope:weak __vt__18dSndBgmMmlParser_c = .data:0x80549158; // type:object size:0x10 lbl_80549168 = .data:0x80549168; // type:object size:0x10 diff --git a/configure.py b/configure.py index 7be44e87..d17077eb 100644 --- a/configure.py +++ b/configure.py @@ -757,7 +757,7 @@ config.libs = [ Object(NonMatching, "d/snd/d_snd_bgm_sound_callbacks.cpp"), Object(NonMatching, "d/snd/d_snd_bgm_sound_battle_callbacks.cpp"), Object(NonMatching, "d/snd/d_snd_bgm_sound.cpp"), - Object(NonMatching, "d/snd/d_snd_bgm_sound_battle.cpp"), + Object(Matching, "d/snd/d_snd_bgm_sound_battle.cpp"), Object(Matching, "d/snd/d_snd_bgm_sound_harp_mgr.cpp"), Object(Matching, "d/snd/d_snd_bgm_seq_data_mgr.cpp"), Object(NonMatching, "d/snd/d_snd_bgm_reverb.cpp"), diff --git a/include/d/snd/d_snd_bgm_harp_data.h b/include/d/snd/d_snd_bgm_harp_data.h index b2f9cdd9..fc62f9ab 100644 --- a/include/d/snd/d_snd_bgm_harp_data.h +++ b/include/d/snd/d_snd_bgm_harp_data.h @@ -15,6 +15,10 @@ * G3-C4-E4-G4-B4-C5-E5-G5-B5-C6-E6-G6 * B3 is missing, possibly to prevent dissonance at the ends of the scale. * (Sealed Grounds, before Demise fight, no actual BGM) + * + * TODO: This deals with slightly more than the harp. It additionally + * also deals with the combat hit sounds that also seem to match up in + * pitch with the BGM. */ /** diff --git a/include/d/snd/d_snd_bgm_mgr.h b/include/d/snd/d_snd_bgm_mgr.h index 5a4400be..ff05db51 100644 --- a/include/d/snd/d_snd_bgm_mgr.h +++ b/include/d/snd/d_snd_bgm_mgr.h @@ -100,7 +100,7 @@ private: bool prepareBgmSound(u32 soundId, dSndBgmSound_c *handle, u32 startOffset); bool startAdditionalBgm(u32 soundId); - bool playBattleBgm(u32 soundId, bool immediately); + bool playBattleBgm(u32 soundId, bool intense); /** Used to mute other BGM when battle music is playing */ void setBgmHandleIdxVolume(u32 handleIdx, f32 volume, s32 fadeFrames); diff --git a/include/d/snd/d_snd_bgm_seq_config.h b/include/d/snd/d_snd_bgm_seq_config.h index b66e9275..a66a8131 100644 --- a/include/d/snd/d_snd_bgm_seq_config.h +++ b/include/d/snd/d_snd_bgm_seq_config.h @@ -6,9 +6,9 @@ struct dSndBgmSeqConfig { /* 0x00 */ u32 soundId; /* 0x04 */ s32 field_0x04; - /* 0x08 */ s32 field_0x08; - /* 0x0C */ u16 field_0x0C; - /* 0x0E */ u16 field_0x0E; + /* 0x08 */ s32 mTimebase; + /* 0x0C */ u16 mLoopStart; + /* 0x0E */ u16 mLoopEnd; static const dSndBgmSeqConfig *getConfig(u32 soundId, s32 unkParam); diff --git a/include/d/snd/d_snd_bgm_sound.h b/include/d/snd/d_snd_bgm_sound.h index 4e76137c..09403fb7 100644 --- a/include/d/snd/d_snd_bgm_sound.h +++ b/include/d/snd/d_snd_bgm_sound.h @@ -77,8 +77,8 @@ protected: /* 0x108 */ s32 mSeqTempo; /* 0x10C */ u32 mBgmFlags; /* 0x110 */ bool mDidRewindPlaySamplePosition; - /* 0x114 */ s32 field_0x114; - /* 0x118 */ s32 field_0x118; + /* 0x114 */ s32 mBgmVar3; + /* 0x118 */ s32 mSeqTimebase; /* 0x11C */ u32 mPlaySamplePosition; /* 0x120 */ dSndBgmSoundHarpMgr_c mHarpMgr; /* 0x140 */ dSndBgmSoundHarpMgr_c *mpHarpMgr; diff --git a/include/d/snd/d_snd_bgm_sound_battle.h b/include/d/snd/d_snd_bgm_sound_battle.h index 047832e5..f18fa7be 100644 --- a/include/d/snd/d_snd_bgm_sound_battle.h +++ b/include/d/snd/d_snd_bgm_sound_battle.h @@ -20,10 +20,19 @@ public: virtual void calcSeqPlaySamplePosition() override; // vt 0x3C virtual void loadCallbacks(u32 soundId) override; // vt 0x40 + /** + * Called when the player is even closer to an enemy. + * Adds some more instruments to the battle sound. + */ + bool startMainBattleLoop(); + private: + void setTrackGroupMuted(u32 groupId); + void setTrackGroupUnmuted(u32 groupId); + /* 0x184 */ const dSndBgmBattleConfig *mpBgmBattleConfig; - /* 0x188 */ u32 mMuteApplyStateMask; - /* 0x18C */ u32 mTickRelated; + /* 0x188 */ u32 mMuteGroupActiveMask; + /* 0x18C */ u32 mPrevTick; /* 0x190 */ u8 field_0x190; /* 0x191 */ u8 field_0x191; }; diff --git a/src/d/snd/d_snd_bgm_mgr.cpp b/src/d/snd/d_snd_bgm_mgr.cpp index dcfcb3ac..a972531c 100644 --- a/src/d/snd/d_snd_bgm_mgr.cpp +++ b/src/d/snd/d_snd_bgm_mgr.cpp @@ -1,7 +1,7 @@ #include "d/snd/d_snd_bgm_mgr.h" #include "common.h" -#include "d/snd/d_snd_bgm_sound battle.h" +#include "d/snd/d_snd_bgm_sound_battle.h" #include "d/snd/d_snd_bgm_sound.h" #include "d/snd/d_snd_mgr.h" #include "d/snd/d_snd_player_mgr.h" diff --git a/src/d/snd/d_snd_bgm_mml_parsers.cpp b/src/d/snd/d_snd_bgm_mml_parsers.cpp index e8797706..8e996ed6 100644 --- a/src/d/snd/d_snd_bgm_mml_parsers.cpp +++ b/src/d/snd/d_snd_bgm_mml_parsers.cpp @@ -1,9 +1,9 @@ #include "d/snd/d_snd_bgm_mml_parsers.h" #include "common.h" -#include "d/snd/d_snd_mgr.h" -#include "d/snd/d_snd_bgm_sound_harp_mgr.h" #include "d/snd/d_snd_bgm_seq_data_mgr.h" +#include "d/snd/d_snd_bgm_sound_harp_mgr.h" +#include "d/snd/d_snd_mgr.h" #include "d/snd/d_snd_player_mgr.h" #include "nw4r/snd/snd_SoundArchive.h" #include "sized_string.h" @@ -23,7 +23,8 @@ bool dSndBgmMmlParserHarp_c::parseData(const char *soundLabel, u32 baseSoundId, SizedString<64> dataLabel; dataLabel.sprintf("%s%s", dSndBgmSeqDataMgr_c::getDataPrefix(), soundLabel); u32 dataId = dSndPlayerMgr_c::GetInstance()->convertLabelStringToSoundId(dataLabel); - if (dataId != -1 && dSndMgr_c::GetInstance()->getArchive()->GetSoundType(dataId) == nw4r::snd::SoundArchive::SOUND_TYPE_SEQ) { + if (dataId != -1 && + dSndMgr_c::GetInstance()->getArchive()->GetSoundType(dataId) == nw4r::snd::SoundArchive::SOUND_TYPE_SEQ) { ok = loadAndParse(dataId, trackMask, true); if (ok) { field_0x294->setSoundId(baseSoundId); @@ -53,22 +54,17 @@ void dSndBgmMmlParserHarp_c::CommandProc(u32 trackNo, int wait, u32 command, s32 } break; default: - if (command == MML_SET_TEMPO) { - field_0x294->setTempo(commandArg1); - } - break; - + if (command == MML_SET_TEMPO) { + field_0x294->setTempo(commandArg1); + } + break; } } void dSndBgmMmlParserHarp_c::NoteOnCommandProc(u32 trackNo, int wait, int key, int velocity, s32 length) const { // TODO type switch ((s32)trackNo) { - case 15: - field_0x298->addVar(wait, key, velocity); - break; - default: - break; - + case 15: field_0x298->addVar(wait, key, velocity); break; + default: break; } } diff --git a/src/d/snd/d_snd_bgm_sound.cpp b/src/d/snd/d_snd_bgm_sound.cpp index e6e8a78e..60a717bc 100644 --- a/src/d/snd/d_snd_bgm_sound.cpp +++ b/src/d/snd/d_snd_bgm_sound.cpp @@ -29,8 +29,8 @@ dSndBgmSound_c::dSndBgmSound_c() mSeqTempo(-1), mBgmFlags(0), mDidRewindPlaySamplePosition(false), - field_0x114(-1), - field_0x118(0x180), + mBgmVar3(-1), + mSeqTimebase(0x180), mPlaySamplePosition(0), mpHarpMgr(&mHarpMgr), mpSeqConfig(nullptr), @@ -71,9 +71,9 @@ void dSndBgmSound_c::cancel() { mpSeqConfig = nullptr; mPlaySamplePosition = 0; mSeqPlaySamplePosition = -1; - field_0x114 = -1; + mBgmVar3 = -1; mSeqTempo = -1; - field_0x118 = 0x180; + mSeqTimebase = 0x180; mHarpMgr.reset(); for (int i = 0; i < 2; i++) { field_0x14C[i] = 0; @@ -239,7 +239,7 @@ void dSndBgmSound_c::loadSeqConfig(u32 soundId) { if (dSndMgr_c::GetInstance()->getArchive()->GetSoundType(soundId) == nw4r::snd::SoundArchive::SOUND_TYPE_SEQ) { mpSeqConfig = dSndBgmSeqConfig::getConfig(soundId, 1); if (mpSeqConfig != nullptr) { - field_0x118 = mpSeqConfig->field_0x08; + mSeqTimebase = mpSeqConfig->mTimebase; } } } @@ -415,27 +415,31 @@ void dSndBgmSound_c::calcSeqPlaySamplePosition() { nw4r::snd::SeqSoundHandle handle(this); s32 tick = handle.GetTick(); - field_0x114 = readSeqTrackVariable(3); - if (field_0x114 >= 0) { - mSeqPlaySamplePosition = tick % field_0x118; + mBgmVar3 = readSeqTrackVariable(3); + if (mBgmVar3 >= 0) { + // Var >= 0 - seq itself controls play position + mSeqPlaySamplePosition = tick % mSeqTimebase; if (mSeqPlaySamplePosition == 0) { - field_0x114++; - if (mpSeqConfig != nullptr && field_0x114 > mpSeqConfig->field_0x0E) { - field_0x114 = mpSeqConfig->field_0x0C; + mBgmVar3++; + if (mpSeqConfig != nullptr && mBgmVar3 > mpSeqConfig->mLoopEnd) { + mBgmVar3 = mpSeqConfig->mLoopStart; } } - mSeqPlaySamplePosition += field_0x118 * field_0x114; + mSeqPlaySamplePosition += mSeqTimebase * mBgmVar3; } else if (mpSeqConfig != nullptr) { - if (tick < (mpSeqConfig->field_0x0E + 1) * field_0x118) { + if (tick < (mpSeqConfig->mLoopEnd + 1) * mSeqTimebase) { + // not looped yet, no adjustment needed mSeqPlaySamplePosition = tick; return; } - s32 offset = mpSeqConfig->field_0x0C * field_0x118; + s32 startOffset = mpSeqConfig->mLoopStart * mSeqTimebase; - tick -= offset; - tick = tick % (field_0x118 * (mpSeqConfig->field_0x0E - mpSeqConfig->field_0x0C)); - mSeqPlaySamplePosition = tick + offset; + // wrap around loop, making sure to account for start offset + tick -= startOffset; + tick = tick % (mSeqTimebase * (mpSeqConfig->mLoopEnd - mpSeqConfig->mLoopStart)); + mSeqPlaySamplePosition = tick + startOffset; } else { + // Fallback, not controlled by seq no config override mSeqPlaySamplePosition = tick; } } diff --git a/src/d/snd/d_snd_bgm_sound_battle.cpp b/src/d/snd/d_snd_bgm_sound_battle.cpp index d3b604c5..034fedb1 100644 --- a/src/d/snd/d_snd_bgm_sound_battle.cpp +++ b/src/d/snd/d_snd_bgm_sound_battle.cpp @@ -5,14 +5,15 @@ #include "d/snd/d_snd_bgm_sound.h" #include "d/snd/d_snd_mgr.h" #include "d/snd/d_snd_wzsound.h" +#include "nw4r/snd/snd_SeqSoundHandle.h" dSndBgmBattleSound_c::dSndBgmBattleSound_c() - : mpBgmBattleConfig(nullptr), mMuteApplyStateMask(0), mTickRelated(0), field_0x190(0), field_0x191(1) {} + : mpBgmBattleConfig(nullptr), mMuteGroupActiveMask(0), mPrevTick(0), field_0x190(0), field_0x191(1) {} void dSndBgmBattleSound_c::cancel() { dSndBgmSound_c::cancel(); - mMuteApplyStateMask = 0; - mTickRelated = 0; + mMuteGroupActiveMask = 0; + mPrevTick = 0; field_0x190 = 0; field_0x191 = 1; } @@ -44,3 +45,54 @@ void dSndBgmBattleSound_c::fadeIn(u32 id, s32 fadeFrames) { field_0x191 = 0; } } + +void dSndBgmBattleSound_c::setTrackGroupMuted(u32 groupId) { + mMuteGroupActiveMask |= (1 << groupId); +} + +void dSndBgmBattleSound_c::setTrackGroupUnmuted(u32 groupId) { + mMuteGroupActiveMask &= ~(1 << groupId); +} + +bool dSndBgmBattleSound_c::startMainBattleLoop() { + if (isPlaying() && readSeqTrackVariable(0) != 1) { + // This seq variable allows the seq sound to jump from intro to main loop + writeSeqTrackVariable(0, 1); + mpSeqConfig = dSndBgmSeqConfig::getConfig(GetId(), 1); + return true; + } + + return false; +} + +void dSndBgmBattleSound_c::calcSeqPlaySamplePosition() { + if (!isSeqSound()) { + return; + } + + nw4r::snd::SeqSoundHandle handle(this); + s32 tick = handle.GetTick(); + s32 tickDiff = tick - mPrevTick; + + if (tickDiff <= 0) { + return; + } + + mPrevTick = tick; + s32 timeBase = mpSeqConfig != nullptr ? mpSeqConfig->mTimebase : 0x180; + mBgmVar3 = readSeqTrackVariable(3); + if (mBgmVar3 >= 0) { + // Var >= 0 - seq itself controls play position + mSeqPlaySamplePosition = tick % mSeqTimebase; + mSeqPlaySamplePosition += mSeqTimebase * mBgmVar3; + } else if (mpSeqConfig != nullptr) { + mSeqPlaySamplePosition += tickDiff; + if (mSeqPlaySamplePosition < (mpSeqConfig->mLoopEnd + 1) * timeBase) { + // not looped yet, no adjustment needed + return; + } + // looped, simple adjustment - simplified compared to dSndBgmSound_c which always calculates + // mSeqPlaySamplePosition freshly. This function instead uses the difference + mSeqPlaySamplePosition -= (timeBase * (mpSeqConfig->mLoopEnd - mpSeqConfig->mLoopStart)); + } +}