#pragma once #include #include #include #include #include "SFX/SFX.h" #include "Runtime/RetroTypes.hpp" #include "Runtime/Audio/CAudioSys.hpp" #include namespace metaforce { class CSfxManager { static std::vector* mpSfxTranslationTable; public: enum class ESfxChannels { Invalid = -1, Default = 0, Game, PauseScreen }; enum class ESfxAudibility { Aud0, Aud1, Aud2, Aud3 }; enum class EAuxEffect { None = -1, ReverbHi = 0, Chorus, ReverbStd, Delay }; class CBaseSfxWrapper; using CSfxHandle = std::shared_ptr; /* Original imp, kept for reference class CSfxHandle { static u32 mRefCount; u32 x0_idx; public: CSfxHandle(u32 id) : x0_idx(++mRefCount << 14 | (id & 0xFFFF)) {} }; */ class CSfxChannel { friend class CSfxManager; zeus::CVector3f x0_pos; zeus::CVector3f xc_; zeus::CVector3f x18_; zeus::CVector3f x24_; /* float x30_ = 0.f; float x34_ = 0.f; float x38_ = 0.f; u32 x3c_ = 0; bool x40_ = false; */ bool x44_listenerActive = false; std::unordered_set x48_handles; }; class CBaseSfxWrapper : public std::enable_shared_from_this { float x4_timeRemaining = 15.f; s16 x8_rank = 0; s16 xa_prio; // CSfxHandle xc_handle; TAreaId x10_area; bool x14_24_isActive : 1 = true; bool x14_25_isPlaying : 1 = false; bool x14_26_looped : 1; bool x14_27_inArea : 1 = true; bool x14_28_isReleased : 1 = false; bool x14_29_useAcoustics : 1; protected: bool m_isEmitter : 1 = false; bool m_isClosed : 1 = false; public: virtual ~CBaseSfxWrapper() = default; virtual void SetActive(bool v) { x14_24_isActive = v; } virtual void SetPlaying(bool v) { x14_25_isPlaying = v; } virtual void SetRank(short v) { x8_rank = v; } virtual void SetInArea(bool v) { x14_27_inArea = v; } virtual bool IsInArea() const { return x14_27_inArea; } virtual bool IsPlaying() const { return x14_25_isPlaying; } virtual bool UseAcoustics() const { return x14_29_useAcoustics; } virtual bool IsLooped() const { return x14_26_looped; } virtual bool IsActive() const { return x14_24_isActive; } virtual s16 GetRank() const { return x8_rank; } virtual s16 GetPriority() const { return xa_prio; } virtual TAreaId GetArea() const { return x10_area; } virtual CSfxHandle GetSfxHandle() { return shared_from_this(); } virtual void Play() = 0; virtual void Stop() = 0; virtual bool Ready() = 0; virtual ESfxAudibility GetAudible(const zeus::CVector3f&) = 0; virtual amuse::ObjToken GetVoice() const = 0; virtual u16 GetSfxId() const = 0; virtual void UpdateEmitterSilent() = 0; virtual void UpdateEmitter() = 0; virtual void SetReverb(float rev) = 0; bool IsEmitter() const { return m_isEmitter; } void Release() { x14_28_isReleased = true; x4_timeRemaining = 15.f; } bool IsReleased() const { return x14_28_isReleased; } void Close() { m_isClosed = true; } bool IsClosed() const { return m_isClosed; } float GetTimeRemaining() const { return x4_timeRemaining; } void SetTimeRemaining(float t) { x4_timeRemaining = t; } CBaseSfxWrapper(bool looped, s16 prio, /*const CSfxHandle& handle,*/ bool useAcoustics, TAreaId area) : xa_prio(prio), /*xc_handle(handle),*/ x10_area(area), x14_26_looped(looped), x14_29_useAcoustics(useAcoustics) {} }; class CSfxEmitterWrapper : public CBaseSfxWrapper { float x1a_reverb = 0.0f; CAudioSys::C3DEmitterParmData x24_parmData; amuse::ObjToken x50_emitterHandle; bool x54_ready = true; float x55_cachedMaxVol = 0.0f; public: bool IsPlaying() const override; void Play() override; void Stop() override; bool Ready() override; ESfxAudibility GetAudible(const zeus::CVector3f&) override; amuse::ObjToken GetVoice() const override { return x50_emitterHandle->getVoice(); } u16 GetSfxId() const override; void UpdateEmitterSilent() override; void UpdateEmitter() override; void SetReverb(float rev) override; CAudioSys::C3DEmitterParmData& GetEmitterData() { return x24_parmData; } amuse::ObjToken GetHandle() const { return x50_emitterHandle; } CSfxEmitterWrapper(bool looped, s16 prio, const CAudioSys::C3DEmitterParmData& data, /*const CSfxHandle& handle,*/ bool useAcoustics, TAreaId area) : CBaseSfxWrapper(looped, prio, /*handle,*/ useAcoustics, area), x24_parmData(data) { m_isEmitter = true; } }; class CSfxWrapper : public CBaseSfxWrapper { u16 x18_sfxId; amuse::ObjToken x1c_voiceHandle; float x20_vol; float x22_pan; bool x24_ready = true; public: bool IsPlaying() const override; void Play() override; void Stop() override; bool Ready() override; ESfxAudibility GetAudible(const zeus::CVector3f&) override { return ESfxAudibility::Aud3; } amuse::ObjToken GetVoice() const override { return x1c_voiceHandle; } u16 GetSfxId() const override; void UpdateEmitterSilent() override; void UpdateEmitter() override; void SetReverb(float rev) override; void SetVolume(float vol) { x20_vol = vol; } CSfxWrapper(bool looped, s16 prio, u16 sfxId, float vol, float pan, /*const CSfxHandle& handle,*/ bool useAcoustics, TAreaId area) : CBaseSfxWrapper(looped, prio, /*handle,*/ useAcoustics, area), x18_sfxId(sfxId), x20_vol(vol), x22_pan(pan) { m_isEmitter = false; } }; static std::array m_channels; static ESfxChannels m_currentChannel; static bool m_doUpdate; static void* m_usedSounds; static bool m_muted; static bool m_auxProcessingEnabled; static float m_reverbAmount; static EAuxEffect m_activeEffect; static EAuxEffect m_nextEffect; static amuse::ObjToken m_listener; static u16 kMaxPriority; static u16 kMedPriority; static u16 kInternalInvalidSfxId; static u32 kAllAreas; static bool LoadTranslationTable(CSimplePool* pool, const SObjectTag* tag); static bool IsAuxProcessingEnabled() { return m_auxProcessingEnabled; } static void SetChannel(ESfxChannels); static void KillAll(ESfxChannels); static void TurnOnChannel(ESfxChannels); static void TurnOffChannel(ESfxChannels); static ESfxChannels GetCurrentChannel() { return m_currentChannel; } static void AddListener(ESfxChannels channel, const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CVector3f& heading, const zeus::CVector3f& up, float frontRadius, float surroundRadius, float soundSpeed, u32 flags /* 0x1 for doppler */, float vol); static void UpdateListener(const zeus::CVector3f& pos, const zeus::CVector3f& dir, const zeus::CVector3f& heading, const zeus::CVector3f& up, float vol); static bool PlaySound(const CSfxHandle& handle); static void StopSound(const CSfxHandle& handle); static s16 GetRank(CBaseSfxWrapper* sfx); static void ApplyReverb(); static float GetReverbAmount(); static void PitchBend(const CSfxHandle& handle, float pitch); static void SfxVolume(const CSfxHandle& handle, float vol); static void SfxSpan(const CSfxHandle& handle, float span); static u16 TranslateSFXID(u16); static void SfxStop(const CSfxHandle& handle); static CSfxHandle SfxStart(u16 id, float vol, float pan, bool useAcoustics, s16 prio, bool looped, s32 areaId); static bool IsPlaying(const CSfxHandle& handle); static void RemoveEmitter(const CSfxHandle& handle); static void UpdateEmitter(const CSfxHandle& handle, const zeus::CVector3f& pos, const zeus::CVector3f& dir, float maxVol); static CSfxHandle AddEmitter(u16 id, const zeus::CVector3f& pos, const zeus::CVector3f& dir, bool useAcoustics, bool looped, s16 prio, s32 areaId); static CSfxHandle AddEmitter(u16 id, const zeus::CVector3f& pos, const zeus::CVector3f& dir, float vol, bool useAcoustics, bool looped, s16 prio, s32 areaId); static CSfxHandle AddEmitter(const CAudioSys::C3DEmitterParmData& parmData, bool useAcoustics, s16 prio, bool looped, s32 areaId); static void StopAndRemoveAllEmitters(); static void DisableAuxCallback(); static void EnableAuxCallback(); static void PrepareDelayCallback(const amuse::EffectDelayInfo& info); static void PrepareReverbStdCallback(const amuse::EffectReverbStdInfo& info); static void PrepareChorusCallback(const amuse::EffectChorusInfo& info); static void PrepareReverbHiCallback(const amuse::EffectReverbHiInfo& info); static void DisableAuxProcessing(); static void SetActiveAreas(const rstl::reserved_vector& areas); static void Update(float dt); static void Shutdown(); }; using CSfxHandle = CSfxManager::CSfxHandle; } // namespace metaforce