From a39af394fb780ab97f39eb20e350e213759065ef Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 8 Sep 2024 14:47:12 -0400 Subject: [PATCH] [jak2] Workaround for sound effects getting dropped (#3660) Similar to the workaround added in jak 3, if too many sounds are playing, a sound will be removed. If there are multiple instances of the same sound being played, those will be removed first. Within that, older sounds are removed first. It's not exactly the same as the instance limits of 989snd, but it seems to work well. It's at least better than what we had before. Co-authored-by: water111 --- game/overlord/common/ssound.cpp | 75 ++++++++++++++++++++++++++++++++- game/overlord/common/ssound.h | 4 +- game/overlord/jak1/srpc.cpp | 4 +- game/overlord/jak2/srpc.cpp | 4 +- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/game/overlord/common/ssound.cpp b/game/overlord/common/ssound.cpp index 7f4532907e..77bfbd7642 100644 --- a/game/overlord/common/ssound.cpp +++ b/game/overlord/common/ssound.cpp @@ -7,7 +7,8 @@ s32 gMusicFade = 0; s32 gSema; -Sound gSounds[64]; +constexpr int kNumSounds = 64; +Sound gSounds[kNumSounds]; Vec3w gEarTrans[2]; Vec3w gCamTrans; s32 gMusicFadeDir = 0; @@ -15,6 +16,7 @@ Curve gCurves[16]; s32 gCamAngle; u8 gMirrorMode = 0; u32 sLastTick = 0; +s64 gAddIndex = 0; static s32 sqrt_table[256] = { 0, 4096, 5793, 7094, 8192, 9159, 10033, 10837, 11585, 12288, 12953, 13585, 14189, @@ -56,6 +58,7 @@ static s32 atan_table[257] = { void ssound_init_globals() { gMusicFade = 0; gSema = 0; + gAddIndex = 0; } Sound* LookupSound(s32 id) { @@ -268,9 +271,66 @@ void UpdateVolume(Sound* sound) { } } -Sound* AllocateSound() { +void RemoveOldSounds() { + int unique_sounds = 0; + struct Entry { + u32 id; + u32 count; + Sound* info; + }; + Entry entries[kNumSounds]; + Entry* best_entry = nullptr; + + for (auto& sound : gSounds) { + if (sound.id) { + Entry* existing_entry = nullptr; + u32 uid = snd_GetSoundID(sound.sound_handle); + + // look for entry: + for (int i = 0; i < unique_sounds; i++) { + if (entries[i].id == uid) { + existing_entry = &entries[i]; + break; + } + } + + // if none found, create + if (!existing_entry) { + existing_entry = &entries[unique_sounds]; + unique_sounds++; + existing_entry->id = uid; + existing_entry->count = 0; + existing_entry->info = &sound; + } + + // update + existing_entry->count++; + // pick oldest sound + if (sound.add_index < existing_entry->info->add_index) { + existing_entry->info = &sound; + } + + // se if we're best + if (!best_entry) { + best_entry = existing_entry; + } else { + if (best_entry->count < existing_entry->count) { + best_entry = existing_entry; + } + } + } + } + + if (best_entry) { + snd_StopSound(best_entry->info->sound_handle); + best_entry->info->id = 0; + } +} + +Sound* AllocateSound(bool remove_old_sounds) { for (auto& s : gSounds) { if (s.id == 0) { + s.add_index = gAddIndex++; return &s; } } @@ -278,10 +338,21 @@ Sound* AllocateSound() { CleanSounds(); for (auto& s : gSounds) { if (s.id == 0) { + s.add_index = gAddIndex++; return &s; } } + if (remove_old_sounds) { + RemoveOldSounds(); + for (auto& s : gSounds) { + if (s.id == 0) { + s.add_index = gAddIndex++; + return &s; + } + } + } + return nullptr; } diff --git a/game/overlord/common/ssound.h b/game/overlord/common/ssound.h index 4732779f95..edb1664de4 100644 --- a/game/overlord/common/ssound.h +++ b/game/overlord/common/ssound.h @@ -41,6 +41,8 @@ struct Sound { s32 auto_time; SoundParams params; SoundRecord* bank_entry; + + s64 add_index = 0; }; struct Curve { @@ -61,7 +63,7 @@ extern u32 sLastTick; void ssound_init_globals(); Sound* LookupSound(s32 id); -Sound* AllocateSound(); +Sound* AllocateSound(bool remove_old_sounds); s32 GetVolume(Sound* sound); void UpdateVolume(Sound* sound); s32 CalculateFalloffVolume(Vec3w* pos, s32 volume, s32 fo_curve, s32 fo_min, s32 fo_max); diff --git a/game/overlord/jak1/srpc.cpp b/game/overlord/jak1/srpc.cpp index a52bc63cc7..6b14a5e757 100644 --- a/game/overlord/jak1/srpc.cpp +++ b/game/overlord/jak1/srpc.cpp @@ -93,7 +93,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { if (!PollSema(gSema)) { if (gMusic) { if (!gMusicPause && !LookupSound(666)) { - Sound* music = AllocateSound(); + Sound* music = AllocateSound(false); if (music != nullptr) { gMusicFade = 0; gMusicFadeDir = 1; @@ -183,7 +183,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { break; } - sound = AllocateSound(); + sound = AllocateSound(false); if (!sound) { break; } diff --git a/game/overlord/jak2/srpc.cpp b/game/overlord/jak2/srpc.cpp index 5991b511a1..fd9547416f 100644 --- a/game/overlord/jak2/srpc.cpp +++ b/game/overlord/jak2/srpc.cpp @@ -40,7 +40,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { if (!PollSema(gSema)) { if (gMusic) { if (!gMusicPause && !LookupSound(666)) { - Sound* music = AllocateSound(); + Sound* music = AllocateSound(true); if (music != nullptr) { gMusicFade = 0; gMusicFadeDir = 1; @@ -117,7 +117,7 @@ void* RPC_Player(unsigned int /*fno*/, void* data, int size) { } else { // new sound - sound = AllocateSound(); + sound = AllocateSound(true); if (sound == nullptr) { // no free sounds break;