#include "d/snd/d_snd_bgm_mgr.h" #include "common.h" #include "d/flag/storyflag_manager.h" #include "d/snd/d_snd_bgm_mml_parsers.h" #include "d/snd/d_snd_bgm_sound.h" #include "d/snd/d_snd_bgm_sound_battle.h" #include "d/snd/d_snd_mgr.h" #include "d/snd/d_snd_player_mgr.h" #include "d/snd/d_snd_sound.h" #include "d/snd/d_snd_state_mgr.h" #include "d/snd/d_snd_util.h" #include "d/snd/d_snd_wzsound.h" #include "nw4r/snd/snd_SoundArchive.h" #include "nw4r/ut/ut_list.h" bool dSndBgmMgr_c::isSoundPlayedByBgmBattlePlayer(u32 soundId) { if (soundId == -1) { return false; } return dSndMgr_c::getPlayerId(soundId) == dSndPlayerMgr_c::PLAYER_BGM_BATTLE; } bool dSndBgmMgr_c::isBgmBattle2(u32 soundId) { return soundId == BGM_BATTLE2; } SND_DISPOSER_DEFINE(dSndBgmMgr_c); dSndBgmMgr_c::dSndBgmMgr_c() : field_0x240(2), field_0x244(0), field_0x248(0), mScheduledSoundId(-1), mScheduledSoundDelay(0), mpPrevActiveBgmSound(nullptr), field_0x29C(0), mSoundActor(dSndMgr_c::GetInstance()->getPlayer()), field_0x2F4(1.0f), mBgmToPlayOnEventEnd(-1), field_0x2FC(0), field_0x300(-1), field_0x304(0), field_0x305(0), field_0x306(0), field_0x307(0), field_0x308(0), field_0x333(0), field_0x340(0) { for (int i = 0; i < BGM_LIST_MAX; i++) { // TODO offsetof nw4r::ut::List_Init(&mBgmSoundLists[i], 0xF0); } for (int i = 0; i < 7; i++) { if (i == 4) { mBgmSounds[i] = new dSndBgmBattleSound_c(); } else { mBgmSounds[i] = new dSndBgmSound_c(); } mBgmSounds[i]->init(mSoundActor, i); } mpBgmMuteSound = new dSndBgmSound_c(); mpBgmMuteSound->init(dSndMgr_c::GetInstance()->getPlayer(), 8); for (int i = 0; i < 3; i++) { mFanSounds[i] = new dSndSound_c(); } nw4r::ut::List_Init(&mAllSoundsList, 8); for (int i = 0; i < 3; i++) { field_0x30C[i] = 0; field_0x318[i] = 0; field_0x324[i] = 0; field_0x330[i] = 0; } } void dSndBgmMgr_c::calcLists() { dSndBgmSound_c *snd = getActiveBgmSound_i(); if (snd != nullptr) { if (snd != mpPrevActiveBgmSound) { snd->onBecomeActive(); } snd->applyVars(); } mpPrevActiveBgmSound = snd; dSndBgmSound_c *next, *it; for (it = getFirstInBgmSoundList(BGM_LIST_PLAYING); it != nullptr; it = next) { next = getNextInBgmSoundList(BGM_LIST_PLAYING, it); it->calc(); } for (it = getFirstInBgmSoundList(BGM_LIST_STOPPING); it != nullptr; it = next) { next = getNextInBgmSoundList(BGM_LIST_STOPPING, it); it->calc(); } for (it = getFirstInBgmSoundList(BGM_LIST_PREPARING); it != nullptr; it = next) { next = getNextInBgmSoundList(BGM_LIST_PREPARING, it); if (!it->IsAttachedSound()) { it->cancel(); removeFromAllBgmSoundLists(it); } } { dSndSound_c *next, *it; for (it = getAllSoundsFirst(); it != nullptr; it = next) { next = getAllSoundsNext(it); if (!it->IsAttachedSound()) { unregistSound(it); } } } } void dSndBgmMgr_c::loadStageSound() { for (int i = 0; i < 3; i++) { field_0x30C[i] = nullptr; field_0x318[i] = 0; field_0x324[i] = 0; field_0x330[i] = 0; } if (dSndStateMgr_c::GetInstance()->isInDemo()) { return; } if (dSndStateMgr_c::isInStage("F103")) { // Flooded Faron Woods if (!StoryflagManager::sInstance->getFlag(STORYFLAG_ALL_TADTONES_GATHERED)) { bool ok = true; if (!dSndPlayerMgr_c::GetInstance()->isLoadedFileForSound(TAG_BGM_EVENT_COMP_NOTE)) { ok = dSndPlayerMgr_c::GetInstance()->loadFileForSound(TAG_BGM_EVENT_COMP_NOTE); } if (ok) { dSndBgmMmlParserTagCompNote_c parser; parser.parseData(&field_0x30C[0]); field_0x324[0] = field_0x30C[0]->data[0]; } } } else if (dSndStateMgr_c::isInStage("F403") && dSndStateMgr_c::GetInstance()->getLayer() == 1) { bool ok = true; if (!dSndPlayerMgr_c::GetInstance()->isLoadedFileForSound(TAG_BGM_BATTLE_CROWD)) { ok = dSndPlayerMgr_c::GetInstance()->loadFileForSound(TAG_BGM_BATTLE_CROWD); } if (ok) { dSndBgmMmlParserTagBattle_c parser; parser.parseData(TAG_BGM_BATTLE_CROWD, &field_0x30C[0]); field_0x324[0] = field_0x30C[0]->data[0]; } } else { if (dSndPlayerMgr_c::GetInstance()->isLoadedFileForSound(TAG_BGM_BOSS_A)) { bool ok = true; // I am REALLY not sure how TAG_BGM_BOSS_A could spontaneously unload here but better // double check I guess if (!dSndPlayerMgr_c::GetInstance()->isLoadedFileForSound(TAG_BGM_BOSS_A)) { // TODO types ok = dSndMgr_c::GetInstance()->loadGroup((unsigned int)GRP_BGM_BOSS_A, nullptr, 0); } if (ok) { dSndBgmMmlParserTagBgmBoss_c parser1; parser1.parseData(&field_0x30C[0], &field_0x30C[1]); } if (ok) { dSndBgmMmlParserTagBattle_c parser; parser.parseData(TAG_BGM_BOSS_A_CHANCE, &field_0x30C[2]); } } } } void dSndBgmMgr_c::startBgmMuteSound() { if (mpBgmMuteSound != nullptr) { mpBgmMuteSound->stop(0); mpBgmMuteSound->startBgmSound(BGM_MUTE, 0, 0); } } bool dSndBgmMgr_c::prepareBgm(u32 soundId, u32 startOffset) { if (isPlayingBgmSoundId(soundId)) { return false; } dSndBgmSound_c *handle = getSoundHandleForBgm(soundId, startOffset); bool ret = false; if (handle != nullptr) { ret = prepareBgmSound(soundId, handle, startOffset); } startAdditionalBgm(soundId); return ret; } void dSndBgmMgr_c::stopAllBgm(s32 fadeFrames) { for (int i = 0; i < 7; i++) { stopBgmSound(mBgmSounds[i], fadeFrames); } cancelDelayedBgm(); } bool dSndBgmMgr_c::stopBgmSound(dSndBgmSound_c *sound, s32 fadeFrames) { u32 oldId = sound->GetId(); if (oldId != -1) { sound->stop(fadeFrames); checkForPrepareStoppedBgmSound(oldId); return true; } return false; } void dSndBgmMgr_c::endBgmMuteSound() { mpBgmMuteSound->stop(0); } void dSndBgmMgr_c::checkForPrepareStoppedBgmSound(u32 stoppedSoundId) { // TODO ??? u32 id = stoppedSoundId == BGM_SKYFIELD ? BGM_SKYFIELD : -1; if (id != -1) { prepareBgm(id, 0); } } bool dSndBgmMgr_c::beginBgmBattleMainLoop() { return getBgmBattleSound()->startMainBattleLoop(); } bool dSndBgmMgr_c::beginBgmBattleRoom() { if (isBgmHandleIdxPlayingSoundId(4, BGM_BATTLE_ROOM_MAIN)) { return false; } return playBattleBgm(BGM_BATTLE_ROOM_MAIN, true); } bool dSndBgmMgr_c::endBgmBattleRoom() { if (!isBgmHandleIdxPlayingSoundId(4, BGM_BATTLE_ROOM_MAIN)) { return false; } stopBgmHandleIdx(4, 5); return playFanSound(BGM_BATTLE_ROOM_OUTRO); } bool dSndBgmMgr_c::weirdCheckAlwaysFalse() { u32 soundId = getBgmBattleSound()->GetId(); bool ok = false; // @bug should be != -1 if (soundId != 0) { if (getBgmBattleSound()->isPlaying()) { ok = true; } } // @bug passes a boolean to a function expecting a sound ID. // function only returns true if sound ID is 0x1585, so this // always returns false return isBgmBattle2(ok); } void dSndBgmMgr_c::playDelayedSound(u32 soundId, s32 delay) { if (soundId == -1) { return; } u32 playerId = dSndMgr_c::getPlayerId(soundId); switch (playerId) { case dSndPlayerMgr_c::PLAYER_BGM: case dSndPlayerMgr_c::PLAYER_BGM_BATTLE: if (delay == 0) { playBgm(soundId, 0, false); return; } prepareBgm(soundId, 0); break; case dSndPlayerMgr_c::PLAYER_FAN: if (delay == 0) { playFanSound(soundId); return; } prepareFanSound(soundId); break; default: return; } mScheduledSoundId = soundId; mScheduledSoundDelay = delay; } void dSndBgmMgr_c::cancelDelayedSound() { mScheduledSoundId = -1; mScheduledSoundDelay = 0; } void dSndBgmMgr_c::cancelDelayedBgm() { if (mScheduledSoundId == -1) { return; } nw4r::snd::SoundArchive::SoundInfo info; u32 playerId = dSndMgr_c::getPlayerId(mScheduledSoundId); if (dSndPlayerMgr_c::isBgmPlayerId(playerId)) { cancelDelayedSound(); } } bool dSndBgmMgr_c::startDelayedSound() { if (mScheduledSoundId == -1) { return false; } bool ok = false; u32 playerId = dSndMgr_c::getPlayerId(mScheduledSoundId); switch (playerId) { case dSndPlayerMgr_c::PLAYER_BGM: case dSndPlayerMgr_c::PLAYER_BGM_BATTLE: ok = playBgm(mScheduledSoundId, 0, false); break; case dSndPlayerMgr_c::PLAYER_FAN: ok = playFanSound(mScheduledSoundId); break; default: break; } cancelDelayedSound(); return ok; } void dSndBgmMgr_c::calcDelayedSound() { if (mScheduledSoundId == -1) { return; } mScheduledSoundDelay--; if (mScheduledSoundDelay == 0) { startDelayedSound(); } } // 8036e980 - plays additional music for some reason. // e.g. Sandship (BGM_D301 / 0x1607) also prepares BGM_D301_INSIDE / 0x1608 void dSndBgmMgr_c::setBgmHandleIdxVolume(u32 handleIdx, f32 volume, s32 fadeFrames) { // Using the getter to check validity but then not using the result is a bit weird if (getBgmSoundByIndex(handleIdx) != nullptr) { mBgmSounds[handleIdx]->setVolume(volume, fadeFrames); } } void dSndBgmMgr_c::setBgmToPlayOnEventEnd(u32 soundId) { if (soundId != -1) { prepareBgm(soundId, 0); mBgmToPlayOnEventEnd = soundId; } } bool dSndBgmMgr_c::onEventEnd() { bool ret = false; if (mBgmToPlayOnEventEnd != -1) { ret = playBgm(mBgmToPlayOnEventEnd, 0, false); mBgmToPlayOnEventEnd = -1; } return ret; } bool dSndBgmMgr_c::isPlayingBgmSound() const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->isPlaying()) { return true; } } return false; } bool dSndBgmMgr_c::isPlayingBgmSoundId(u32 soundId) const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->isPlayingSoundId(soundId)) { return true; } } return false; } bool dSndBgmMgr_c::isFadingOutBgmSoundId(u32 soundId) const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->GetId() == soundId && mBgmSounds[i]->isFadingOut()) { return true; } } return false; } bool dSndBgmMgr_c::isPreparingBgmSoundId(u32 soundId) const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->isPreparingSoundId(soundId)) { return true; } } return false; } bool dSndBgmMgr_c::isPreparingBgmSoundIdWithStartOffset(u32 soundId, u32 startOffset) const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->isPreparingSoundIdWithStartOffset(soundId, startOffset)) { return true; } } return false; } bool dSndBgmMgr_c::isPreparedBgmSoundId(u32 soundId) const { for (int i = 0; i < 7; i++) { if (mBgmSounds[i]->isPreparedSoundId(soundId)) { return true; } } return false; } dSndBgmSound_c *dSndBgmMgr_c::getBgmSoundByIndex(u32 idx) { if (idx >= 7) { return nullptr; } return mBgmSounds[idx]; } dSndBgmSound_c *dSndBgmMgr_c::getBgmSoundHandleForId(u32 soundId) const { for (int i = 0; i < 7; i++) { dSndBgmSound_c *snd = mBgmSounds[i]; if (snd->isPlayingSoundId(soundId)) { return snd; } } return nullptr; } dSndBgmSound_c *dSndBgmMgr_c::findIdleBgmSoundHandle() { for (int i = 0; i < 4; i++) { dSndBgmSound_c *snd = mBgmSounds[i]; if (!snd->hasState()) { return snd; } } return nullptr; } dSndBgmBattleSound_c *dSndBgmMgr_c::getBgmBattleSound() { return static_cast(mBgmSounds[4]); } void dSndBgmMgr_c::addToBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound) { if (list < BGM_LIST_MAX && sound != nullptr) { removeFromAllBgmSoundLists(sound); nw4r::ut::List_Prepend(&mBgmSoundLists[list], sound); } } void dSndBgmMgr_c::appendToBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound) { if (list < BGM_LIST_MAX && sound != nullptr) { removeFromAllBgmSoundLists(sound); nw4r::ut::List_Append(&mBgmSoundLists[list], sound); } } void dSndBgmMgr_c::removeFromBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound) { if (list < BGM_LIST_MAX && sound != nullptr) { if (isInBgmSoundList(list, sound)) { nw4r::ut::List_Remove(&mBgmSoundLists[list], sound); } } } void dSndBgmMgr_c::removeFromAllBgmSoundLists(dSndBgmSound_c *sound) { for (int i = 0; i < BGM_LIST_MAX; i++) { removeFromBgmSoundList(static_cast(i), sound); } } bool dSndBgmMgr_c::isInBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound) { if (list >= BGM_LIST_MAX) { return false; } if (sound == nullptr) { return false; } for (dSndBgmSound_c *it = getFirstInBgmSoundList(list); it != nullptr; it = getNextInBgmSoundList(list, it)) { if (it == sound) { return true; } } return false; } dSndBgmSound_c *dSndBgmMgr_c::getFirstInBgmSoundList(BgmSoundList_e list) { if (list >= BGM_LIST_MAX) { return nullptr; } return static_cast(nw4r::ut::List_GetFirst(&mBgmSoundLists[list])); } dSndBgmSound_c *dSndBgmMgr_c::getNextInBgmSoundList(BgmSoundList_e list, dSndBgmSound_c *sound) { if (list >= BGM_LIST_MAX) { return nullptr; } return static_cast(nw4r::ut::List_GetNext(&mBgmSoundLists[list], sound)); } dSndBgmSound_c *dSndBgmMgr_c::getLastInBgmSoundList(BgmSoundList_e list) { if (list >= BGM_LIST_MAX) { return nullptr; } return static_cast(nw4r::ut::List_GetLast(&mBgmSoundLists[list])); } dSndSound_c *dSndBgmMgr_c::getFreeFanSoundHandle() { for (int i = 0; i < 3; i++) { if (!mFanSounds[i]->IsAttachedSound()) { return mFanSounds[i]; } } return nullptr; } dSndSound_c *dSndBgmMgr_c::getFanSoundHandleForFan(u32 soundId) { for (int i = 0; i < 3; i++) { if (mFanSounds[i]->GetId() == soundId) { return mFanSounds[i]; } } return nullptr; } dSndSound_c *dSndBgmMgr_c::getSoundHandleCurrentlyPlayingFanSound(u32 soundId) { for (int i = 0; i < 3; i++) { if (mFanSounds[i]->isPlayingSoundId(soundId)) { return mFanSounds[i]; } } return nullptr; } dSndSound_c *dSndBgmMgr_c::getFanSoundHandleForFan2(u32 soundId) { for (int i = 0; i < 3; i++) { if (mFanSounds[i]->GetId() == soundId) { return mFanSounds[i]; } } return nullptr; } bool dSndBgmMgr_c::isCurrentlyPlayingFanSound(u32 soundId) const { for (int i = 0; i < 3; i++) { if (mFanSounds[i]->isPlayingSoundId(soundId)) { return true; } } return false; } bool dSndBgmMgr_c::hasPlayingFanSounds() const { for (int i = 0; i < 3; i++) { if (mFanSounds[i]->isPlaying()) { return true; } } return false; } void dSndBgmMgr_c::stopFanSounds(s32 fadeFrames) { for (int i = 0; i < 3; i++) { mFanSounds[i]->stop(fadeFrames); } } void dSndBgmMgr_c::calcStopOldBgmSounds() { s32 numPlayingSounds = 0; dSndBgmSound_c *it; for (it = getFirstInBgmSoundList(BGM_LIST_PLAYING); it != nullptr; it = getNextInBgmSoundList(BGM_LIST_PLAYING, it)) { if (!it->isPaused() && it->isStrmSound()) { numPlayingSounds++; } } // If more than one strm sound is playing, stop all but the first one if (numPlayingSounds >= 2) { for (it = getFirstInBgmSoundList(BGM_LIST_PLAYING); it != nullptr; it = getNextInBgmSoundList(BGM_LIST_PLAYING, it)) { if (!it->isPaused() && it->isStrmSound() && it != getFirstInBgmSoundList(BGM_LIST_PLAYING)) { it->stop(15); } } } } void dSndBgmMgr_c::registSound(dSndSound_c *sound) { if (sound == nullptr) { return; } unregistSound(sound); nw4r::ut::List_Append(&mAllSoundsList, sound); } void dSndBgmMgr_c::unregistSound(dSndSound_c *sound) { if (isSoundRegist(sound)) { nw4r::ut::List_Remove(&mAllSoundsList, sound); } } bool dSndBgmMgr_c::isSoundRegist(dSndSound_c *sound) { if (sound == nullptr) { return false; } for (dSndSound_c *it = getAllSoundsFirst(); it != nullptr; it = getAllSoundsNext(it)) { if (it == sound) { return true; } } return false; }