OpenBarnyard
 
Loading...
Searching...
No Matches
ASoundManager.h
Go to the documentation of this file.
1#pragma once
2#include "AWaveBank.h"
3#include "ASoundBank.h"
4
5#include <Toshi/TPString8.h>
6#include <Toshi/TTask.h>
7#include <Toshi/TSystem.h>
8#include <Toshi/T2Map.h>
9#include <Toshi/T2DList.h>
10#include <Toshi/T2Vector.h>
11#include <Toshi/T2SortedList.h>
12#include <Toshi/T2ObjectPool.h>
13
14#include <File/TFile.h>
15
16#include <Math/TVector4.h>
17
18#define ASOUNDMANAGER_MAX_NUM_CUE 128
19
20class ASoundManager : public Toshi::TTask
21 , public Toshi::TSingleton<ASoundManager>
22{
23public:
24 TDECLARE_CLASS( ASoundManager, Toshi::TTask );
25
26 class Cue;
27
28 struct S2 : public Toshi::T2DList<S2>::Node
29 {
30 };
31
32 struct S4 : public Toshi::T2DList<S4>::Node
33 {
34 };
35
37 {
38 Toshi::TVector4 Position = Toshi::TVector4::VEC_ZERO;
39 Toshi::TVector4 Velocity = Toshi::TVector4::VEC_ZERO;
40 Toshi::TVector4 Forward = Toshi::TVector4::VEC_ZERO;
41 Toshi::TVector4 Up = Toshi::TVector4::VEC_ZERO;
42 };
43
57
59 {
60 public:
61 static constexpr TSIZE MAX_NUM_PARAMS = 3;
62
63 public:
64 TFLOAT& operator[]( TUINT a_uiIndex )
65 {
66 TASSERT( a_uiIndex < MAX_NUM_PARAMS );
67 return aParams[ a_uiIndex ];
68 }
69
70 TFLOAT operator[]( TUINT a_uiIndex ) const
71 {
72 TASSERT( a_uiIndex < MAX_NUM_PARAMS );
73 return aParams[ a_uiIndex ];
74 }
75
76 public:
78 };
79
80 // NOTE: originally ChannelRef and ChannelRefLegacy are the same structure
81 // but it's a fucking mess to maintain and understand code if they're merged
82 // so I split them in two. It doesn't affect anything including compatibility
83 // since ChannelRefLegacy is not even created by the game.
84
85 struct ChannelRef : public Toshi::T2DList<ChannelRef>::Node
86 {
87 public:
94 };
95
96 struct TDEPRECATED ChannelRefLegacy : public Toshi::T2DList<ChannelRefLegacy>::Node
97 {
98 public:
99 using Callback_t = void ( * )( TINT a_iType, TINT a_iCueIndex, void* a_pUserData );
100
101 public:
104 };
105
106 struct StreamRef : public Toshi::T2DList<StreamRef>::Node
107 {
108 public:
111 void* pUnknown;
112 };
113
114 class SoundEvent : public Toshi::T2DList<SoundEvent>::Node
115 {
116 public:
117 SoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fStartTime, Cue* a_pCue, ASound::Sample* a_pWave, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
118 SoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fStartTime, Cue* a_pCue, ASound::Sample* a_pWave, TFLOAT a_fCustomParam1, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
119 SoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fStartTime, Cue* a_pCue, ASound::Sample* a_pWave, const EventParameters& a_rcCustomParams, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
120
121 public:
130 };
131
132 // Sorts sound events in the SoundEventList by the start time (from 0 to n)
134 {
135 TINT operator()( const SoundEvent& a_rcVal1, const SoundEvent& a_rcVal2 ) const
136 {
137 TFLOAT fStartTime1 = a_rcVal1.fStartTime;
138 TFLOAT fStartTime2 = a_rcVal2.fStartTime;
139
140 if ( fStartTime1 > fStartTime2 )
141 return 1;
142
143 if ( fStartTime1 >= fStartTime2 )
144 return 0;
145
146 return -1;
147 }
148 };
149
150 //-----------------------------------------------------------------------------
151 // Purpose: contains SoundEvents in sorted order, can be used in T2DList
152 //-----------------------------------------------------------------------------
153 using SoundEventList = Toshi::T2DListNodeWrapper<Toshi::T2SortedList<SoundEvent, Toshi::T2DList<SoundEvent>, SoundEventSortResults>>;
154
155 // Sorts lists of the events by the amount of stored events (from 0 to n)
157 {
158 TINT operator()( const SoundEventList& a_rcVal1, const SoundEventList& a_rcVal2 ) const
159 {
160 if ( a_rcVal1->Size() <= 0 )
161 return ( a_rcVal2->Size() == 0 ) ? 0 : -1;
162
163 if ( a_rcVal2->Size() <= 0 )
164 return 1;
165
166 return SoundEventSortResults()( *a_rcVal1->Begin(), *a_rcVal2->Begin() );
167 }
168 };
169
170 //-----------------------------------------------------------------------------
171 // Purpose: Cue is an only playable unit that can be created by ASoundManager.
172 // It contains all the channels (sounds) that are played by ASound.
173 //-----------------------------------------------------------------------------
174 class Cue : public Toshi::T2DList<Cue>::Node
175 {
176 public:
177 Cue();
178 ~Cue();
179
180 void Reset();
181
182 TBOOL HasEventOfType( SOUNDEVENT a_eEventType ) const;
183
184 TBOOL IsUsed() const { return fStartTime > 0.0f; }
185
186 public:
191 Toshi::TVector4 vecPosition;
195 Toshi::T2DList<ChannelRef> oChannelRefs;
197 Toshi::T2DList<ChannelRefLegacy> aChannelRefsLegacy[ 2 ];
198 Toshi::T2Vector<TINT, 15> vecLoopStarts;
199 };
200
201 //-----------------------------------------------------------------------------
202 // Purpose: stores common settings for specified groups of sounds.
203 //-----------------------------------------------------------------------------
204 struct Category
205 {
206 public:
211 // ...
212 Toshi::T2DList<Cue> PlayingCues;
213 };
214
215 //-----------------------------------------------------------------------------
216 // Purpose: stores list of event handlers that can be executed by the event
217 // loop in ASoundManager::Update
218 //-----------------------------------------------------------------------------
220 {
221 private:
222 struct EventHandler
223 {
224 public:
225 using Callback_t = void ( ASoundManager::* )( SoundEvent* a_pSoundEvent );
226
227 public:
228 Callback_t fnCallback = TNULL;
229 TUINT Unused = 0;
230 };
231
232 public:
233 SoundEventManager() = default;
235
236 void SetEventHandler( SOUNDEVENT a_eEventType, EventHandler::Callback_t a_fnHandler );
237 void ExecuteEvent( SOUNDEVENT a_eEventType, ASoundManager* a_pSoundManager, SoundEvent* a_pEvent );
238
239 private:
240 EventHandler m_aEventHandlers[ SOUNDEVENT_NUMOF ];
241 };
242
243 using PauseListener = Toshi::TListener<Toshi::TSystemManager, TBOOL, ASoundManager>;
244
245 static constexpr const TCHAR* SOUNDS_BASE_DIRECTORY = "Data/Sound/";
246 static constexpr TUINT MAX_NUM_CATEGORIES = 16;
247
248 friend AWaveBank;
249
250public:
253
254 //-----------------------------------------------------------------------------
255 // Toshi::TTask
256 //-----------------------------------------------------------------------------
257 virtual TBOOL Reset() override;
258 virtual TBOOL OnCreate() override;
259 virtual TBOOL OnUpdate( TFLOAT a_fDeltaTime ) override;
260 virtual void OnDestroy() override;
261
262 //-----------------------------------------------------------------------------
263 // Own methods
264 //-----------------------------------------------------------------------------
265
266 // Immediately plays cue and returns it's index. Use PlayCueEx for more settings.
267 TINT PlayCue( ASoundId a_iSound );
268
269 // Plays cue and returns it's index
270 TINT PlayCueEx( ASoundId a_iSound, TFLOAT a_fVolume, TBOOL a_bFlag, TFLOAT a_fDelay, TINT a_iTrack );
271
272 // Immediately stops cue and all it's sounds
273 void StopCue( TINT& a_rCueIndex );
274
275 // Asynchronously stop cue and all it's sounds
276 void StopCueAsync( TINT& a_rCueIndex, TFLOAT a_fDelay );
277
278 // Allows to control pause state of sounds
279 void PauseAllCues( TBOOL a_bPause );
280
281 // Returns index of an available cue that can be used to play sound
283
284 // Returns TTRUE if cue is playing
285 TBOOL IsCuePlaying( TINT a_iCueIndex );
286
287 // Cancels all queued events of specified type
288 void CancelCueEvents( Cue* a_pCue, SOUNDEVENT a_eEventType );
289
290 //-----------------------------------------------------------------------------
291 // Wavebanks
292 // ----------------------------------------------------------------------------
293 // They are storing information about different packs of files (usually .fsb
294 // if FMOD is being used) and their samples. Samples store technical info about
295 // flags, frequency and length making sure the sounds from soundbanks can get
296 // this information when neccessary.
297 //-----------------------------------------------------------------------------
298
299 // Returns pointer to a loaded wavebank or TNULL if not found
300 AWaveBank* FindWaveBank( const Toshi::TPString8& a_rcName );
301
302 // Loads info about all wavebanks from a specified PProperties file
303 TBOOL LoadWaveBanksInfo( const TCHAR* a_szFileName );
304
305 // Loads all samples (f.e. from fsb file) of a specified bank
306 TBOOL LoadWaveBankSamples( const Toshi::TPString8& a_rcName, AWaveBank::LOADFLAGS a_eLoadFlags, TINT a_iBufferSize );
307
308 //-----------------------------------------------------------------------------
309 // Soundbanks
310 // ----------------------------------------------------------------------------
311 // Unlike wavebanks, soundbanks store info about how each sound should be
312 // played by the engine. Such info includes volume, pitch, various
313 // randomizations and much much more...
314 //-----------------------------------------------------------------------------
315 // The sounds can be stored either with ASound or ASoundEx class.
316 // ASound class doesn't store any advanced settings for the sound.
317 // ASoundEx class allows sounds to have different volume, pitch and more.
318 //-----------------------------------------------------------------------------
319
320 // Returns pointer to a loaded soundbank or TNULL if not found
321 ASoundBank* FindSoundBank( const Toshi::TPString8& a_rcName );
322
323 // Loads soundbank if it's not loaded yet.
324 // If a_bSimpleSound is TFALSE, sounds are created from ASoundEx allowing many settings to be set from the properties file.
325 // Returns TTRUE if was (now) loaded.
326 TBOOL LoadSoundBank( const Toshi::TPString8& a_rcName, TBOOL a_bSimpleSound, TBOOL a_bLoadImmediately );
327
328 // Initialises sounds of the sound bank
329 void LoadSoundBankSamples( const Toshi::TPString8& a_rcName );
330
331private:
332 void CreatePlaySoundEvent( Cue* a_pCue, TINT a_iTrackIndex, TINT a_iFirstWaveIndex, TINT a_iLastWaveIndex, TINT a_iFlags, TFLOAT a_fDelay1, TFLOAT a_fDelay2 );
333
334 // Allocates new SoundEvent and adds it to the specified cue
335 SoundEvent* CreateSoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fDelay, Cue* a_pCue, ASound::Sample* a_pSample, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
336
337 // Allocates new SoundEvent and adds it to the specified cue
338 SoundEvent* CreateSoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fDelay, Cue* a_pCue, ASound::Sample* a_pSample, TFLOAT a_fCustomParam1, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
339
340 // Allocates new SoundEvent and adds it to the specified cue
341 SoundEvent* CreateSoundEvent( SOUNDEVENT a_eEventType, TFLOAT a_fDelay, Cue* a_pCue, ASound::Sample* a_pSample, const EventParameters& a_rcCustomParams, ChannelRef* a_pChannel, TINT a_iFlags, TINT a_iTrackIndex );
342
343 // Adds event to the cue and queues the cue to be played
344 void AddEventToCue( Cue* a_pCue, SoundEvent* a_pSoundEvent );
345
346 // Updates stream that has some unknown value (probably ASoundActivity). Returns TTRUE if stream is over
347 TBOOL UpdateStreamActivity( StreamRef* a_pStream );
348
349 // Updates stream that has Cue. Returns TTRUE if stream is over
350 TBOOL UpdateStreamCue( StreamRef* a_pStream );
351
352private:
353 //-----------------------------------------------------------------------------
354 // Event handlers
355 //-----------------------------------------------------------------------------
356 void EventHandler_PlaySound( SoundEvent* a_pEvent );
357 void EventHandler_PlayStream( SoundEvent* a_pEvent );
358 void EventHandler_StopAudio( SoundEvent* a_pEvent );
359 void EventHandler_UpdateChannelVolume( SoundEvent* a_pEvent );
360 void EventHandler_UpdateChannelFrequency( SoundEvent* a_pEvent );
361 void EventHandler_UpdatePosition( SoundEvent* a_pEvent );
362
363private:
364 TBOOL Initialise();
365
366 AWaveBank* LoadWaveBankFromAsset( const Toshi::TString8& a_strName, TUINT32 a_uiForcedFlags );
367 AWaveBank* AllocateWaveBank( const Toshi::TPString8& a_strBank, const Toshi::TPString8& a_strLibrary, const Toshi::TPString8& a_strType, const Toshi::TPString8& a_strPath );
368
369 TBOOL LoadSoundBankImpl( const TCHAR* a_szName, TBOOL a_bSimpleSound, TBOOL a_bLoadImmediately );
370
371private:
372 static TUINT GetCueIndex( Cue* a_pCue );
373
374public:
375 // Whether ALoadScreen should be updated while loading audio stream or not
377
378private:
379 inline static Toshi::TFileSystem* ms_pFileSystem;
380 inline static Toshi::T2Map<Toshi::TPString8, AWaveBank*, Toshi::TPString8::Comparator> ms_WaveBanks;
381 inline static TINT ms_iNumPauses;
382
383private:
384 Toshi::T2DynamicObjectPool<SoundEvent> m_SoundEventPool; // 0x20
385 Toshi::T2DynamicObjectPool<StreamRef> m_StreamRefPool; // 0x38
386 Toshi::T2DynamicObjectPool<ChannelRef> m_ChannelRefPool; // 0x50
387 Toshi::T2DynamicObjectPool<ChannelRefLegacy> m_ChannelRefLegacyPool; // 0x68
388 Toshi::T2Map<Toshi::TPString8, TSIZE, Toshi::TPString8::Comparator> m_CategoryIndices; // 0x80
389 Toshi::T2Map<TINT, ASound*> m_SoundIdToSound; // 0x98
390 Toshi::T2Map<TINT, ASoundLegacy*> m_SoundIdToSoundLegacy; // 0xB0
391 CameraData m_oCameraData; // 0xC8
392 Cue m_aCues[ ASOUNDMANAGER_MAX_NUM_CUE ]; // 0x108
393 S2 m_aS2[ 8 ]; // 0x4D08
394 Toshi::T2DList<StreamRef> m_StreamRefs; // 0x4E08
395 // ...
396 Category m_aCategories[ MAX_NUM_CATEGORIES ]; // 0x4E10
397 TINT m_iLastAvailableSoundExSlot; // 0x4F50
398 Toshi::T2SortedList<SoundEventList, Toshi::T2DList<SoundEventList>, SoundEventListSortResults> m_QueuedSortedEventLists; // 0x4F54
399 TFLOAT m_fCurrentTime; // 0x4F5C
400 SoundEventManager m_oEventManager; // 0x4F60
401 TBOOL m_bMuted; // 0x4FA8
402 TBOOL m_bUseMinHardwareChannels; // 0x4FA9
403 TINT m_iMinHWChannels; // 0x4FAC
404 TINT m_iNumChannels; // 0x4FB0
405 TINT m_iGlobalFrequency; // 0x4FB4
406 PauseListener m_PauseListener; // 0x4FB8
407 S4* m_pS4; // 0x4FCC
408 Toshi::T2DList<S4> m_FreeListS4; // 0x4FD0
409 Toshi::T2DList<S4> m_UnkList1; // 0x4FD8
410 Toshi::T2DList<ASoundBank> m_SoundBanks; // 0x4FE0
411 Toshi::T2DList<S2> m_FreeListS2; // 0x4FE8
412 // ...
413};
Core file system interface for the Toshi engine.
#define TASSERT(X,...)
Definition Defines.h:138
#define TDEPRECATED
Definition Defines.h:81
#define TDECLARE_CLASS(THIS_CLASS, PARENT_CLASS)
Definition TObject.h:38
unsigned int TUINT
Definition Typedefs.h:8
size_t TSIZE
Definition Typedefs.h:9
char TCHAR
Definition Typedefs.h:20
float TFLOAT
Definition Typedefs.h:4
#define TNULL
Definition Typedefs.h:23
uint32_t TUINT32
Definition Typedefs.h:13
int TINT
Definition Typedefs.h:7
#define TFALSE
Definition Typedefs.h:24
#define TTRUE
Definition Typedefs.h:25
bool TBOOL
Definition Typedefs.h:6
TINT32 ASoundId
Definition ASoundLegacy.h:5
#define ASOUNDMANAGER_MAX_NUM_CUE
Toshi::T2DListNodeWrapper< Toshi::T2SortedList< SoundEvent, Toshi::T2DList< SoundEvent >, SoundEventSortResults > > SoundEventList
virtual TBOOL OnCreate() override
void CancelCueEvents(Cue *a_pCue, SOUNDEVENT a_eEventType)
TINT GetAvailableCueIndex()
TBOOL LoadWaveBankSamples(const Toshi::TPString8 &a_rcName, AWaveBank::LOADFLAGS a_eLoadFlags, TINT a_iBufferSize)
TINT PlayCueEx(ASoundId a_iSound, TFLOAT a_fVolume, TBOOL a_bFlag, TFLOAT a_fDelay, TINT a_iTrack)
AWaveBank * FindWaveBank(const Toshi::TPString8 &a_rcName)
virtual TBOOL OnUpdate(TFLOAT a_fDeltaTime) override
virtual void OnDestroy() override
ASoundBank * FindSoundBank(const Toshi::TPString8 &a_rcName)
static constexpr const TCHAR * SOUNDS_BASE_DIRECTORY
@ SOUNDEVENT_UpdateChannelPosition
@ SOUNDEVENT_UpdateChannelVolume
@ SOUNDEVENT_UpdateChannelFrequency
TBOOL IsCuePlaying(TINT a_iCueIndex)
void LoadSoundBankSamples(const Toshi::TPString8 &a_rcName)
void StopCue(TINT &a_rCueIndex)
void StopCueAsync(TINT &a_rCueIndex, TFLOAT a_fDelay)
static TBOOL ms_bShouldUpdateLoadingScreen
Toshi::TListener< Toshi::TSystemManager, TBOOL, ASoundManager > PauseListener
TBOOL LoadSoundBank(const Toshi::TPString8 &a_rcName, TBOOL a_bSimpleSound, TBOOL a_bLoadImmediately)
TINT PlayCue(ASoundId a_iSound)
virtual TBOOL Reset() override
TBOOL LoadWaveBanksInfo(const TCHAR *a_szFileName)
void PauseAllCues(TBOOL a_bPause)
static constexpr TUINT MAX_NUM_CATEGORIES
TFLOAT operator[](TUINT a_uiIndex) const
TFLOAT aParams[MAX_NUM_PARAMS]
TFLOAT & operator[](TUINT a_uiIndex)
static constexpr TSIZE MAX_NUM_PARAMS
ASound::Sample * pSample
void(*)(TINT a_iType, TINT a_iCueIndex, void *a_pUserData) Callback_t
SoundEvent(SOUNDEVENT a_eEventType, TFLOAT a_fStartTime, Cue *a_pCue, ASound::Sample *a_pWave, ChannelRef *a_pChannel, TINT a_iFlags, TINT a_iTrackIndex)
EventParameters oParameters
TINT operator()(const SoundEvent &a_rcVal1, const SoundEvent &a_rcVal2) const
TINT operator()(const SoundEventList &a_rcVal1, const SoundEventList &a_rcVal2) const
Toshi::TVector4 vecPosition
TBOOL IsUsed() const
Toshi::T2DList< ChannelRef > oChannelRefs
Toshi::T2DList< ChannelRefLegacy > aChannelRefsLegacy[2]
SoundEventList oEventList
TBOOL HasEventOfType(SOUNDEVENT a_eEventType) const
Toshi::T2Vector< TINT, 15 > vecLoopStarts
Toshi::T2DList< Cue > PlayingCues
void SetEventHandler(SOUNDEVENT a_eEventType, EventHandler::Callback_t a_fnHandler)
void ExecuteEvent(SOUNDEVENT a_eEventType, ASoundManager *a_pSoundManager, SoundEvent *a_pEvent)
TUINT32 LOADFLAGS
Definition AWaveBank.h:13