diff --git a/game/sound/989snd/blocksound_handler.cpp b/game/sound/989snd/blocksound_handler.cpp index 375bb5e1ed..87234babc6 100644 --- a/game/sound/989snd/blocksound_handler.cpp +++ b/game/sound/989snd/blocksound_handler.cpp @@ -19,7 +19,8 @@ BlockSoundHandler::BlockSoundHandler(SoundBank& bank, u32 sound_id, s32 start_tick) : m_group(sfx.VolGroup), - m_sfx(sfx), + m_sfx(&sfx), + m_orig_sfx(&sfx), m_vm(vm), m_bank(bank), m_sound_id(sound_id), @@ -98,7 +99,7 @@ BlockSoundHandler::BlockSoundHandler(SoundBank& bank, // } m_next_grain = 0; - m_countdown = m_sfx.Grains[0].Delay; + m_countdown = m_sfx->Grains[0].Delay; while (m_countdown <= 0 && !m_done) { DoGrain(); } @@ -209,7 +210,7 @@ void BlockSoundHandler::SetVolPan(s32 vol, s32 pan) { } if (pan == PAN_RESET) { - m_app_pan = m_sfx.Pan; + m_app_pan = m_sfx->Pan; } else if (pan != PAN_DONT_CHANGE) { m_app_pan = pan; } @@ -283,7 +284,7 @@ void BlockSoundHandler::SetPBend(s32 bend) { } void BlockSoundHandler::DoGrain() { - auto& grain = m_sfx.Grains[m_next_grain]; + auto& grain = m_sfx->Grains[m_next_grain]; s32 ret = grain(*this); @@ -296,22 +297,23 @@ void BlockSoundHandler::DoGrain() { } m_next_grain++; - if (m_next_grain >= m_sfx.Grains.size()) { + if (m_next_grain >= m_sfx->Grains.size()) { m_done = true; return; } - m_countdown = m_sfx.Grains[m_next_grain].Delay + ret; + m_countdown = m_sfx->Grains[m_next_grain].Delay + ret; } SoundHandler* BlockSoundHandler::CheckInstanceLimit( const std::map>& handlers, - s32 vol) { - if (!m_sfx.InstanceLimit) { + s32 vol, + bool parent) { + if (!m_sfx->InstanceLimit) { return nullptr; } - if (!m_sfx.Flags.has_instlimit()) { + if (!m_sfx->Flags.has_instlimit()) { return nullptr; } @@ -326,22 +328,20 @@ SoundHandler* BlockSoundHandler::CheckInstanceLimit( } // See if this is playing the same sound - // 989snd checks both an orig_sound and a SH.Sound, but we never change the sound. - // We'd need to revisit this if we eventually support BRANCH grains. - if (&handler->m_sfx == &m_sfx) { + if ((parent && handler->m_orig_sfx == m_sfx) || handler->m_sfx == m_sfx) { inst++; - if (!weakest || // - (m_sfx.Flags.instlimit_vol() && handler->m_app_volume < weakest->m_app_volume) || // - (m_sfx.Flags.instlimit_tick() && handler->m_start_tick < weakest->m_start_tick)) { + if (!weakest || // + (m_sfx->Flags.instlimit_vol() && handler->m_app_volume < weakest->m_app_volume) || // + (m_sfx->Flags.instlimit_tick() && handler->m_start_tick < weakest->m_start_tick)) { weakest = handler; } } } // See if this handler would cause us to exceed the limit - if (m_sfx.InstanceLimit - 1 < inst) { - if (weakest && ((m_sfx.Flags.instlimit_vol() && weakest->m_app_volume < vol) || - m_sfx.Flags.instlimit_tick())) { + if (m_sfx->InstanceLimit - 1 < inst) { + if (weakest && ((m_sfx->Flags.instlimit_vol() && weakest->m_app_volume < vol) || + m_sfx->Flags.instlimit_tick())) { // existing weakest is worst return weakest; } else { diff --git a/game/sound/989snd/blocksound_handler.h b/game/sound/989snd/blocksound_handler.h index 146da0e02c..76e64e832f 100644 --- a/game/sound/989snd/blocksound_handler.h +++ b/game/sound/989snd/blocksound_handler.h @@ -48,7 +48,8 @@ class BlockSoundHandler : public SoundHandler { void UpdatePitch(); SoundHandler* CheckInstanceLimit(const std::map>& handlers, - s32 vol) override; + s32 vol, + bool parent) override; bool m_paused{false}; @@ -59,7 +60,8 @@ class BlockSoundHandler : public SoundHandler { u32 m_grains_to_skip{0}; bool m_skip_grains{false}; - SFXBlock::SFX& m_sfx; + SFXBlock::SFX* m_sfx = nullptr; + SFXBlock::SFX* m_orig_sfx = nullptr; VoiceManager& m_vm; std::list> m_voices; diff --git a/game/sound/989snd/handle_allocator.h b/game/sound/989snd/handle_allocator.h index 885e95dfbd..49fd3dd8cd 100644 --- a/game/sound/989snd/handle_allocator.h +++ b/game/sound/989snd/handle_allocator.h @@ -2,31 +2,19 @@ // SPDX-License-Identifier: ISC #pragma once -#include -#include - #include "common/common_types.h" namespace snd { class IdAllocator { public: - u32 GetId() { - u32 id = 0; - if (mFreeIds.empty()) { - id = mNextId++; - } else { - id = mFreeIds.front(); - mFreeIds.pop(); - } - return id; - } - - void FreeId(u32 id) { mFreeIds.push(id); } + // Use a unique ID each time - the Overlord will sometimes do the wrong thing if handles are + // reused. The real 989snd also includes type + handle index in this. + u32 GetId() { return mNextId++; } + void FreeId(u32) {} private: u32 mNextId{1}; - std::queue mFreeIds; }; } // namespace snd diff --git a/game/sound/989snd/lfo.cpp b/game/sound/989snd/lfo.cpp index 0b6bdfb865..60e983d513 100644 --- a/game/sound/989snd/lfo.cpp +++ b/game/sound/989snd/lfo.cpp @@ -19,7 +19,7 @@ void LFOTracker::Init() { void LFOTracker::CalcDepth() { if (m_target == LFOTarget::VOLUME) { - m_range = (m_handler.m_sfx.Vol * m_depth) >> 10; + m_range = (m_handler.m_sfx->Vol * m_depth) >> 10; } if (m_target == LFOTarget::PAN) { m_range = (180 * m_depth) >> 10; diff --git a/game/sound/989snd/player.cpp b/game/sound/989snd/player.cpp index 361b41bd3c..b5adc12baa 100644 --- a/game/sound/989snd/player.cpp +++ b/game/sound/989snd/player.cpp @@ -142,7 +142,7 @@ u32 Player::PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm return 0; } - auto handler_to_stop = handler.value()->CheckInstanceLimit(mHandlers, vol); + auto handler_to_stop = handler.value()->CheckInstanceLimit(mHandlers, vol, true); if (handler_to_stop) { handler_to_stop->Stop(); if (handler_to_stop == handler.value().get()) { diff --git a/game/sound/989snd/sfxgrain.cpp b/game/sound/989snd/sfxgrain.cpp index 64e582963f..12c9716c42 100644 --- a/game/sound/989snd/sfxgrain.cpp +++ b/game/sound/989snd/sfxgrain.cpp @@ -180,7 +180,7 @@ s32 Grain::snd_SFX_GRAIN_TYPE_STOPCHILDSOUND(BlockSoundHandler& handler) { for (auto it = handler.m_children.begin(); it != handler.m_children.end();) { auto* sound = static_cast(it->get()); // TODO VERIFY that this works - if (&sound->m_sfx == &block.Sounds[psp.sound_id]) { + if (sound->m_sfx == &block.Sounds[psp.sound_id]) { it = handler.m_children.erase(it); } else { ++it; @@ -201,6 +201,46 @@ s32 Grain::snd_SFX_GRAIN_TYPE_PLUGIN_MESSAGE(BlockSoundHandler& handler) { } s32 Grain::snd_SFX_GRAIN_TYPE_BRANCH(BlockSoundHandler& handler) { + auto psp = std::get(data); + s32 index = psp.sound_id; + if (index <= -1) { + lg::error("Unsupported BRANCH sound not specified by ID"); + // unsure exactly how this case worked + return 0; + } + + // kill voices + for (auto& p : handler.m_voices) { + auto v = p.lock(); + if (v == nullptr) { + continue; + } + + v->KeyOff(); + v->SetVolumeL(0); + v->SetVolumeR(0); + } + + auto& block = static_cast(handler.m_bank); + auto* new_sfx = &block.Sounds[index]; + if (new_sfx->Flags.has_instlimit()) { + // TODO: not entirely straightforward. + } + + handler.m_sfx = new_sfx; + handler.m_orig_volume = new_sfx->Vol; + handler.m_orig_pan = new_sfx->Pan; + handler.m_cur_volume = (handler.m_app_volume * new_sfx->Vol) >> 10; + handler.m_group = new_sfx->VolGroup; + handler.m_countdown = new_sfx->Grains[0].Delay; + handler.m_next_grain = -1; + handler.m_skip_grains = false; + handler.m_grains_to_play = 0; + handler.m_grains_to_skip = 0; + // the ID case only supports BRANCHing to sfx in the same block + // (this would need to be a pointer, not a reference) + // handler.m_bank = block; + return 0; } @@ -219,7 +259,7 @@ s32 Grain::snd_SFX_GRAIN_TYPE_LOOP_START(BlockSoundHandler& handler) { s32 Grain::snd_SFX_GRAIN_TYPE_LOOP_END(BlockSoundHandler& handler) { bool found = false; for (int i = handler.m_next_grain - 1; i >= 0 && !found; i--) { - if (handler.m_sfx.Grains[i].Type == GrainType::LOOP_START) { + if (handler.m_sfx->Grains[i].Type == GrainType::LOOP_START) { handler.m_next_grain = i - 1; found = true; } @@ -234,8 +274,8 @@ s32 Grain::snd_SFX_GRAIN_TYPE_LOOP_END(BlockSoundHandler& handler) { s32 Grain::snd_SFX_GRAIN_TYPE_LOOP_CONTINUE(BlockSoundHandler& handler) { bool found = false; - for (int i = handler.m_next_grain + 1; i < (int)handler.m_sfx.Grains.size() && !found; i++) { - if (handler.m_sfx.Grains[i].Type == GrainType::LOOP_END) { + for (int i = handler.m_next_grain + 1; i < (int)handler.m_sfx->Grains.size() && !found; i++) { + if (handler.m_sfx->Grains[i].Type == GrainType::LOOP_END) { handler.m_next_grain = i; found = true; } @@ -416,9 +456,9 @@ s32 Grain::snd_SFX_GRAIN_TYPE_GOTO_MARKER(BlockSoundHandler& handler) { auto target_mark = cp.param[0]; bool found = false; - for (int i = 0; i < (int)handler.m_sfx.Grains.size() && !found; i++) { - if (handler.m_sfx.Grains.at(i).Type == GrainType::MARKER) { - auto mcp = std::get(handler.m_sfx.Grains.at(i).data); + for (int i = 0; i < (int)handler.m_sfx->Grains.size() && !found; i++) { + if (handler.m_sfx->Grains.at(i).Type == GrainType::MARKER) { + auto mcp = std::get(handler.m_sfx->Grains.at(i).data); auto mark = mcp.param[0]; if (mark == target_mark) { @@ -444,9 +484,9 @@ s32 Grain::snd_SFX_GRAIN_TYPE_GOTO_RANDOM_MARKER(BlockSoundHandler& handler) { s32 range = upper_bound - lower_bound + 1; s32 target_mark = (rand() % range) + lower_bound; - for (int i = 0; i < (int)handler.m_sfx.Grains.size() && !found; i++) { - if (handler.m_sfx.Grains.at(i).Type == GrainType::MARKER) { - auto mcp = std::get(handler.m_sfx.Grains.at(i).data); + for (int i = 0; i < (int)handler.m_sfx->Grains.size() && !found; i++) { + if (handler.m_sfx->Grains.at(i).Type == GrainType::MARKER) { + auto mcp = std::get(handler.m_sfx->Grains.at(i).data); auto mark = mcp.param[0]; if (mark == target_mark) { @@ -534,7 +574,7 @@ s32 Grain::snd_SFX_GRAIN_TYPE_KILL_VOICES(BlockSoundHandler& handler) { } s32 Grain::snd_SFX_GRAIN_TYPE_ON_STOP_MARKER(BlockSoundHandler& handler) { - handler.m_next_grain = handler.m_sfx.Grains.size() - 1; + handler.m_next_grain = handler.m_sfx->Grains.size() - 1; return 0; } diff --git a/game/sound/989snd/sound_handler.h b/game/sound/989snd/sound_handler.h index c7fe71596a..9affd82913 100644 --- a/game/sound/989snd/sound_handler.h +++ b/game/sound/989snd/sound_handler.h @@ -33,7 +33,8 @@ class SoundHandler { // should be removed. virtual SoundHandler* CheckInstanceLimit( const std::map>& handlers, - s32 vol) { + s32 vol, + bool parent) { return nullptr; } }; diff --git a/goal_src/jak3/levels/wascity/wlander-male.gc b/goal_src/jak3/levels/wascity/wlander-male.gc index cebbc2f539..4f65931a79 100644 --- a/goal_src/jak3/levels/wascity/wlander-male.gc +++ b/goal_src/jak3/levels/wascity/wlander-male.gc @@ -532,6 +532,8 @@ (set! (-> s4-1 volume) 1024) (set! (-> s4-1 pitch-mod) 0) (set! (-> s4-1 reg 0) (the-as uint (-> this shot-sound))) + ;; uncomment the following line to enable the wastelander shot variations. + ;; (logior! (-> s4-1 mask) (sound-mask reg0)) (s5-2 s4-1 (new-sound-id) (-> this root trans)) ) 0