Files
ss/include/nw4r/snd/snd_SoundInstanceManager.h
2025-05-29 17:14:02 +02:00

187 lines
4.0 KiB
C++

#ifndef NW4R_SND_SOUND_INSTANCE_MANAGER_H
#define NW4R_SND_SOUND_INSTANCE_MANAGER_H
/*******************************************************************************
* headers
*/
#include <new>
#include "common.h"
#include "nw4r/snd/snd_InstancePool.h"
#include "nw4r/ut/ut_Lock.h"
#include "nw4r/ut/ut_algorithm.h"
#include <rvl/OS/OSMutex.h>
#include "nw4r/NW4RAssert.hpp"
/*******************************************************************************
* classes and functions
*/
namespace nw4r { namespace snd { namespace detail
{
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2f03c, 0x30a63...
template <class Sound>
class SoundInstanceManager
{
// methods
public:
// cdtors
SoundInstanceManager() { OSInitMutex(&mMutex); }
// methods
u32 Create(void *buffer, u32 size)
{
NW4RAssertPointerNonnull_Line(67, buffer);
ut::detail::AutoLock<OSMutex> lock(mMutex);
return mPool.Create(buffer, size);
}
void Destroy(void *buffer, u32 size)
{
NW4RAssertPointerNonnull_Line(86, buffer);
ut::detail::AutoLock<OSMutex> lock(mMutex);
mPool.Destroy(buffer, size);
}
Sound *Alloc(int priority, int ambientPriority)
{
int allocPriority =
ut::Clamp(priority + ambientPriority, Sound::PRIORITY_MIN,
Sound::PRIORITY_MAX);
ut::detail::AutoLock<OSMutex> lock(mMutex);
Sound *sound = nullptr;
while (!sound)
{
if (void *ptr = mPool.Alloc())
{
sound = new (ptr) Sound(this, priority, ambientPriority);
continue;
}
Sound *sound = GetLowestPrioritySound();
if (!sound)
return nullptr;
if (allocPriority < sound->CalcCurrentPlayerPriority())
return nullptr;
OSUnlockMutex(&mMutex);
NW4RCheckMessage_Line(133,
!Debug_GetWarningFlag(
Debug_GetDebugWarningFlagFromSoundType(
sound->GetSoundType())),
"Sound (id:%d) is stopped for not enough %s sound "
"instance.",
sound->GetId(),
Debug_GetSoundTypeString(sound->GetSoundType()));
sound->Stop(0);
OSLockMutex(&mMutex);
}
InsertPriorityList(sound, allocPriority);
return sound;
}
void Free(Sound *sound)
{
NW4RAssertPointerNonnull_Line(158, sound);
ut::detail::AutoLock<OSMutex> lock(mMutex);
if (mPriorityList.IsEmpty())
return;
RemovePriorityList(sound);
sound->~Sound();
mPool.Free(sound);
}
u32 GetActiveCount() const { return mPriorityList.GetSize(); }
Sound *GetLowestPrioritySound()
{
if (mPriorityList.IsEmpty())
return nullptr;
return &mPriorityList.GetFront();
}
void InsertPriorityList(Sound *sound, int priority)
{
decltype(mPriorityList.GetBeginIter()) itr =
mPriorityList.GetBeginIter();
for (; itr != mPriorityList.GetEndIter(); ++itr)
{
if (priority < itr->CalcCurrentPlayerPriority())
break;
}
mPriorityList.Insert(itr, sound);
}
void SortPriorityList()
{
int const TMP_NUM = Sound::PRIORITY_MAX + 1;
if (mPriorityList.GetSize() < 2)
return;
ut::detail::AutoLock<OSMutex> lock(mMutex);
typename Sound::PriorityLinkList tmpList[TMP_NUM];
while (!mPriorityList.IsEmpty())
{
Sound &front = mPriorityList.GetFront();
mPriorityList.PopFront();
tmpList[front.CalcCurrentPlayerPriority()].PushBack(&front);
}
for (int i = 0; i < TMP_NUM; i++)
{
while (!tmpList[i].IsEmpty())
{
Sound &front = tmpList[i].GetFront();
tmpList[i].PopFront();
mPriorityList.PushBack(&front);
}
}
}
void RemovePriorityList(Sound *sound) { mPriorityList.Erase(sound); }
void UpdatePriority(Sound *sound, int priority)
{
ut::detail::AutoLock<OSMutex> lock(mMutex);
RemovePriorityList(sound);
InsertPriorityList(sound, priority);
}
// members
private:
MemoryPool<Sound> mPool; // size 0x04, offset 0x00
typename Sound::PriorityLinkList mPriorityList; // size 0x0c, offset 0x04
OSMutex mMutex; // size 0x18, offset 0x10
}; // size 0x28
}}} // namespace nw4r::snd::detail
#endif // NW4R_SND_SOUND_INSTANCE_MANAGER_H