diff --git a/game/overlord/common/srpc.cpp b/game/overlord/common/srpc.cpp index 5345a78b8a5..725a47f7c12 100644 --- a/game/overlord/common/srpc.cpp +++ b/game/overlord/common/srpc.cpp @@ -1,6 +1,7 @@ #include "srpc.h" #include + #include "game/sound/sndshim.h" // added diff --git a/game/overlord/jak2/srpc.cpp b/game/overlord/jak2/srpc.cpp index 8b9a05cec96..a845098490f 100644 --- a/game/overlord/jak2/srpc.cpp +++ b/game/overlord/jak2/srpc.cpp @@ -148,9 +148,9 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { } // lg::warn("RPC: PLAY {} v:{}, p:{}", sound->name, GetVolume(sound), GetPan(sound)); - s32 handle = snd_PlaySoundByNameVolPanPMPB(0, nullptr, sound->name, GetVolume(sound), - GetPan(sound), sound->params.pitch_mod, - sound->params.bend); + s32 handle = snd_PlaySoundByNameVolPanPMPB(nullptr, nullptr, sound->name, + GetVolume(sound), GetPan(sound), + sound->params.pitch_mod, sound->params.bend); sound->sound_handle = handle; if (handle != 0) { sound->id = cmd->play.sound_id; diff --git a/game/sound/989snd/ame_handler.cpp b/game/sound/989snd/ame_handler.cpp index 4bad545f74e..7f66f53370c 100644 --- a/game/sound/989snd/ame_handler.cpp +++ b/game/sound/989snd/ame_handler.cpp @@ -12,12 +12,13 @@ namespace snd { u64 SoundFlavaHack = 0; u8 GlobalExcite = 0; -AmeHandler::AmeHandler(MultiMidi* block, +AmeHandler::AmeHandler(SoundHandle oid, + MultiMidi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, SoundBank& bank) - : m_sound(sound), m_bank(bank), m_header(block), m_repeats(sound.Repeats) { + : SoundHandler(oid), m_sound(sound), m_bank(bank), m_header(block), m_repeats(sound.Repeats) { if (vol == VOLUME_DONT_CHANGE) { vol = 1024; } @@ -57,8 +58,8 @@ void AmeHandler::StartSegment(u32 id) { // Skip adding if not midi type u32 type = (midi.SoundHandle >> 24) & 0xf; if (type == 1 || type == 3) { - m_midis.emplace(id, std::make_unique(static_cast(&midi), m_sound, m_vol, - m_pan, m_bank, this)); + m_midis.emplace(id, std::make_unique(0, static_cast(&midi), m_sound, + m_vol, m_pan, m_bank, this)); } } } diff --git a/game/sound/989snd/ame_handler.h b/game/sound/989snd/ame_handler.h index bad3aedc6e0..543ae543cb7 100644 --- a/game/sound/989snd/ame_handler.h +++ b/game/sound/989snd/ame_handler.h @@ -23,7 +23,12 @@ class AmeHandler : public SoundHandler { friend class MidiHandler; public: - AmeHandler(MultiMidi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, SoundBank& bank); + AmeHandler(SoundHandle oid, + MultiMidi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank); bool Tick() override; SoundBank& Bank() override { return m_bank; }; @@ -71,4 +76,10 @@ class AmeHandler : public SoundHandler { std::array m_register{}; std::array m_macro{}; }; + +AmeHandler* AllocAmeSound(MultiMidi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank); } // namespace snd diff --git a/game/sound/989snd/blocksound_handler.cpp b/game/sound/989snd/blocksound_handler.cpp index 7834abe841a..f9df448fbb0 100644 --- a/game/sound/989snd/blocksound_handler.cpp +++ b/game/sound/989snd/blocksound_handler.cpp @@ -10,12 +10,11 @@ namespace snd { std::array g_block_reg{}; -BlockSoundHandler::BlockSoundHandler(SoundBank& bank, - SFXBlock::SFX& sfx, - s32 sfx_vol, - s32 sfx_pan, - SndPlayParams& params) - : m_group(sfx.VolGroup), m_sfx(sfx), m_bank(bank) { +BlockSoundHandler* BlockSoundHandler::MakeBlockSound(SoundBank& bank, + SFXBlock::SFX& sfx, + s32 sfx_vol, + s32 sfx_pan, + SndPlayParams& params) { s32 vol, pan, pitch_mod, pitch_bend; if (sfx_vol == -1) { sfx_vol = sfx.Vol; @@ -60,42 +59,49 @@ BlockSoundHandler::BlockSoundHandler(SoundBank& bank, pan = sfx_pan; } - m_orig_volume = sfx_vol; - m_orig_pan = sfx_pan; + if (sfx.Flags.solo()) { + lg::warn("989snd: Unsupported solo sound flag"); + } + + auto* hnd = AllocBlockSound(bank, sfx, vol); + if (hnd == nullptr) { + return nullptr; + } - m_cur_volume = play_vol; - m_cur_pan = pan; - m_cur_pb = pitch_bend; - m_cur_pm = pitch_mod; + hnd->m_orig_volume = sfx_vol; + hnd->m_orig_pan = sfx_pan; - m_app_volume = vol; - m_app_pan = pan; - m_app_pb = pitch_bend; - m_app_pm = pitch_mod; + hnd->m_cur_volume = play_vol; + hnd->m_cur_pan = pan; + hnd->m_cur_pb = pitch_bend; + hnd->m_cur_pm = pitch_mod; - m_lfo_volume = 0; - m_lfo_pan = 0; - m_lfo_pb = 0; - m_lfo_pm = 0; + hnd->m_app_volume = vol; + hnd->m_app_pan = pan; + hnd->m_app_pb = pitch_bend; + hnd->m_app_pm = pitch_mod; + + hnd->m_lfo_volume = 0; + hnd->m_lfo_pan = 0; + hnd->m_lfo_pb = 0; + hnd->m_lfo_pm = 0; if (params.registers.has_value()) { - m_registers = params.registers.value(); + hnd->m_registers = params.registers.value(); } - // Figure this stuff out properly someday - // if (m_sfx.d.Flags & 2) { - // fmt::print("solo flag\n"); - // m_done = true; - // return; - // } - - m_next_grain = 0; - m_countdown = m_sfx.Grains[0].Delay; - while (m_countdown <= 0 && !m_done) { - DoGrain(); + hnd->m_next_grain = 0; + hnd->m_countdown = hnd->m_sfx.Grains[0].Delay; + while (hnd->m_countdown <= 0 && !hnd->m_done) { + hnd->DoGrain(); } + + return hnd; } +BlockSoundHandler::BlockSoundHandler(SoundHandle oid, SoundBank& bank, SFXBlock::SFX& sfx) + : SoundHandler(oid), m_group(sfx.VolGroup), m_sfx(sfx), m_bank(bank) {} + BlockSoundHandler::~BlockSoundHandler() { for (auto& p : m_voices) { auto v = p.lock(); @@ -113,8 +119,9 @@ bool BlockSoundHandler::Tick() { } for (auto it = m_children.begin(); it != m_children.end();) { - bool done = it->get()->Tick(); + bool done = (*it)->Tick(); if (done) { + FreeSound(*it); it = m_children.erase(it); } else { ++it; diff --git a/game/sound/989snd/blocksound_handler.h b/game/sound/989snd/blocksound_handler.h index cdd0cf58769..d0c3833d12c 100644 --- a/game/sound/989snd/blocksound_handler.h +++ b/game/sound/989snd/blocksound_handler.h @@ -20,11 +20,13 @@ class BlockSoundVoice : public VagVoice { class BlockSoundHandler : public SoundHandler { public: - BlockSoundHandler(SoundBank& bank, - SFXBlock::SFX& sfx, - s32 sfx_vol, - s32 sfx_pan, - SndPlayParams& params); + static BlockSoundHandler* MakeBlockSound(SoundBank& bank, + SFXBlock::SFX& sfx, + s32 sfx_vol, + s32 sfx_pan, + SndPlayParams& params); + + BlockSoundHandler(SoundHandle oid, SoundBank& bank, SFXBlock::SFX& sfx); ~BlockSoundHandler() override; bool Tick() override; @@ -55,8 +57,7 @@ class BlockSoundHandler : public SoundHandler { SFXBlock::SFX& m_sfx; std::list> m_voices; - - std::list> m_children; + std::vector m_children; s32 m_orig_volume{0}; s32 m_orig_pan{0}; @@ -85,4 +86,7 @@ class BlockSoundHandler : public SoundHandler { s32 m_countdown{0}; u32 m_next_grain{0}; }; + +BlockSoundHandler* AllocBlockSound(SoundBank& bank, SFXBlock::SFX& sfx, s32 sfx_vol); + } // namespace snd diff --git a/game/sound/989snd/midi_handler.cpp b/game/sound/989snd/midi_handler.cpp index c8d8e3931b4..a9c008179d8 100644 --- a/game/sound/989snd/midi_handler.cpp +++ b/game/sound/989snd/midi_handler.cpp @@ -22,12 +22,13 @@ namespace snd { ** */ -MidiHandler::MidiHandler(Midi* block, +MidiHandler::MidiHandler(SoundHandle oid, + Midi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, SoundBank& bank) - : m_sound(sound), m_repeats(sound.Repeats), m_bank(bank), m_header(block) { + : SoundHandler(oid), m_sound(sound), m_repeats(sound.Repeats), m_bank(bank), m_header(block) { if (vol == VOLUME_DONT_CHANGE) { vol = 1024; } @@ -46,13 +47,15 @@ MidiHandler::MidiHandler(Midi* block, InitMidi(); } -MidiHandler::MidiHandler(Midi* block, +MidiHandler::MidiHandler(SoundHandle oid, + Midi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, SoundBank& bank, std::optional parent) - : m_parent(parent), + : SoundHandler(oid), + m_parent(parent), m_sound(sound), m_vol(vol), m_pan(pan), diff --git a/game/sound/989snd/midi_handler.h b/game/sound/989snd/midi_handler.h index de3e4dbc80e..992ba6a460d 100644 --- a/game/sound/989snd/midi_handler.h +++ b/game/sound/989snd/midi_handler.h @@ -29,9 +29,15 @@ class midi_voice : public VagVoice { class AmeHandler; class MidiHandler : public SoundHandler { public: - MidiHandler(Midi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, SoundBank& bank); + MidiHandler(SoundHandle oid, + Midi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank); - MidiHandler(Midi* block, + MidiHandler(SoundHandle oid, + Midi* block, MusicBank::MIDISound& sound, s32 vol, s32 pan, @@ -123,4 +129,11 @@ class MidiHandler : public SoundHandler { static std::pair ReadVLQ(u8* value); }; + +MidiHandler* AllocMidiSound(Midi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank); + } // namespace snd diff --git a/game/sound/989snd/musicbank.cpp b/game/sound/989snd/musicbank.cpp index 8a8eb25b66d..ec29d43833d 100644 --- a/game/sound/989snd/musicbank.cpp +++ b/game/sound/989snd/musicbank.cpp @@ -7,11 +7,7 @@ namespace snd { -std::optional> MusicBank::MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - s32 pm, - s32 pb) { +SoundHandler* MusicBank::MakeHandler(u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) { auto& sound = Sounds[sound_id]; // FIXME: global midi list @@ -21,27 +17,24 @@ std::optional> MusicBank::MakeHandler(u32 sound_id if (sound.Type == 4) { auto& midi = std::get(MidiData); if (sound.MIDIID == midi.ID) { - return std::make_unique(&midi, sound, vol, pan, *this); + return AllocMidiSound(&midi, sound, vol, pan, *this); } - return std::nullopt; + return nullptr; } else if (sound.Type == 5) { auto& midi = std::get(MidiData); if (sound.MIDIID == midi.ID) { - return std::make_unique(&midi, sound, vol, pan, *this); + return AllocAmeSound(&midi, sound, vol, pan, *this); } - return std::nullopt; + return nullptr; } else { lg::error("Invalid music sound type"); - return std::nullopt; + return nullptr; // error } } -std::optional> MusicBank::MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - SndPlayParams& params) { - return std::nullopt; +SoundHandler* MusicBank::MakeHandler(u32 sound_id, s32 vol, s32 pan, SndPlayParams& params) { + return nullptr; } } // namespace snd diff --git a/game/sound/989snd/musicbank.h b/game/sound/989snd/musicbank.h index 40d6e8b3b39..177ac29ff06 100644 --- a/game/sound/989snd/musicbank.h +++ b/game/sound/989snd/musicbank.h @@ -67,15 +67,7 @@ class MusicBank : public SoundBank { nonstd::span samples, nonstd::span midi_data); - std::optional> MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - s32 pm, - s32 pb) override; - - std::optional> MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - SndPlayParams& params) override; + SoundHandler* MakeHandler(u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) override; + SoundHandler* MakeHandler(u32 sound_id, s32 vol, s32 pan, SndPlayParams& params) override; }; } // namespace snd diff --git a/game/sound/989snd/player.cpp b/game/sound/989snd/player.cpp index 95c6af34184..f2b01ea2ee9 100644 --- a/game/sound/989snd/player.cpp +++ b/game/sound/989snd/player.cpp @@ -6,6 +6,7 @@ #include "loader.h" #include "sfxblock.h" +#include "sound_handler.h" #include "vagvoice.h" #include "third-party/fmt/core.h" @@ -21,8 +22,7 @@ namespace snd { u8 g_global_excite = 0; std::recursive_mutex gTickLock; // TODO does not need to recursive with some light restructuring -IdAllocator gHandleAllocator; -std::unordered_map> gHandlers; +std::vector gHandlers; Synth gSynth; s32 gTick{0}; @@ -135,10 +135,10 @@ void Tick(s16Output* stream, int samples) { gTick++; for (auto it = gHandlers.begin(); it != gHandlers.end();) { - bool done = it->second->Tick(); + bool done = (*it)->Tick(); if (done) { // fmt::print("erasing handler\n"); - gHandleAllocator.FreeId(it->first); + FreeSound(*it); it = gHandlers.erase(it); } else { ++it; @@ -168,15 +168,12 @@ u32 PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb } auto handler = bank->MakeHandler(sound_id, vol, pan, pm, pb); - if (!handler.has_value()) { + if (!handler) { return 0; } - u32 handle = gHandleAllocator.GetId(); - gHandlers.emplace(handle, std::move(handler.value())); - // fmt::print("play_sound {}:{} - {}\n", bank_id, sound_id, handle); - - return handle; + gHandlers.push_back(handler); + return handler->Handle(); } u32 PlaySoundByName(BankHandle bank_id, @@ -203,6 +200,7 @@ u32 PlaySoundByName(BankHandle bank_id, auto sound = bank->GetSoundByName(sound_name); if (sound.has_value()) { + // lg::error("play_sound_by_name: playing {}", sound_name); return PlaySound(bank, sound.value(), vol, pan, pm, pb); } @@ -213,35 +211,32 @@ u32 PlaySoundByName(BankHandle bank_id, void StopSound(u32 sound_id) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_id); - if (handler == gHandlers.end()) + auto s = GetSound(sound_id); + if (s == nullptr) return; - handler->second->Stop(); - - // m_handle_allocator.free_id(sound_id); - // m_handlers.erase(sound_id); + s->Stop(); } void SetSoundReg(u32 sound_id, u8 reg, u8 value) { std::scoped_lock lock(gTickLock); - if (gHandlers.find(sound_id) == gHandlers.end()) { + auto s = GetSound(sound_id); + if (s == nullptr) { // fmt::print("set_midi_reg: Handler {} does not exist\n", sound_id); return; } - auto* handler = gHandlers.at(sound_id).get(); - handler->SetRegister(reg, value); + s->SetRegister(reg, value); } -bool SoundStillActive(u32 sound_id) { +u32 SoundStillActive(u32 sound_id) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_id); - if (handler == gHandlers.end()) - return false; + auto s = GetSound(sound_id); + if (s == nullptr) { + return 0; + } - // fmt::print("sound_still_active {}\n", sound_id); - return true; + return s->Handle(); } void SetMasterVolume(u32 group, s32 volume) { @@ -275,8 +270,8 @@ void UnloadBank(BankHandle bank_handle) { return; for (auto it = gHandlers.begin(); it != gHandlers.end();) { - if (&it->second->Bank() == bank_handle) { - gHandleAllocator.FreeId(it->first); + if (&((*it)->Bank()) == bank) { + FreeSound(*it); it = gHandlers.erase(it); } else { ++it; @@ -288,28 +283,28 @@ void UnloadBank(BankHandle bank_handle) { void PauseSound(s32 sound_id) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_id); - if (handler == gHandlers.end()) + auto s = GetSound(sound_id); + if (s == nullptr) return; - handler->second->Pause(); + s->Pause(); } void ContinueSound(s32 sound_id) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_id); - if (handler == gHandlers.end()) + auto s = GetSound(sound_id); + if (s == nullptr) return; - handler->second->Unpause(); + s->Unpause(); } void PauseAllSoundsInGroup(u8 group) { std::scoped_lock lock(gTickLock); for (auto& h : gHandlers) { - if ((1 << h.second->Group()) & group) { - h.second->Pause(); + if ((1 << h->Group()) & group) { + h->Pause(); } } } @@ -318,34 +313,34 @@ void ContinueAllSoundsInGroup(u8 group) { std::scoped_lock lock(gTickLock); for (auto& h : gHandlers) { - if ((1 << h.second->Group()) & group) { - h.second->Unpause(); + if ((1 << h->Group()) & group) { + h->Unpause(); } } } void SetSoundVolPan(s32 sound_id, s32 vol, s32 pan) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_id); - if (handler == gHandlers.end()) + auto s = GetSound(sound_id); + if (s == nullptr) return; - handler->second->SetVolPan(vol, pan); + s->SetVolPan(vol, pan); } void SetSoundPmod(s32 sound_handle, s32 mod) { std::scoped_lock lock(gTickLock); - auto handler = gHandlers.find(sound_handle); - if (handler == gHandlers.end()) + auto s = GetSound(sound_handle); + if (s == nullptr) return; - handler->second->SetPMod(mod); + s->SetPMod(mod); } void StopAllSounds() { std::scoped_lock lock(gTickLock); for (auto it = gHandlers.begin(); it != gHandlers.end();) { - gHandleAllocator.FreeId(it->first); + FreeSound(*it); it = gHandlers.erase(it); } } diff --git a/game/sound/989snd/player.h b/game/sound/989snd/player.h index 77ac42bdf6c..1a307180489 100644 --- a/game/sound/989snd/player.h +++ b/game/sound/989snd/player.h @@ -34,7 +34,7 @@ u32 PlaySoundByName(BankHandle bank, s32 pb); void SetSoundReg(u32 sound_id, u8 reg, u8 value); void SetGlobalExcite(u8 value); -bool SoundStillActive(u32 sound_id); +u32 SoundStillActive(u32 sound_id); void SetMasterVolume(u32 group, s32 volume); void UnloadBank(BankHandle bank_handle); void StopSound(u32 sound_handle); diff --git a/game/sound/989snd/sfxblock.cpp b/game/sound/989snd/sfxblock.cpp index 8b957bf40f1..053d95a0894 100644 --- a/game/sound/989snd/sfxblock.cpp +++ b/game/sound/989snd/sfxblock.cpp @@ -7,17 +7,14 @@ namespace snd { -std::optional> SFXBlock::MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - SndPlayParams& params) { +SoundHandler* SFXBlock::MakeHandler(u32 sound_id, s32 vol, s32 pan, SndPlayParams& params) { auto& SFX = Sounds[sound_id]; if (SFX.Grains.empty()) { - return std::nullopt; + return nullptr; } - auto handler = std::make_unique(*this, SFX, vol, pan, params); + auto handler = BlockSoundHandler::MakeBlockSound(*this, SFX, vol, pan, params); return handler; } diff --git a/game/sound/989snd/sfxblock.h b/game/sound/989snd/sfxblock.h index 13b5cf7a565..3dba02d3f5a 100644 --- a/game/sound/989snd/sfxblock.h +++ b/game/sound/989snd/sfxblock.h @@ -48,10 +48,7 @@ class SFXBlock : public SoundBank { static SFXBlock* ReadBlock(nonstd::span bank_data, nonstd::span samples); - std::optional> MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - SndPlayParams& params) override; + SoundHandler* MakeHandler(u32 sound_id, s32 vol, s32 pan, SndPlayParams& params) override; std::optional GetName() override { return Name; }; std::optional GetSoundByName(const char* name) override; diff --git a/game/sound/989snd/sfxgrain.cpp b/game/sound/989snd/sfxgrain.cpp index da5b49344b0..e68b538e7fe 100644 --- a/game/sound/989snd/sfxgrain.cpp +++ b/game/sound/989snd/sfxgrain.cpp @@ -158,8 +158,8 @@ s32 Grain::snd_SFX_GRAIN_TYPE_STARTCHILDSOUND(BlockSoundHandler& handler) { if (index >= 0) { auto child_handler = block.MakeHandler(index, vol, pan, params); - if (child_handler.has_value()) { - handler.m_children.emplace_front(std::move(child_handler.value())); + if (child_handler) { + handler.m_children.push_back(child_handler); } return 0; @@ -176,9 +176,10 @@ s32 Grain::snd_SFX_GRAIN_TYPE_STOPCHILDSOUND(BlockSoundHandler& handler) { if (psp.sound_id >= 0) { for (auto it = handler.m_children.begin(); it != handler.m_children.end();) { - auto* sound = static_cast(it->get()); + auto* sound = static_cast(*it); // TODO VERIFY that this works if (&sound->m_sfx == &block.Sounds[psp.sound_id]) { + FreeSound(sound); it = handler.m_children.erase(it); } else { ++it; diff --git a/game/sound/989snd/sound_handler.cpp b/game/sound/989snd/sound_handler.cpp new file mode 100644 index 00000000000..b05f9ae8abe --- /dev/null +++ b/game/sound/989snd/sound_handler.cpp @@ -0,0 +1,251 @@ +#include "sound_handler.h" + +#include "ame_handler.h" +#include "blocksound_handler.h" +#include "midi_handler.h" + +namespace snd { + +enum { + SOUND_BLOCK = 1, + SOUND_MIDI, + SOUND_AME, +}; + +static constexpr SoundHandle MakeHandle(u8 tag, u8 idx, u16 sequence) { + return ((tag & 0x1f) << 24) | (idx << 16) | sequence; +} + +static constexpr u8 HandleType(SoundHandle handle) { + return (handle >> 24) & 0x1f; +} + +static constexpr u8 HandleIndex(SoundHandle handle) { + return (handle >> 16) & 0xff; +} + +static constexpr u16 HandleSequence(SoundHandle handle) { + return handle & 0xffff; +} + +template +class HandlerPool { + public: + HandlerPool() { + int i = 0; + for (auto& h : mHandlers) { + h.ID = MakeHandle(tag, i, 0); + h.Free = true; + i++; + } + } + + T* GetPtrFromHandle(SoundHandle handle) { + auto idx = HandleIndex(handle); + if (idx >= size) { + return nullptr; + } + + auto& h = mHandlers[idx]; + if (h.Free == false && h.ID == handle) { + return reinterpret_cast(&h.hnd); + } + + return nullptr; + } + + template + T* AllocateHandler(Args&&... args) { + for (auto& h : mHandlers) { + if (h.Free) { + auto idx = HandleIndex(h.ID); + auto sq = HandleSequence(h.ID); + + h.ID = MakeHandle(tag, idx, sq + 1); + h.Free = false; + + auto p = new (&h.hnd) T(h.ID, args...); + + return p; + } + } + + return nullptr; + } + + void FreeHandler(SoundHandle handle) { + auto idx = HandleIndex(handle); + if (idx >= size) { + return; + } + + auto& h = mHandlers[idx]; + if (h.Free == false && h.ID == handle) { + auto* p = reinterpret_cast(&h.hnd); + std::destroy_at(p); + h.Free = true; + } + } + + T* Idx(std::size_t idx) { + if (idx >= size) { + return nullptr; + } + + auto& h = mHandlers[idx]; + if (h.Free == false) { + return reinterpret_cast(&h.hnd); + } + } + + private: + struct HandlerEntry { + SoundHandle ID{0}; + bool Free{true}; + typename std::aligned_storage::type hnd; + }; + + std::array mHandlers; +}; + +HandlerPool gBlockSounds; +HandlerPool gMidiSounds; +HandlerPool gAmeSounds; + +void SoundInit() { + // TODO reset? +} + +bool CheckInstanceLimit(SFXBlock::SFX& sfx, s32 sfx_vol, BlockSoundHandler** weakest_out) { + s32 instances = 0; + BlockSoundHandler* weakest = nullptr; + + if (!sfx.InstanceLimit) { + return false; + } + + if (sfx.Flags.instlimit_tick()) { + lg::warn("unhandled tick instlimit"); + } + + for (int i = 0; i < 64; i++) { + auto* s = gBlockSounds.Idx(i); + if (s == nullptr) { + continue; + } + + if (&s->m_sfx == &sfx) { + instances++; + if (!weakest) { + weakest = s; + } + + if (sfx.Flags.instlimit_vol() && s->m_app_volume < weakest->m_app_volume) { + weakest = s; + } + + // if (sfx.Flags.instlimit_tick() && s->m_start_tick < weakest->m_start_tick) { + // weakest = s; + // } + } + } + + if (instances > sfx.InstanceLimit) { + lg::warn("instance limit exceeded {}", sfx.InstanceLimit); + if (!weakest) { + lg::warn("no weakest"); + return false; + } + + if (sfx.Flags.instlimit_vol() && weakest->m_app_volume < sfx_vol) { + *weakest_out = weakest; + lg::warn("found weaker handler {} < {}", weakest->m_app_volume, sfx_vol); + return true; + } + + if (sfx.Flags.instlimit_vol()) { + lg::warn("failed to find weaker handler {} < {}", weakest->m_app_volume, sfx_vol); + } + + return false; + } + + return true; +} + +BlockSoundHandler* AllocBlockSound(SoundBank& bank, SFXBlock::SFX& sfx, s32 sfx_vol) { + BlockSoundHandler* weakest = nullptr; + + if (sfx.Flags.has_instlimit()) { + if (!CheckInstanceLimit(sfx, sfx_vol, &weakest)) { + return nullptr; + } + + if (weakest) { + weakest->Stop(); + } + } + + return gBlockSounds.AllocateHandler(bank, sfx); +} + +MidiHandler* AllocMidiSound(Midi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank) { + return gMidiSounds.AllocateHandler(block, sound, vol, pan, bank); +} + +AmeHandler* AllocAmeSound(MultiMidi* block, + MusicBank::MIDISound& sound, + s32 vol, + s32 pan, + SoundBank& bank) { + return gAmeSounds.AllocateHandler(block, sound, vol, pan, bank); +} + +void FreeSound(SoundHandler* handler) { + auto handle = handler->Handle(); + u8 type = HandleType(handle); + switch (type) { + case SOUND_BLOCK: + gBlockSounds.FreeHandler(handle); + break; + case SOUND_MIDI: + gMidiSounds.FreeHandler(handle); + break; + case SOUND_AME: + gAmeSounds.FreeHandler(handle); + break; + default: + lg::die("Unknown sound type (messed up sound handle) {:x}", handle); + break; + } +} + +SoundHandler* GetSound(SoundHandle handle) { + if (handle == 0) { + return nullptr; + } + + u8 type = HandleType(handle); + switch (type) { + case SOUND_BLOCK: + return gBlockSounds.GetPtrFromHandle(handle); + break; + case SOUND_MIDI: + return gMidiSounds.GetPtrFromHandle(handle); + break; + case SOUND_AME: + return gAmeSounds.GetPtrFromHandle(handle); + break; + default: + lg::die("Unknown sound type (messed up sound handle) {:x}", handle); + break; + } + + return nullptr; +} + +} // namespace snd diff --git a/game/sound/989snd/sound_handler.h b/game/sound/989snd/sound_handler.h index 9fd3b6f1dd2..e82525d0b4a 100644 --- a/game/sound/989snd/sound_handler.h +++ b/game/sound/989snd/sound_handler.h @@ -10,9 +10,11 @@ static constexpr int PAN_DONT_CHANGE = -2; static constexpr int VOLUME_DONT_CHANGE = 0x7fffffff; class SoundBank; +using SoundHandle = u32; class SoundHandler { public: + SoundHandler(SoundHandle OwnerID) : mOwnerId(OwnerID){}; virtual ~SoundHandler() = default; virtual bool Tick() = 0; virtual SoundBank& Bank() = 0; @@ -24,5 +26,13 @@ class SoundHandler { virtual void SetPMod(s32 mod) = 0; virtual void SetPBend(s32 /*mod*/){}; virtual void SetRegister(u8 /*reg*/, u8 /*value*/) {} + + SoundHandle Handle() { return mOwnerId; } + + SoundHandle mOwnerId; }; + +SoundHandler* GetSound(SoundHandle handle); +void FreeSound(SoundHandler* handler); + } // namespace snd diff --git a/game/sound/989snd/soundbank.h b/game/sound/989snd/soundbank.h index 1ad9e6b494f..5e90f16817e 100644 --- a/game/sound/989snd/soundbank.h +++ b/game/sound/989snd/soundbank.h @@ -53,11 +53,7 @@ class SoundBank { u32 BankID; s8 BankNum; - virtual std::optional> MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - s32 pm, - s32 pb) { + virtual SoundHandler* MakeHandler(u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb) { SndPlayParams params{}; params.vol = vol; params.pan = pan; @@ -67,10 +63,7 @@ class SoundBank { return MakeHandler(sound_id, -1, -1, params); }; - virtual std::optional> MakeHandler(u32 sound_id, - s32 vol, - s32 pan, - SndPlayParams& params) = 0; + virtual SoundHandler* MakeHandler(u32 sound_id, s32 vol, s32 pan, SndPlayParams& params) = 0; virtual std::optional GetName() { return std::nullopt; }; virtual std::optional GetSoundByName(const char* /*name*/) { return std::nullopt; }; diff --git a/game/sound/CMakeLists.txt b/game/sound/CMakeLists.txt index 4804d844df0..4abc1a940b0 100644 --- a/game/sound/CMakeLists.txt +++ b/game/sound/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOUND_SOURCES 989snd/midi_handler.cpp 989snd/ame_handler.cpp 989snd/blocksound_handler.cpp + 989snd/sound_handler.cpp 989snd/musicbank.cpp 989snd/sfxblock.cpp 989snd/sfxgrain.cpp diff --git a/game/sound/sndshim.cpp b/game/sound/sndshim.cpp index 0212054d3a8..18c12a93f74 100644 --- a/game/sound/sndshim.cpp +++ b/game/sound/sndshim.cpp @@ -78,11 +78,7 @@ void snd_SetPlayBackMode(s32 mode) { } s32 snd_SoundIsStillPlaying(s32 sound_handle) { - if (snd::SoundStillActive(sound_handle)) { - return sound_handle; - } - - return 0; + return snd::SoundStillActive(sound_handle); } void snd_StopSound(s32 sound_handle) { @@ -141,7 +137,7 @@ void snd_SetSoundPitchModifier(s32 sound_handle, s32 pitch_mod) { } void snd_SetSoundPitchBend(s32 sound_handle, s32 bend) { - lg::warn("unimplemented snd_SetSoundPitchBend"); + // lg::warn("unimplemented snd_SetSoundPitchBend({:x}, {})", sound_handle, bend); } void snd_PauseSound(s32 sound_handle) {