#ifndef D_SND_BGM_MGR_H #define D_SND_BGM_MGR_H #include "common.h" #include "d/snd/d_snd_actor.h" #include "d/snd/d_snd_sound.h" #include "d/snd/d_snd_types.h" #include "d/snd/d_snd_util.h" #include "nw4r/snd/snd_FxReverbStdDpl2.h" #include "nw4r/ut/ut_list.h" SND_DISPOSER_FORWARD_DECL(dSndBgmMgr_c); // Previous Ghidra name: FanfareSoundMgr class dSndBgmMgr_c { public: SND_DISPOSER_MEMBERS(dSndBgmMgr_c); public: static bool isSoundPlayedByBgmBattlePlayer(u32 soundId); static bool isBgmBattle2(u32 soundId); enum BgmSoundList_e { BGM_LIST_PREPARING = 0, BGM_LIST_PLAYING = 1, BGM_LIST_STOPPING = 2, BGM_LIST_MAX = 3, }; dSndBgmMgr_c(); void calc(); void setup(EGG::Heap *heap); void restoreEffects(); bool playBgm(u32 soundId, s32 fadeFrames, bool paused); bool prepareBgm(u32 soundId, u32 startOffset); void pauseAllBgm(); void stopAllBgm(s32 fadeFrames); void loadStageSound(); void setBgmToPlayOnEventEnd(u32 soundId); bool onEventEnd(); void onEventStart(const char *eventName, s32 soundEventId, s32 unk); bool onEventFinalize(const char *eventName, u32 soundEventId, bool skipped); void prepareBgm(); void setOverrideBgmId(u32 id); void activateOverrideBgmId(); void onTgSndAreaMgFlagsChange(u32 newFlags, u32 oldFlags); void onTgSndAreaFlagsChange(u32 newFlags, u32 oldFlags); dSndBgmSound_c *getSoundHandleForBgm(u32 soundId, u32 startOffset); bool isPlayingBgmSound() const; bool isPlayingBgmSoundId(u32 soundId) const; bool isPreparingBgmSoundId(u32 soundId) const; bool isFadingOutBgmSoundId(u32 soundId) const; bool isPreparingBgmSoundIdWithStartOffset(u32 soundId, u32 startOffset) const; bool isPreparedBgmSoundId(u32 soundId) const; void registSound(dSndSound_c *sound); void unregistSound(dSndSound_c *sound); dSndSound_c *getFanSoundHandleForFan2(u32 soundId); dSndSound_c *getSoundHandleCurrentlyPlayingFanSound(u32 soundId); bool isCurrentlyPlayingFanSound(u32 soundId) const; bool hasPlayingFanSounds() const; bool playFanSound(u32 soundId); bool prepareFanSound(u32 soundId); void playDelayedSound(u32 soundId, s32 delay); void cancelDelayedSound(); void cancelDelayedBgm(); dSndBgmSound_c *getBgmSoundByIndex(u32 idx); bool prepareBossBgm(const char *name); /** * E.g. Lizalfos fight in ET. Note that in the ET case, this is only called when triggering * the fight without a cutscene, the cutscene code runs through "ELizarufos_c_opening" */ bool beginBgmBattleRoom(); /** Runs when the fight is over, no matter how you started it */ bool endBgmBattleRoom(); bool beginBgmBattleMainLoop(); bool isPlayingAnyBattleMusic(); void cullTooManyPreparingSounds(); void removeFromAllBgmSoundLists(dSndBgmSound_c *sound); void addToBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound); void appendToBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound); // Unless there's a Ghidra decompiler bug this function // always returns false bool weirdCheckAlwaysFalse(); void fn_80372D70(UNKWORD); dSndBgmSound_c *getActiveBgmSound(); // I don't love this inline but it fixes one regswap // TODO look into getting rid of this one dSndBgmSound_c *getActiveBgmSound_i() { return getActiveBgmSound(); } void setField_0x306(u8 val) { field_0x306 = val; } void setField_0x300(s32 v) { field_0x300 = v; } void setField_0x307(u8 val) { field_0x307 = val; } u8 getField_0x308() const { return field_0x308; } void updateField_0x2F4(f32 value) { if (field_0x2F4 > value) { field_0x2F4 = value; } } private: dSndBgmBattleSound_c *getBgmBattleSound(); void startBgmMuteSound(); void endBgmMuteSound(); bool stopBgmSound(dSndBgmSound_c *sound, s32 fadeFrames); void checkForPrepareStoppedBgmSound(u32 stoppedSoundId); dSndBgmSound_c *findNewBgmSoundHandle(); dSndBgmSound_c *findIdleBgmSoundHandle(); bool prepareBgmSound(u32 soundId, dSndBgmSound_c *handle, u32 startOffset); bool startAdditionalBgm(u32 soundId); bool playBattleBgm(u32 soundId, bool intense); /** Used to mute other BGM when battle music is playing */ void setBgmHandleIdxVolume(u32 handleIdx, f32 volume, s32 fadeFrames); bool isBgmHandleIdxPlayingSoundId(u32 handleIdx, u32 soundId); bool stopBgmHandleIdx(u32 handleIdx, s32 fadeFrames); void calcLists(); void calcStopOldBgmSounds(); void removeFromBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound); bool isInBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound); dSndBgmSound_c *getFirstInBgmSoundList(BgmSoundList_e list); dSndBgmSound_c *getNextInBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound); dSndBgmSound_c *getLastInBgmSoundList(BgmSoundList_e list); bool startDelayedSound(); void calcDelayedSound(); dSndBgmSound_c *getBgmSoundHandleForId(u32 soundId) const; dSndSound_c *getFreeFanSoundHandle(); dSndSound_c *getFanSoundHandleForFan(u32 soundId); void stopFanSounds(s32 fadeFrames); bool isSoundRegist(dSndSound_c *sound); /* 0x010 */ nw4r::snd::FxReverbStdDpl2 mFx; /* 0x240 */ UNKWORD field_0x240; /* 0x244 */ UNKWORD field_0x244; /* 0x248 */ UNKWORD field_0x248; /* 0x24C */ u32 mScheduledSoundId; /* 0x250 */ s32 mScheduledSoundDelay; /* 0x254 */ dSndBgmSound_c *mBgmSounds[7]; /* 0x270 */ dSndBgmSound_c *mpBgmMuteSound; /* 0x274 */ dSndBgmSound_c *mpPrevActiveBgmSound; /* 0x278 */ nw4r::ut::List mBgmSoundLists[BGM_LIST_MAX]; // node offset 0xF0 -> dSndBgmSound_c /* 0x29C */ UNKWORD field_0x29C; /* 0x2A0 */ dSndActor_c mSoundActor; /* 0x2F4 */ f32 field_0x2F4; /* 0x2F8 */ u32 mBgmToPlayOnEventEnd; /* 0x2FC */ u8 field_0x2FC; /* 0x300 */ s32 field_0x300; /* 0x304 */ u8 field_0x304; /* 0x305 */ u8 field_0x305; /* 0x306 */ u8 field_0x306; /* 0x307 */ u8 field_0x307; /* 0x308 */ u8 field_0x308; /* 0x30C */ dSndTagData *field_0x30C[3]; /* 0x318 */ u32 field_0x318[3]; /* 0x324 */ u32 field_0x324[3]; /* 0x330 */ u8 field_0x330[3]; /* 0x333 */ u8 field_0x333; /* 0x334 */ dSndSound_c *mFanSounds[3]; /* 0x340 */ u8 field_0x340; /* 0x344 */ LIST_MEMBER(dSndSound_c, AllSounds); // node offset 0x8 }; #endif