mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-27 00:10:31 +00:00
[sound] Add instance limits
This commit is contained in:
parent
7543acfb8a
commit
81df24660b
@ -16,8 +16,14 @@ BlockSoundHandler::BlockSoundHandler(SoundBank& bank,
|
||||
s32 sfx_vol,
|
||||
s32 sfx_pan,
|
||||
SndPlayParams& params,
|
||||
u32 sound_id)
|
||||
: m_group(sfx.VolGroup), m_sfx(sfx), m_vm(vm), m_bank(bank), m_sound_id(sound_id) {
|
||||
u32 sound_id,
|
||||
s32 start_tick)
|
||||
: m_group(sfx.VolGroup),
|
||||
m_sfx(sfx),
|
||||
m_vm(vm),
|
||||
m_bank(bank),
|
||||
m_sound_id(sound_id),
|
||||
m_start_tick(start_tick) {
|
||||
s32 vol, pan, pitch_mod, pitch_bend;
|
||||
if (sfx_vol == -1) {
|
||||
sfx_vol = sfx.Vol;
|
||||
@ -298,4 +304,53 @@ void BlockSoundHandler::DoGrain() {
|
||||
m_countdown = m_sfx.Grains[m_next_grain].Delay + ret;
|
||||
}
|
||||
|
||||
SoundHandler* BlockSoundHandler::CheckInstanceLimit(
|
||||
const std::map<u32, std::unique_ptr<SoundHandler>>& handlers,
|
||||
s32 vol) {
|
||||
if (!m_sfx.InstanceLimit) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!m_sfx.Flags.has_instlimit()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BlockSoundHandler* weakest = nullptr;
|
||||
int inst = 0;
|
||||
|
||||
for (const auto& [id, handler_ptr] : handlers) {
|
||||
// Only compare to BlockSoundHandlers
|
||||
auto* handler = dynamic_cast<BlockSoundHandler*>(handler_ptr.get());
|
||||
if (!handler) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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)) {
|
||||
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())) {
|
||||
// existing weakest is worst
|
||||
return weakest;
|
||||
} else {
|
||||
// new sound is weakest
|
||||
return this;
|
||||
}
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
|
@ -26,7 +26,8 @@ class BlockSoundHandler : public SoundHandler {
|
||||
s32 sfx_vol,
|
||||
s32 sfx_pan,
|
||||
SndPlayParams& params,
|
||||
u32 sound_id);
|
||||
u32 sound_id,
|
||||
s32 start_tick);
|
||||
|
||||
~BlockSoundHandler() override;
|
||||
bool Tick() override;
|
||||
@ -46,6 +47,9 @@ class BlockSoundHandler : public SoundHandler {
|
||||
|
||||
void UpdatePitch();
|
||||
|
||||
SoundHandler* CheckInstanceLimit(const std::map<u32, std::unique_ptr<SoundHandler>>& handlers,
|
||||
s32 vol) override;
|
||||
|
||||
bool m_paused{false};
|
||||
|
||||
u8 m_group{0};
|
||||
@ -90,5 +94,6 @@ class BlockSoundHandler : public SoundHandler {
|
||||
u32 m_next_grain{0};
|
||||
|
||||
u32 m_sound_id{0};
|
||||
s32 m_start_tick{0};
|
||||
};
|
||||
} // namespace snd
|
||||
|
@ -7,12 +7,8 @@
|
||||
|
||||
namespace snd {
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
std::optional<std::unique_ptr<SoundHandler>>
|
||||
MusicBank::MakeHandler(VoiceManager& vm, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb, s32 tick) {
|
||||
auto& sound = Sounds[sound_id];
|
||||
|
||||
// FIXME: global midi list
|
||||
@ -42,7 +38,8 @@ std::optional<std::unique_ptr<SoundHandler>> MusicBank::MakeHandler(VoiceManager
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) {
|
||||
SndPlayParams& params,
|
||||
s32 tick) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -66,17 +66,14 @@ class MusicBank : public SoundBank {
|
||||
std::span<u8> samples,
|
||||
std::span<u8> midi_data);
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) override;
|
||||
std::optional<std::unique_ptr<SoundHandler>>
|
||||
MakeHandler(VoiceManager& vm, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb, s32 tick) override;
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) override;
|
||||
SndPlayParams& params,
|
||||
s32 tick) override;
|
||||
};
|
||||
} // namespace snd
|
||||
|
@ -137,11 +137,19 @@ u32 Player::PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto handler = bank->MakeHandler(mVmanager, sound_id, vol, pan, pm, pb);
|
||||
auto handler = bank->MakeHandler(mVmanager, sound_id, vol, pan, pm, pb, GetTick());
|
||||
if (!handler.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto handler_to_stop = handler.value()->CheckInstanceLimit(mHandlers, vol);
|
||||
if (handler_to_stop) {
|
||||
handler_to_stop->Stop();
|
||||
if (handler_to_stop == handler.value().get()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 handle = mHandleAllocator.GetId();
|
||||
mHandlers.emplace(handle, std::move(handler.value()));
|
||||
// fmt::print("play_sound {}:{} - {}\n", bank_id, sound_id, handle);
|
||||
@ -149,6 +157,16 @@ u32 Player::PlaySound(BankHandle bank_id, u32 sound_id, s32 vol, s32 pan, s32 pm
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Player::DebugPrintAllSoundsInBank(BankHandle bank_id) {
|
||||
std::scoped_lock lock(mTickLock);
|
||||
auto* bank = mLoader.GetBankByHandle(bank_id);
|
||||
if (!bank) {
|
||||
lg::error("DebugPrintAllSoundsInBank: invalid bank");
|
||||
return;
|
||||
}
|
||||
bank->DebugPrintAllSounds();
|
||||
}
|
||||
|
||||
u32 Player::PlaySoundByName(BankHandle bank_id,
|
||||
char* bank_name,
|
||||
char* sound_name,
|
||||
|
@ -2,10 +2,10 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "ame_handler.h"
|
||||
@ -42,6 +42,7 @@ class Player {
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb);
|
||||
void DebugPrintAllSoundsInBank(BankHandle bank);
|
||||
void SetSoundReg(u32 sound_id, u8 reg, u8 value);
|
||||
void SetGlobalExcite(u8 value) { GlobalExcite = value; };
|
||||
bool SoundStillActive(u32 sound_id);
|
||||
@ -71,7 +72,7 @@ class Player {
|
||||
private:
|
||||
std::recursive_mutex mTickLock; // TODO does not need to recursive with some light restructuring
|
||||
IdAllocator mHandleAllocator;
|
||||
std::unordered_map<u32, std::unique_ptr<SoundHandler>> mHandlers;
|
||||
std::map<u32, std::unique_ptr<SoundHandler>> mHandlers;
|
||||
|
||||
void Tick(s16Output* stream, int samples);
|
||||
|
||||
|
@ -5,20 +5,24 @@
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "third-party/magic_enum.hpp"
|
||||
|
||||
namespace snd {
|
||||
|
||||
std::optional<std::unique_ptr<SoundHandler>> SFXBlock::MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) {
|
||||
SndPlayParams& params,
|
||||
s32 current_tick) {
|
||||
auto& SFX = Sounds[sound_id];
|
||||
|
||||
if (SFX.Grains.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto handler = std::make_unique<BlockSoundHandler>(*this, SFX, vm, vol, pan, params, sound_id);
|
||||
auto handler =
|
||||
std::make_unique<BlockSoundHandler>(*this, SFX, vm, vol, pan, params, sound_id, current_tick);
|
||||
return handler;
|
||||
}
|
||||
|
||||
@ -31,4 +35,22 @@ std::optional<u32> SFXBlock::GetSoundByName(const char* name) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void SFXBlock::DebugPrintAllSounds() {
|
||||
for (const auto& [name, id] : Names) {
|
||||
printf("%s : %d\n", name.c_str(), id);
|
||||
const auto& sound = Sounds.at(id);
|
||||
printf(" Vol: %d\n", sound.Vol);
|
||||
printf(" VolGroup: %d\n", sound.VolGroup);
|
||||
printf(" Pan: %d\n", sound.Pan);
|
||||
printf(" InstanceLimit: %d\n", sound.InstanceLimit);
|
||||
printf(" Flags: 0x%x\n", sound.Flags.flags);
|
||||
printf(" User: 0x%x 0x%x 0x%x 0x%x\n", sound.UserData.data[0], sound.UserData.data[1],
|
||||
sound.UserData.data[2], sound.UserData.data[3]);
|
||||
printf(" Grains\n");
|
||||
for (const auto& grain : sound.Grains) {
|
||||
fmt::print(" {} ({})\n", magic_enum::enum_name(grain.Type), (int)grain.Type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
|
@ -52,13 +52,15 @@ class SFXBlock : public SoundBank {
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) override;
|
||||
SndPlayParams& params,
|
||||
s32 current_tick) override;
|
||||
|
||||
std::optional<std::string_view> GetName() override { return Name; };
|
||||
std::optional<u32> GetSoundByName(const char* name) override;
|
||||
std::optional<const SFXUserData*> GetSoundUserData(u32 sound_id) override {
|
||||
return &Sounds.at(sound_id).UserData;
|
||||
};
|
||||
void DebugPrintAllSounds() override;
|
||||
};
|
||||
|
||||
} // namespace snd
|
||||
|
@ -158,7 +158,8 @@ s32 Grain::snd_SFX_GRAIN_TYPE_STARTCHILDSOUND(BlockSoundHandler& handler) {
|
||||
s32 index = psp.sound_id;
|
||||
|
||||
if (index >= 0) {
|
||||
auto child_handler = block.MakeHandler(handler.m_vm, index, vol, pan, params);
|
||||
auto child_handler =
|
||||
block.MakeHandler(handler.m_vm, index, vol, pan, params, handler.m_start_tick);
|
||||
if (child_handler.has_value()) {
|
||||
handler.m_children.emplace_front(std::move(child_handler.value()));
|
||||
}
|
||||
@ -257,7 +258,7 @@ s32 Grain::snd_SFX_GRAIN_TYPE_RAND_PLAY(BlockSoundHandler& handler) {
|
||||
auto cp = std::get<ControlParams>(data);
|
||||
auto options = cp.param[0];
|
||||
auto count = cp.param[1];
|
||||
auto previous = cp.param[2];
|
||||
auto& previous = cp.param[2];
|
||||
|
||||
int rnd = rand() % options;
|
||||
if (rnd == previous) {
|
||||
|
@ -28,6 +28,7 @@ int main(int argc, char* argv[]) {
|
||||
printf("commands:\n");
|
||||
printf(" play [id]\n");
|
||||
printf(" stop\n");
|
||||
printf(" dump-info\n");
|
||||
|
||||
while (true) {
|
||||
printf("> ");
|
||||
@ -77,6 +78,10 @@ int main(int argc, char* argv[]) {
|
||||
printf("stopping all sounds\n");
|
||||
player.StopAllSounds();
|
||||
}
|
||||
|
||||
if (parts[0] == "dump-info") {
|
||||
player.DebugPrintAllSoundsInBank(bankid);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2,6 +2,9 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace snd {
|
||||
@ -25,5 +28,13 @@ class SoundHandler {
|
||||
virtual void SetPBend(s32 /*mod*/){};
|
||||
virtual void SetRegister(u8 /*reg*/, u8 /*value*/) {}
|
||||
virtual u32 SoundID() const { return -1; }
|
||||
|
||||
// Check if this handler violates an instance limit. If so, return pointer to the sound that
|
||||
// should be removed.
|
||||
virtual SoundHandler* CheckInstanceLimit(
|
||||
const std::map<u32, std::unique_ptr<SoundHandler>>& handlers,
|
||||
s32 vol) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} // namespace snd
|
||||
|
@ -54,32 +54,31 @@ class SoundBank {
|
||||
u32 BankID;
|
||||
s8 BankNum;
|
||||
|
||||
virtual std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
s32 pm,
|
||||
s32 pb) {
|
||||
virtual std::optional<std::unique_ptr<SoundHandler>>
|
||||
MakeHandler(VoiceManager& vm, u32 sound_id, s32 vol, s32 pan, s32 pm, s32 pb, s32 current_tick) {
|
||||
SndPlayParams params{};
|
||||
params.vol = vol;
|
||||
params.pan = pan;
|
||||
params.pitch_mod = pm;
|
||||
params.pitch_bend = pb;
|
||||
|
||||
return MakeHandler(vm, sound_id, -1, -1, params);
|
||||
return MakeHandler(vm, sound_id, -1, -1, params, current_tick);
|
||||
};
|
||||
|
||||
virtual std::optional<std::unique_ptr<SoundHandler>> MakeHandler(VoiceManager& vm,
|
||||
u32 sound_id,
|
||||
s32 vol,
|
||||
s32 pan,
|
||||
SndPlayParams& params) = 0;
|
||||
SndPlayParams& params,
|
||||
s32 current_tick) = 0;
|
||||
|
||||
virtual std::optional<std::string_view> GetName() { return std::nullopt; };
|
||||
virtual std::optional<u32> GetSoundByName(const char* /*name*/) { return std::nullopt; };
|
||||
virtual std::optional<const SFXUserData*> GetSoundUserData(u32 /*sound_id*/) {
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
virtual void DebugPrintAllSounds() {}
|
||||
};
|
||||
|
||||
} // namespace snd
|
||||
|
Loading…
Reference in New Issue
Block a user