summaryrefslogtreecommitdiffstats
path: root/game/code/sound
diff options
context:
space:
mode:
Diffstat (limited to 'game/code/sound')
-rw-r--r--game/code/sound/allsound.cpp7
-rw-r--r--game/code/sound/avatar/allsoundavatar.cpp5
-rw-r--r--game/code/sound/avatar/avatarsoundplayer.cpp187
-rw-r--r--game/code/sound/avatar/avatarsoundplayer.h63
-rw-r--r--game/code/sound/avatar/carsoundparameters.cpp1184
-rw-r--r--game/code/sound/avatar/carsoundparameters.h302
-rw-r--r--game/code/sound/avatar/icarsoundparameters.h168
-rw-r--r--game/code/sound/avatar/soundavatar.cpp245
-rw-r--r--game/code/sound/avatar/soundavatar.h78
-rw-r--r--game/code/sound/avatar/vehiclesounddebugpage.cpp138
-rw-r--r--game/code/sound/avatar/vehiclesounddebugpage.h75
-rw-r--r--game/code/sound/avatar/vehiclesoundplayer.cpp2499
-rw-r--r--game/code/sound/avatar/vehiclesoundplayer.h162
-rw-r--r--game/code/sound/dialog/alldialog.cpp11
-rw-r--r--game/code/sound/dialog/conversation.cpp408
-rw-r--r--game/code/sound/dialog/conversation.h79
-rw-r--r--game/code/sound/dialog/conversationmatcher.cpp237
-rw-r--r--game/code/sound/dialog/conversationmatcher.h57
-rw-r--r--game/code/sound/dialog/dialogcoordinator.cpp971
-rw-r--r--game/code/sound/dialog/dialogcoordinator.h84
-rw-r--r--game/code/sound/dialog/dialogline.cpp1018
-rw-r--r--game/code/sound/dialog/dialogline.h172
-rw-r--r--game/code/sound/dialog/dialoglist.cpp1259
-rw-r--r--game/code/sound/dialog/dialoglist.h109
-rw-r--r--game/code/sound/dialog/dialogpriorityqueue.cpp536
-rw-r--r--game/code/sound/dialog/dialogpriorityqueue.h99
-rw-r--r--game/code/sound/dialog/dialogqueueelement.cpp951
-rw-r--r--game/code/sound/dialog/dialogqueueelement.h158
-rw-r--r--game/code/sound/dialog/dialogqueuetype.h24
-rw-r--r--game/code/sound/dialog/dialogselectiongroup.cpp376
-rw-r--r--game/code/sound/dialog/dialogselectiongroup.h91
-rw-r--r--game/code/sound/dialog/dialogsounddebugpage.cpp243
-rw-r--r--game/code/sound/dialog/dialogsounddebugpage.h89
-rw-r--r--game/code/sound/dialog/playabledialog.cpp87
-rw-r--r--game/code/sound/dialog/playabledialog.h48
-rw-r--r--game/code/sound/dialog/selectabledialog.cpp214
-rw-r--r--game/code/sound/dialog/selectabledialog.h118
-rw-r--r--game/code/sound/dialog/selectabledialoglist.h24
-rw-r--r--game/code/sound/listener.cpp236
-rw-r--r--game/code/sound/listener.h56
-rw-r--r--game/code/sound/movingpositional/actorplayer.cpp194
-rw-r--r--game/code/sound/movingpositional/actorplayer.h77
-rw-r--r--game/code/sound/movingpositional/aivehiclesoundplayer.cpp99
-rw-r--r--game/code/sound/movingpositional/aivehiclesoundplayer.h53
-rw-r--r--game/code/sound/movingpositional/allmovingposn.cpp9
-rw-r--r--game/code/sound/movingpositional/animobjsoundplayer.cpp202
-rw-r--r--game/code/sound/movingpositional/animobjsoundplayer.h70
-rw-r--r--game/code/sound/movingpositional/avatarvehicleposnplayer.cpp208
-rw-r--r--game/code/sound/movingpositional/avatarvehicleposnplayer.h58
-rw-r--r--game/code/sound/movingpositional/movingsoundmanager.cpp747
-rw-r--r--game/code/sound/movingpositional/movingsoundmanager.h108
-rw-r--r--game/code/sound/movingpositional/platformsoundplayer.cpp209
-rw-r--r--game/code/sound/movingpositional/platformsoundplayer.h74
-rw-r--r--game/code/sound/movingpositional/trafficsoundplayer.cpp458
-rw-r--r--game/code/sound/movingpositional/trafficsoundplayer.h83
-rw-r--r--game/code/sound/movingpositional/vehicleposnsoundplayer.cpp258
-rw-r--r--game/code/sound/movingpositional/vehicleposnsoundplayer.h81
-rw-r--r--game/code/sound/movingpositional/waspsoundplayer.cpp260
-rw-r--r--game/code/sound/movingpositional/waspsoundplayer.h71
-rw-r--r--game/code/sound/music/allmusic.cpp1
-rw-r--r--game/code/sound/music/musicplayer.cpp2284
-rw-r--r--game/code/sound/music/musicplayer.h344
-rw-r--r--game/code/sound/nis/allnissound.cpp1
-rw-r--r--game/code/sound/nis/nissoundplayer.cpp388
-rw-r--r--game/code/sound/nis/nissoundplayer.h115
-rw-r--r--game/code/sound/nisenum.h41
-rw-r--r--game/code/sound/positionalsoundplayer.cpp283
-rw-r--r--game/code/sound/positionalsoundplayer.h109
-rw-r--r--game/code/sound/simpsonssoundplayer.cpp539
-rw-r--r--game/code/sound/simpsonssoundplayer.h136
-rw-r--r--game/code/sound/soundcluster.cpp276
-rw-r--r--game/code/sound/soundcluster.h103
-rw-r--r--game/code/sound/soundclusternameenum.h51
-rw-r--r--game/code/sound/soundcollisiondata.h58
-rw-r--r--game/code/sound/sounddebug/allsounddebug.cpp2
-rw-r--r--game/code/sound/sounddebug/sounddebugdisplay.cpp438
-rw-r--r--game/code/sound/sounddebug/sounddebugdisplay.h86
-rw-r--r--game/code/sound/sounddebug/sounddebugpage.cpp161
-rw-r--r--game/code/sound/sounddebug/sounddebugpage.h67
-rw-r--r--game/code/sound/soundfx/allsoundfx.cpp14
-rw-r--r--game/code/sound/soundfx/gcreverbcontroller.cpp108
-rw-r--r--game/code/sound/soundfx/gcreverbcontroller.h54
-rw-r--r--game/code/sound/soundfx/ipositionalsoundsettings.h59
-rw-r--r--game/code/sound/soundfx/ireverbsettings.h73
-rw-r--r--game/code/sound/soundfx/positionalsoundsettings.cpp180
-rw-r--r--game/code/sound/soundfx/positionalsoundsettings.h80
-rw-r--r--game/code/sound/soundfx/ps2reverbcontroller.cpp124
-rw-r--r--game/code/sound/soundfx/ps2reverbcontroller.h54
-rw-r--r--game/code/sound/soundfx/reverbcontroller.cpp410
-rw-r--r--game/code/sound/soundfx/reverbcontroller.h83
-rw-r--r--game/code/sound/soundfx/reverbsettings.cpp133
-rw-r--r--game/code/sound/soundfx/reverbsettings.h158
-rw-r--r--game/code/sound/soundfx/soundeffectplayer.cpp249
-rw-r--r--game/code/sound/soundfx/soundeffectplayer.h122
-rw-r--r--game/code/sound/soundfx/soundfxfrontendlogic.cpp137
-rw-r--r--game/code/sound/soundfx/soundfxfrontendlogic.h50
-rw-r--r--game/code/sound/soundfx/soundfxgameplaylogic.cpp1212
-rw-r--r--game/code/sound/soundfx/soundfxgameplaylogic.h130
-rw-r--r--game/code/sound/soundfx/soundfxlogic.cpp322
-rw-r--r--game/code/sound/soundfx/soundfxlogic.h91
-rw-r--r--game/code/sound/soundfx/soundfxpauselogic.cpp98
-rw-r--r--game/code/sound/soundfx/soundfxpauselogic.h50
-rw-r--r--game/code/sound/soundfx/win32reverbcontroller.cpp127
-rw-r--r--game/code/sound/soundfx/win32reverbcontroller.h54
-rw-r--r--game/code/sound/soundfx/xboxreverbcontroller.cpp127
-rw-r--r--game/code/sound/soundfx/xboxreverbcontroller.h54
-rw-r--r--game/code/sound/soundloader.cpp601
-rw-r--r--game/code/sound/soundloader.h98
-rw-r--r--game/code/sound/soundmanager.cpp2193
-rw-r--r--game/code/sound/soundmanager.h377
-rw-r--r--game/code/sound/soundrenderer/allsoundrenderer.cpp14
-rw-r--r--game/code/sound/soundrenderer/dasoundgroup.h100
-rw-r--r--game/code/sound/soundrenderer/dasoundplayer.cpp1191
-rw-r--r--game/code/sound/soundrenderer/fader.cpp483
-rw-r--r--game/code/sound/soundrenderer/fader.h146
-rw-r--r--game/code/sound/soundrenderer/idasoundresource.h172
-rw-r--r--game/code/sound/soundrenderer/idasoundtuner.h205
-rw-r--r--game/code/sound/soundrenderer/musicsoundplayer.cpp300
-rw-r--r--game/code/sound/soundrenderer/musicsoundplayer.h112
-rw-r--r--game/code/sound/soundrenderer/playermanager.cpp989
-rw-r--r--game/code/sound/soundrenderer/playermanager.h185
-rw-r--r--game/code/sound/soundrenderer/soundallocatedresource.cpp429
-rw-r--r--game/code/sound/soundrenderer/soundallocatedresource.h249
-rw-r--r--game/code/sound/soundrenderer/soundconstants.h0
-rw-r--r--game/code/sound/soundrenderer/sounddynaload.cpp954
-rw-r--r--game/code/sound/soundrenderer/sounddynaload.h199
-rw-r--r--game/code/sound/soundrenderer/soundnucleus.cpp594
-rw-r--r--game/code/sound/soundrenderer/soundnucleus.hpp70
-rw-r--r--game/code/sound/soundrenderer/soundplayer.h468
-rw-r--r--game/code/sound/soundrenderer/soundrenderingmanager.cpp1545
-rw-r--r--game/code/sound/soundrenderer/soundrenderingmanager.h187
-rw-r--r--game/code/sound/soundrenderer/soundresource.cpp555
-rw-r--r--game/code/sound/soundrenderer/soundresource.h152
-rw-r--r--game/code/sound/soundrenderer/soundresourcemanager.cpp527
-rw-r--r--game/code/sound/soundrenderer/soundresourcemanager.h164
-rw-r--r--game/code/sound/soundrenderer/soundsystem.h118
-rw-r--r--game/code/sound/soundrenderer/soundtuner.cpp1241
-rw-r--r--game/code/sound/soundrenderer/soundtuner.h253
-rw-r--r--game/code/sound/soundrenderer/tunerdebugpage.cpp231
-rw-r--r--game/code/sound/soundrenderer/tunerdebugpage.h68
-rw-r--r--game/code/sound/soundrenderer/wireplayers.cpp1
-rw-r--r--game/code/sound/soundrenderer/wiresystem.cpp104
-rw-r--r--game/code/sound/soundrenderercallback.cpp181
-rw-r--r--game/code/sound/soundrenderercallback.h70
-rw-r--r--game/code/sound/tuning/allsoundtuning.cpp1
-rw-r--r--game/code/sound/tuning/globalsettings.cpp467
-rw-r--r--game/code/sound/tuning/globalsettings.h224
-rw-r--r--game/code/sound/tuning/iglobalsettings.h128
148 files changed, 42369 insertions, 0 deletions
diff --git a/game/code/sound/allsound.cpp b/game/code/sound/allsound.cpp
new file mode 100644
index 0000000..9d10b15
--- /dev/null
+++ b/game/code/sound/allsound.cpp
@@ -0,0 +1,7 @@
+#include <sound/listener.cpp>
+#include <sound/simpsonssoundplayer.cpp>
+#include <sound/soundcluster.cpp>
+#include <sound/soundloader.cpp>
+#include <sound/soundmanager.cpp>
+#include <sound/soundrenderercallback.cpp>
+#include <sound/positionalsoundplayer.cpp>
diff --git a/game/code/sound/avatar/allsoundavatar.cpp b/game/code/sound/avatar/allsoundavatar.cpp
new file mode 100644
index 0000000..ff0df8f
--- /dev/null
+++ b/game/code/sound/avatar/allsoundavatar.cpp
@@ -0,0 +1,5 @@
+#include <sound/avatar/avatarsoundplayer.cpp>
+#include <sound/avatar/carsoundparameters.cpp>
+#include <sound/avatar/soundavatar.cpp>
+#include <sound/avatar/vehiclesoundplayer.cpp>
+#include <sound/avatar/vehiclesounddebugpage.cpp> \ No newline at end of file
diff --git a/game/code/sound/avatar/avatarsoundplayer.cpp b/game/code/sound/avatar/avatarsoundplayer.cpp
new file mode 100644
index 0000000..4f6df3a
--- /dev/null
+++ b/game/code/sound/avatar/avatarsoundplayer.cpp
@@ -0,0 +1,187 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: avatarsoundplayer.cpp
+//
+// Description: Implementation of AvatarSoundPlayer, which directs the
+// playing of avatar-related sounds
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+#include <radfactory.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/avatar/avatarsoundplayer.h>
+
+#include <mission/gameplaymanager.h>
+#include <worldsim/avatarmanager.h>
+
+#include <sound/avatar/soundavatar.h>
+#include <sound/avatar/carsoundparameters.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// AvatarSoundPlayer::AvatarSoundPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+AvatarSoundPlayer::AvatarSoundPlayer()
+{
+ int i;
+
+ for( i = 0; i < MAX_PLAYERS; i++ )
+ {
+ m_avatars[i] = NULL;
+ }
+}
+
+//==============================================================================
+// AvatarSoundPlayer::~AvatarSoundPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+AvatarSoundPlayer::~AvatarSoundPlayer()
+{
+ int i;
+
+ for( i = 0; i < MAX_PLAYERS; i++ )
+ {
+ if( m_avatars[i] != NULL )
+ {
+ delete m_avatars[i];
+ }
+ }
+}
+
+//=============================================================================
+// AvatarSoundPlayer::Initialize
+//=============================================================================
+// Description: Do the initialization stuff for the avatar sound subsystem
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void AvatarSoundPlayer::Initialize()
+{
+ //
+ // Must register the carSoundParameters factory method with RadScript before
+ // the script creating these objects gets run
+ //
+ ::radFactoryRegister( "carSoundParameters", (radFactoryOutParamProc*) ::CarSoundParameterObjCreate );
+}
+
+//=============================================================================
+// AvatarSoundPlayer::UpdateOncePerFrame
+//=============================================================================
+// Description: Update function. Used for stuff that either doesn't need to
+// be called often and/or uses expensive math.
+//
+// Parameters: elapsedTime - time since last frame in msecs
+//
+// Return: void
+//
+//=============================================================================
+void AvatarSoundPlayer::UpdateOncePerFrame( unsigned int elapsedTime )
+{
+ int i;
+
+ for( i = 0; i < MAX_PLAYERS; i++ )
+ {
+ if( m_avatars[i] != NULL )
+ {
+ m_avatars[i]->UpdateOncePerFrame( elapsedTime );
+ }
+ }
+}
+
+//=============================================================================
+// AvatarSoundPlayer::OnBeginGameplay
+//=============================================================================
+// Description: Create SoundAvatar objects when gameplay begins
+//
+// Parameters: None
+//
+// Return: true if player 0 in car, false otherwise
+//
+//=============================================================================
+bool AvatarSoundPlayer::OnBeginGameplay()
+{
+ unsigned int i;
+ unsigned int numPlayers = GetGameplayManager()->GetNumPlayers();
+
+ for( i = 0; i < numPlayers; i++ )
+ {
+ rAssert( m_avatars[i] == NULL );
+
+ m_avatars[i] = new(GMA_LEVEL_AUDIO) SoundAvatar( GetAvatarManager()->GetAvatarForPlayer( i ) );
+ }
+
+ return( GetAvatarManager()->GetAvatarForPlayer( 0 )->IsInCar() );
+}
+
+//=============================================================================
+// AvatarSoundPlayer::OnEndGameplay
+//=============================================================================
+// Description: Destroy SoundAvatar objects when gameplay ends
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void AvatarSoundPlayer::OnEndGameplay()
+{
+ int i;
+
+ //
+ // Destroy the avatar trackers, since we won't have avatars anymore until
+ // gameplay restarts
+ //
+ for( i = 0; i < MAX_PLAYERS; i++ )
+ {
+ if( m_avatars[i] != NULL )
+ {
+ delete m_avatars[i];
+ m_avatars[i] = NULL;
+ }
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/avatar/avatarsoundplayer.h b/game/code/sound/avatar/avatarsoundplayer.h
new file mode 100644
index 0000000..ce8bacd
--- /dev/null
+++ b/game/code/sound/avatar/avatarsoundplayer.h
@@ -0,0 +1,63 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: avatarsoundplayer.h
+//
+// Description: Declaration of AvatarSoundPlayer class, which directs the
+// playing of avatar-related sounds
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef AVATARSOUNDPLAYER_H
+#define AVATARSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <constants/maxplayers.h>
+
+//========================================
+// Forward References
+//========================================
+
+class SoundAvatar;
+
+//=============================================================================
+//
+// Synopsis: AvatarSoundPlayer
+//
+//=============================================================================
+
+class AvatarSoundPlayer
+{
+ public:
+ AvatarSoundPlayer();
+ virtual ~AvatarSoundPlayer();
+
+ void Initialize();
+
+ void UpdateOncePerFrame( unsigned int elapsedTime );
+
+ //
+ // Returns true if first player in car, false otherwise
+ //
+ bool OnBeginGameplay();
+
+ void OnEndGameplay();
+
+ private:
+ //Prevent wasteful constructor creation.
+ AvatarSoundPlayer( const AvatarSoundPlayer& original );
+ AvatarSoundPlayer& operator=( const AvatarSoundPlayer& rhs );
+
+ //
+ // One SoundAvatar to track activity of each Avatar object
+ //
+ SoundAvatar* m_avatars[MAX_PLAYERS];
+};
+
+
+#endif // AVATARSOUNDPLAYER_H
+
diff --git a/game/code/sound/avatar/carsoundparameters.cpp b/game/code/sound/avatar/carsoundparameters.cpp
new file mode 100644
index 0000000..870c13f
--- /dev/null
+++ b/game/code/sound/avatar/carsoundparameters.cpp
@@ -0,0 +1,1184 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: carsoundparameters.cpp
+//
+// Description: Implement carSoundParameters
+//
+// History: 01/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <string.h>
+
+#include <raddebugwatch.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/avatar/carsoundparameters.h>
+
+#include <memory/srrmemory.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Initialially the list is empty
+//
+carSoundParameters* radLinkedClass< carSoundParameters >::s_pLinkedClassHead = NULL;
+carSoundParameters* radLinkedClass< carSoundParameters >::s_pLinkedClassTail = NULL;
+
+static float s_maxPitchDefault = 5.0f;
+static float s_inAirIdleDefault = 0.2f;
+static float s_inAirThrottleDefault = 2.0f;
+static float s_powerslideMinDefault = 0.2f;
+static float s_powerslideMaxDefault = 2.0f;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// carSoundParameters::carSoundParameters
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+carSoundParameters::carSoundParameters() :
+ radRefCount( 0 ),
+ m_clipRPM( 3000 ),
+ m_engineClipName( NULL ),
+ m_idleClipName( NULL ),
+ m_damagedClipName( NULL ),
+ m_hornClipName( NULL ),
+ m_carOpenClipName( NULL ),
+ m_carCloseClipName( NULL ),
+ m_overlayClipName( NULL ),
+ m_roadSkidClipName( NULL ),
+ m_dirtSkidClipName( NULL ),
+ m_backupClipName( NULL ),
+ m_downshiftDamper( 0.05f ),
+ m_attackTime( 100 ),
+ m_delayTime( 50 ),
+ m_decayTime( 200 ),
+ m_decayFinishTrim( 0.75f ),
+ m_maxReverseKmh( 50.0f ),
+ m_minReversePitch( 1.5f ),
+ m_maxReversePitch( 3.0f ),
+ m_damageStartPcnt( 0.4f ),
+ m_damageVolumeRange( m_damageStartPcnt ),
+ m_damageStartTrim( 0.0f ),
+ m_damageMaxTrim( 1.0f ),
+ m_idleEnginePitch( 1.0f ),
+ m_inAirThrottlePitch( s_inAirThrottleDefault ),
+ m_inAirIdlePitch( s_inAirIdleDefault ),
+ m_inAirResponseMsecs( 500 ),
+ m_burnoutMinPitch( 0.5f ),
+ m_burnoutMaxPitch( 1.3f ),
+ m_powerslideMinPitch( s_powerslideMinDefault ),
+ m_powerslideMaxPitch( s_powerslideMaxDefault ),
+ m_msecsPerOctave( 500 )
+{
+ unsigned int i;
+
+ //
+ // Shift point defaults
+ //
+ m_shiftPoints[0] = 0.01f;
+ m_shiftPoints[1] = 0.30f;
+ m_shiftPoints[2] = 0.45f;
+ m_shiftPoints[3] = 0.70f;
+ m_shiftPoints[4] = 0.85f;
+ m_shiftPoints[5] = 0.95f;
+
+ m_shiftPoints[MAX_GEARS] = 1.0f;
+
+ //
+ // Pitch range and gear shift defaults
+ //
+ for( i = 0; i < MAX_GEARS; i++ )
+ {
+ m_minPitch[i] = 0.5f;
+ m_maxPitch[i] = s_maxPitchDefault;
+
+ m_gearShiftPitchDrop[i] = 0.2f;
+ }
+}
+
+//==============================================================================
+// carSoundParameters::~carSoundParameters
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+carSoundParameters::~carSoundParameters()
+{
+ if( m_engineClipName != NULL )
+ {
+ delete [] m_engineClipName;
+ }
+ if( m_idleClipName != NULL )
+ {
+ delete [] m_idleClipName;
+ }
+ if( m_damagedClipName != NULL )
+ {
+ delete [] m_damagedClipName;
+ }
+ if( m_hornClipName != NULL )
+ {
+ delete [] m_hornClipName;
+ }
+ if( m_carOpenClipName != NULL )
+ {
+ delete [] m_carOpenClipName;
+ }
+ if( m_carCloseClipName != NULL )
+ {
+ delete [] m_carCloseClipName;
+ }
+ if( m_overlayClipName != NULL )
+ {
+ delete [] m_overlayClipName;
+ }
+ if( m_roadSkidClipName != NULL )
+ {
+ delete [] m_roadSkidClipName;
+ }
+ if( m_dirtSkidClipName != NULL )
+ {
+ delete [] m_dirtSkidClipName;
+ }
+ if( m_backupClipName != NULL )
+ {
+ delete [] m_backupClipName;
+ }
+}
+
+//=============================================================================
+// carSoundParameters::SetWatcherName
+//=============================================================================
+// Description: Set the name of this object, since it's usually stored
+// in radScript's data structures. FOR DEBUGGING ONLY. We use
+// this to give the car a name for Watcher tuning.
+//
+// Parameters: name - name of car
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetWatcherName( const char* name )
+{
+#ifndef RAD_RELEASE
+ unsigned int i;
+ char label[50];
+ char watcherGroup[50];
+
+ sprintf( watcherGroup, "Sound::%s", name );
+
+ //
+ // Register members with Watcher for tweakage
+ //
+ for( i = 1; i <= MAX_GEARS; i++ )
+ {
+ sprintf( label, "Min pitch: gear %d", i );
+ radDbgWatchAddFloat( &m_minPitch[i-1], label, watcherGroup, NULL, NULL, 0.0f, 10.0f );
+
+ sprintf( label, "Max pitch: gear %d", i );
+ radDbgWatchAddFloat( &m_maxPitch[i-1], label, watcherGroup, NULL, NULL, 0.0f, 10.0f );
+
+ sprintf( label, "Pitch drop: gear %d", i );
+ radDbgWatchAddFloat( &m_gearShiftPitchDrop[i-1], label, watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ }
+
+ for( i = 1; i <= MAX_GEARS + 1; i++ )
+ {
+ sprintf( label, "Shift point: gear %d", i );
+ radDbgWatchAddFloat( &m_shiftPoints[i-1], label, watcherGroup );
+ }
+
+ radDbgWatchAddFloat( &m_downshiftDamper, "Downshift damper", watcherGroup );
+ radDbgWatchAddFloat( &m_attackTime, "Attack time (msecs)", watcherGroup, NULL, NULL, 0, 2000.0f );
+ radDbgWatchAddUnsignedInt( &m_delayTime, "Delay time (msecs)", watcherGroup, NULL, NULL, 0, 2000 );
+ radDbgWatchAddFloat( &m_decayTime, "Decay time (msecs)", watcherGroup, NULL, NULL, 0, 2000.0f );
+ radDbgWatchAddFloat( &m_decayFinishTrim, "Decay finish trim", watcherGroup );
+ radDbgWatchAddFloat( &m_maxReverseKmh, "Max reverse kmh", watcherGroup, NULL, NULL, 0.0f, 200.0f );
+ radDbgWatchAddFloat( &m_minReversePitch, "Min reverse pitch", watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ radDbgWatchAddFloat( &m_maxReversePitch, "Max reverse pitch", watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ radDbgWatchAddFloat( &m_damageStartPcnt, "Damage start", watcherGroup );
+ radDbgWatchAddFloat( &m_damageVolumeRange, "Damage max volume life %", watcherGroup );
+ radDbgWatchAddFloat( &m_damageStartTrim, "Damage start trim", watcherGroup );
+ radDbgWatchAddFloat( &m_damageMaxTrim, "Damage max trim", watcherGroup );
+ radDbgWatchAddFloat( &m_idleEnginePitch, "Idle engine pitch", watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ radDbgWatchAddFloat( &m_inAirThrottlePitch, "In air throttle pitch", watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ radDbgWatchAddFloat( &m_inAirIdlePitch, "In air idle pitch", watcherGroup, NULL, NULL, 0.0f, 10.0f );
+ radDbgWatchAddUnsignedInt( &m_inAirResponseMsecs, "In air response time (msecs)", watcherGroup, NULL, NULL, 0, 2000 );
+#endif
+}
+
+//=============================================================================
+// carSoundParameters::SetShiftPoint
+//=============================================================================
+// Description: Set the percentage of top speed at which we shift to a
+// given gear
+//
+// Parameters: gear - gear to be shifted to
+// lowPercent - percentage of top speed at which we downshift
+// highPercent - percentage of top speed at which we upshift
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetShiftPoint( unsigned int gear, float percent )
+{
+ rAssert( gear > 0 );
+ rAssert( gear <= MAX_GEARS );
+ rAssert( percent > 0.0f );
+ rAssert( percent <= 1.0f );
+
+ m_shiftPoints[gear-1] = percent;
+}
+
+//=============================================================================
+// carSoundParameters::GetShiftPoint
+//=============================================================================
+// Description: Get the percentage of top speed at which we shift up from a
+// given gear
+//
+// Parameters: gear - gear we're currently in
+//
+// Return: shift point as percentage of top speed
+//
+//=============================================================================
+float carSoundParameters::GetShiftPoint( int gear )
+{
+ if( gear > 0 )
+ {
+ return( m_shiftPoints[gear-1] );
+ }
+ else
+ {
+ return( 0.0f );
+ }
+}
+
+//=============================================================================
+// carSoundParameters::SetAttackTimeMsecs
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( float msecs )
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetAttackTimeMsecs( float msecs )
+{
+ m_attackTime = msecs;
+}
+
+//=============================================================================
+// carSoundParameters::SetDelayTimeMsecs
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int msecs )
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDelayTimeMsecs( unsigned int msecs )
+{
+ m_delayTime = msecs;
+}
+
+//=============================================================================
+// carSoundParameters::SetDecayTimeMsecs
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( float msecs )
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDecayTimeMsecs( float msecs )
+{
+ m_decayTime = msecs;
+}
+
+//=============================================================================
+// carSoundParameters::SetDecayFinishTrim
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( float trim )
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDecayFinishTrim( float trim )
+{
+ m_decayFinishTrim = trim;
+}
+
+//=============================================================================
+// carSoundParameters::SetDownshiftDamperSize
+//=============================================================================
+// Description: Amount that we can drop below the shift point to avoid
+// downshifting
+//
+// Parameters: percent - percentage of top speed that acts as the buffer
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDownshiftDamperSize( float percent )
+{
+ rAssert( percent >= 0.0f );
+ rAssert( percent <= 1.0f );
+
+ m_downshiftDamper = percent;
+}
+
+//=============================================================================
+// carSoundParameters::SetEngineClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for engine
+// sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetEngineClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_engineClipName = new char[strlen(clipName)+1];
+ strcpy( m_engineClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetEngineIdleClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for engine
+// idle sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetEngineIdleClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_idleClipName = new char[strlen(clipName)+1];
+ strcpy( m_idleClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetDamagedEngineClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for damaged
+// engine sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDamagedEngineClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_damagedClipName = new char[strlen(clipName)+1];
+ strcpy( m_damagedClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetHornClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for horn
+// sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetHornClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_hornClipName = new char[strlen(clipName)+1];
+ strcpy( m_hornClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetCarDoorOpenClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for car
+// door opening sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetCarDoorOpenClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_carOpenClipName = new char[strlen(clipName)+1];
+ strcpy( m_carOpenClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetCarDoorCloseClipName
+//=============================================================================
+// Description: Store the name of the sound resource we're using for car
+// door closing sounds
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetCarDoorCloseClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_carCloseClipName = new char[strlen(clipName)+1];
+ strcpy( m_carCloseClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetOverlayClipName
+//=============================================================================
+// Description: Store the name of the sound resource we want to play along
+// with the specified engine sound. Is optional.
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetOverlayClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_overlayClipName = new char[strlen(clipName)+1];
+ strcpy( m_overlayClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetRoadSkidClipName
+//=============================================================================
+// Description: Store the name of the sound resource we want to play when
+// the car skids on the road. Is optional.
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetRoadSkidClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_roadSkidClipName = new char[strlen(clipName)+1];
+ strcpy( m_roadSkidClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetDirtSkidClipName
+//=============================================================================
+// Description: Store the name of the sound resource we want to play when
+// the car skids. Is optional.
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDirtSkidClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_dirtSkidClipName = new char[strlen(clipName)+1];
+ strcpy( m_dirtSkidClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetBackupClipName
+//=============================================================================
+// Description: Store the name of the sound resource we want to play when
+// the car goes into reverse. Is optional.
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetBackupClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_PERSISTENT );
+
+ m_backupClipName = new char[strlen(clipName)+1];
+ strcpy( m_backupClipName, clipName );
+
+ HeapMgr()->PopHeap(GMA_PERSISTENT);
+}
+
+//=============================================================================
+// carSoundParameters::SetGearPitchRange
+//=============================================================================
+// Description: Set pitch range for engine clip for given gear
+//
+// Parameters: gear - gear to apply range to
+// min - pitch at lowest gear RPMs
+// max - pitch at highest gear RPMs
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetGearPitchRange( unsigned int gear, float min, float max )
+{
+ rAssert( gear > 0 );
+ rAssert( gear <= MAX_GEARS );
+ rAssert( max >= min );
+
+ m_minPitch[gear-1] = min;
+ m_maxPitch[gear-1] = max;
+}
+
+//=============================================================================
+// carSoundParameters::SetNumberOfGears
+//=============================================================================
+// Description: Like the name says
+//
+// Parameters: gear - number of gears we want, must be <= MAX_GEARS
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetNumberOfGears( unsigned int gear )
+{
+ rAssert( gear <= MAX_GEARS );
+
+ //
+ // If we set the shift point for the given gear to 1.0f, we're
+ // effectively cutting the number of gears
+ //
+ m_shiftPoints[gear] = 1.0f;
+}
+
+//=============================================================================
+// carSoundParameters::SetReversePitchCapKmh
+//=============================================================================
+// Description: Set maximum reverse speed at which we'll increase engine
+// pitch
+//
+// Parameters: speed - max reverse speed
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetReversePitchCapKmh( float speed )
+{
+ rAssert( speed > 0.0f );
+
+ m_maxReverseKmh = speed;
+}
+
+//=============================================================================
+// carSoundParameters::SetReversePitchRange
+//=============================================================================
+// Description: Set range of engine pitch for reverse gear
+//
+// Parameters: min - pitch at rest
+// max - pitch at m_maxReverseKmh
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetReversePitchRange( float min, float max )
+{
+ rAssert( min < max );
+
+ m_minReversePitch = min;
+ m_maxReversePitch = max;
+}
+
+//=============================================================================
+// carSoundParameters::SetGearShiftPitchDrop
+//=============================================================================
+// Description: Set amount of engine clip pitch drop we'll do on gear shifts
+//
+// Parameters: gear - gear that we want to set drop for
+// drop - amount of pitch drop
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetGearShiftPitchDrop( unsigned int gear, float drop )
+{
+ rAssert( gear > 0 );
+ rAssert( gear <= MAX_GEARS );
+ rAssert( drop >= 0.0f );
+
+ m_gearShiftPitchDrop[gear-1] = drop;
+}
+
+//=============================================================================
+// carSoundParameters::GetGearShiftPitchDrop
+//=============================================================================
+// Description: Get amount of engine clip pitch drop we'll do on gear shifts
+//
+// Parameters: gear - gear that we want drop for
+//
+// Return: value of pitch drop
+//
+//=============================================================================
+float carSoundParameters::GetGearShiftPitchDrop( unsigned int gear )
+{
+ rAssert( gear > 0 );
+ rAssert( gear <= MAX_GEARS );
+
+ return( m_gearShiftPitchDrop[gear-1] );
+}
+
+//=============================================================================
+// carSoundParameters::SetDamageStartPcnt
+//=============================================================================
+// Description: Set vehicle life percentage at which we'll start playing
+// damage sounds
+//
+// Parameters: damagePercent - vehicle life percentage for damage sound
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDamageStartPcnt( float damagePercent )
+{
+ rAssert( damagePercent >= 0.0f );
+ rAssert( damagePercent <= 1.0f );
+
+ // Also need to adjust damage volume range when start pcnt changes
+ m_damageVolumeRange += damagePercent - m_damageStartPcnt;
+
+ m_damageStartPcnt = damagePercent;
+}
+
+//=============================================================================
+// carSoundParameters::SetDamageMaxVolPcnt
+//=============================================================================
+// Description: Set vehicle life percentage at which the damage clip will
+// be played at maximum volume (linear interpolation between
+// m_damageStartPcnt and m_damageMaxVolPcnt).
+//
+// Parameters: percent - vehicle life percentage for maximum volume
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDamageMaxVolPcnt( float percent )
+{
+ rAssert( percent >= 0.0f );
+ rAssert( percent <= 1.0f );
+
+ //
+ // We don't actually store the percentage, since the trim setting code
+ // only cares about the min/max range; might as well precalculate it
+ m_damageVolumeRange = m_damageStartPcnt - percent;
+}
+
+//=============================================================================
+// carSoundParameters::SetDamageStartTrim
+//=============================================================================
+// Description: Set volume for damage clip when vehicle life percentage
+// reaches damage start percentage
+//
+// Parameters: trim - initial volume
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDamageStartTrim( float trim )
+{
+ rAssert( trim >= 0.0f );
+ rAssert( trim <= 1.0f );
+
+ m_damageStartTrim = trim;
+}
+
+//=============================================================================
+// carSoundParameters::SetDamageMaxTrim
+//=============================================================================
+// Description: Set volume for damage clip when vehicle life percentage
+// reaches damage max percentage
+//
+// Parameters: trim - initial volume
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetDamageMaxTrim( float trim )
+{
+ rAssert( trim >= 0.0f );
+ rAssert( trim <= 1.0f );
+
+ m_damageMaxTrim = trim;
+}
+
+//=============================================================================
+// carSoundParameters::SetIdleEnginePitch
+//=============================================================================
+// Description: Set pitch value for idle engine clip
+//
+// Parameters: pitch - obvious
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetIdleEnginePitch( float pitch )
+{
+ m_idleEnginePitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::SetInAirThrottlePitch
+//=============================================================================
+// Description: Set pitch that engine goes to when gas applied in air
+//
+// Parameters: pitch - engine pitch
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetInAirThrottlePitch( float pitch )
+{
+ m_inAirThrottlePitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::GetInAirThrottlePitch
+//=============================================================================
+// Description: Get pitch that engine goes to when gas applied in air
+//
+// Parameters: None
+//
+// Return: full-throttle pitch
+//
+//=============================================================================
+float carSoundParameters::GetInAirThrottlePitch()
+{
+ //
+ // POST-BETA HACK!!
+ //
+ if( m_inAirIdlePitch == s_inAirIdleDefault )
+ {
+ //
+ // Untuned, d'oh. Make something up.
+ //
+ m_inAirThrottlePitch = GetRevLimit();
+ }
+
+ return( m_inAirThrottlePitch );
+}
+
+//=============================================================================
+// carSoundParameters::SetInAirIdlePitch
+//=============================================================================
+// Description: Set pitch that engine goes to when engine idling in air
+//
+// Parameters: pitch - engine pitch
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetInAirIdlePitch( float pitch )
+{
+ m_inAirIdlePitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::GetInAirIdlePitch
+//=============================================================================
+// Description: Get pitch that engine goes to when engine idling in air
+//
+// Parameters: None
+//
+// Return: idle pitch
+//
+//=============================================================================
+float carSoundParameters::GetInAirIdlePitch()
+{
+ //
+ // POST-BETA HACK!!
+ //
+ if( m_inAirIdlePitch == s_inAirIdleDefault )
+ {
+ //
+ // Untuned, d'oh. Make something up as percentage of rev limit
+ //
+ m_inAirIdlePitch = 0.5f * GetRevLimit();
+ }
+
+ return( m_inAirIdlePitch );
+}
+
+//=============================================================================
+// carSoundParameters::SetInAirThrottleResponseTimeMsecs
+//=============================================================================
+// Description: Set amount of time to go from throttle pitch to idle pitch
+// in midair and vice versa
+//
+// Parameters: msecs - time in milliseconds
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetInAirThrottleResponseTimeMsecs( unsigned int msecs )
+{
+ m_inAirResponseMsecs = msecs;
+}
+
+//=============================================================================
+// carSoundParameters::SetBurnoutMinPitch
+//=============================================================================
+// Description: Set pitch for engine when burnout factor is at minimum
+// value
+//
+// Parameters: pitch - pitch to apply to sound clip
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetBurnoutMinPitch( float pitch )
+{
+ m_burnoutMinPitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::SetBurnoutMaxPitch
+//=============================================================================
+// Description: Set pitch for engine when burnout factor is at maximum
+// value
+//
+// Parameters: pitch - pitch to apply to sound clip
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetBurnoutMaxPitch( float pitch )
+{
+ m_burnoutMaxPitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::SetPowerslideMinPitch
+//=============================================================================
+// Description: Set pitch for engine when powerslide factor is at minimum
+// value
+//
+// Parameters: pitch - pitch to apply to sound clip
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetPowerslideMinPitch( float pitch )
+{
+ m_powerslideMinPitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::GetPowerslideMinPitch
+//=============================================================================
+// Description: Get pitch for engine when powerslide factor is at minimum
+// value
+//
+// Parameters: None
+//
+// Return: min pitch
+//
+//=============================================================================
+float carSoundParameters::GetPowerslideMinPitch()
+{
+ if( m_powerslideMinPitch == s_powerslideMinDefault )
+ {
+ m_powerslideMinPitch = 0.5f * GetRevLimit();
+ }
+
+ return( m_powerslideMinPitch );
+}
+
+//=============================================================================
+// carSoundParameters::SetPowerslideMaxPitch
+//=============================================================================
+// Description: Set pitch for engine when powerslide factor is at maximum
+// value
+//
+// Parameters: pitch - pitch to apply to sound clip
+//
+// Return: void
+//
+//=============================================================================
+void carSoundParameters::SetPowerslideMaxPitch( float pitch )
+{
+ m_powerslideMaxPitch = pitch;
+}
+
+//=============================================================================
+// carSoundParameters::GetPowerslideMaxPitch
+//=============================================================================
+// Description: Get pitch for engine when powerslide factor is at maximum
+// value
+//
+// Parameters: None
+//
+// Return: max pitch
+//
+//=============================================================================
+float carSoundParameters::GetPowerslideMaxPitch()
+{
+ if( m_powerslideMaxPitch == s_powerslideMaxDefault )
+ {
+ m_powerslideMaxPitch = 0.9f * GetRevLimit();
+ }
+
+ return( m_powerslideMaxPitch );
+}
+
+//=============================================================================
+// carSoundParameters::CalculateEnginePitch
+//=============================================================================
+// Description: Given some car data, figure out the pitch we should be playing
+// the clip at
+//
+// Parameters: gear - gear we're currently in
+// currentSpeed - how fast the car is travelling
+// topSpeed - top end for this car
+//
+// Return: pitch as a value from 0.0f to 1.0f
+//
+//=============================================================================
+float carSoundParameters::CalculateEnginePitch( int gear, float currentSpeed, float topSpeed )
+{
+ float enginePitch;
+ float percentageOfGear;
+ float bottomEndSpeed;
+
+ //rAssert( currentSpeed <= topSpeed );
+ rAssert( ( gear > 0 ) || ( gear == REVERSE_GEAR ) );
+ rAssert( gear <= static_cast<int>(MAX_GEARS) );
+
+ if( gear == REVERSE_GEAR )
+ {
+ percentageOfGear = currentSpeed / m_maxReverseKmh;
+ if( percentageOfGear > 1.0f )
+ {
+ percentageOfGear = 1.0f;
+ }
+
+ enginePitch = m_minReversePitch + ( percentageOfGear * ( m_maxReversePitch - m_minReversePitch ) );
+ }
+ else
+ {
+ bottomEndSpeed = m_shiftPoints[gear-1] * topSpeed;
+
+ //
+ // m_shiftPoints[gear+1] is allowed because we set m_shiftPoints[MAX_GEARS] to 1.0f
+ //
+ percentageOfGear = ( ( currentSpeed - bottomEndSpeed )
+ / ( ( m_shiftPoints[gear] * topSpeed ) - bottomEndSpeed ) );
+
+ //
+ // Based on our speed position within the range of speed used for this gear, apply that
+ // same percentage to the pitch range for our final pitch calculation
+ //
+ enginePitch = m_minPitch[gear-1] + ( ( m_maxPitch[gear-1] - m_minPitch[gear-1] ) * percentageOfGear );
+ }
+
+ return( enginePitch );
+}
+
+//=============================================================================
+// carSoundParameters::CalculateCurrentGear
+//=============================================================================
+// Description: Given our speed, figure out what gear we're in
+//
+// Parameters: currentSpeed - how fast the car is travelling
+// previousSpeed - how fast the car was going in the previous frame
+// (to see if we're upshifting or downshifting)
+// topSpeed - top end for this car
+// previousGear - which gear we were in before (used to cut down
+// on spurious gearshifts). If unknown, use -1.
+//
+// Return: 0 for idle, 1 to MAX_GEARS for forward gears
+//
+//=============================================================================
+int carSoundParameters::CalculateCurrentGear( float currentSpeed,
+ float previousSpeed,
+ float topSpeed,
+ int previousGear )
+{
+ unsigned int currentGear;
+ unsigned int uiPreviousGear;
+
+ //
+ // Find our current gear
+ //
+ for( currentGear = 0; currentGear < MAX_GEARS; currentGear++ )
+ {
+ if( currentSpeed <= ( topSpeed * m_shiftPoints[currentGear] ) )
+ {
+ break;
+ }
+ }
+
+ //
+ // Don't downshift if we're accelerating, and vice versa. If
+ // previousGear is -1, we'll accept the gearshift anyway
+ //
+ if( previousGear >= 0 )
+ {
+ uiPreviousGear = static_cast<unsigned int>(previousGear);
+
+ if( ( currentSpeed > previousSpeed )
+ && ( currentGear < uiPreviousGear ) )
+ {
+ currentGear = uiPreviousGear;
+ }
+ else if( ( currentSpeed <= previousSpeed )
+ && ( currentGear > uiPreviousGear ) )
+ {
+ currentGear = uiPreviousGear;
+ }
+ }
+
+ return( static_cast<int>(currentGear) );
+}
+
+//=============================================================================
+// carSoundParameters::GetRevLimit
+//=============================================================================
+// Description: Try to calculate a sensible maximum pitch
+//
+// Parameters: None
+//
+// Return: Rev limit as pitch value
+//
+//=============================================================================
+float carSoundParameters::GetRevLimit()
+{
+ unsigned int i;
+ float revLimit = 0.0f;
+
+ for( i = 0; i < MAX_GEARS; i++ )
+ {
+ //
+ // Ignore the default values of 2.0f, probably too high
+ //
+ if( ( m_maxPitch[i] > revLimit )
+ && ( m_maxPitch[i] < s_maxPitchDefault ) )
+ {
+ revLimit = m_maxPitch[i];
+ }
+ }
+
+ return( revLimit );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+
+//******************************************************************************
+// Factory functions
+//******************************************************************************
+
+//==============================================================================
+// CarSoundParameterObjCreate
+//==============================================================================
+// Description: Factory function for creating carSoundParameters objects.
+// Called by RadScript.
+//
+// Parameters: ppParametersObj - Address of ptr to new object
+// allocator - FTT pool to allocate object within
+//
+// Return: N/A.
+//
+//==============================================================================
+void CarSoundParameterObjCreate
+(
+ ICarSoundParameters** ppParametersObj,
+ radMemoryAllocator allocator
+)
+{
+ rAssert( ppParametersObj != NULL );
+ (*ppParametersObj) = new ( allocator ) carSoundParameters( );
+ (*ppParametersObj)->AddRef( );
+}
+
diff --git a/game/code/sound/avatar/carsoundparameters.h b/game/code/sound/avatar/carsoundparameters.h
new file mode 100644
index 0000000..d5c4ef1
--- /dev/null
+++ b/game/code/sound/avatar/carsoundparameters.h
@@ -0,0 +1,302 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: carsoundparameters.h
+//
+// Description: Declaration for RadScript-created class for tunable car sound
+// parameters
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef CARSOUNDPARAMETERS_H
+#define CARSOUNDPARAMETERS_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/avatar/icarsoundparameters.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: carSoundParameters
+//
+//=============================================================================
+
+class carSoundParameters: public ICarSoundParameters,
+ public radLinkedClass< carSoundParameters >,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "carSoundParameters" );
+
+ static const int REVERSE_GEAR = -1;
+
+ carSoundParameters();
+ virtual ~carSoundParameters();
+
+ void SetWatcherName( const char* name );
+
+ void SetClipRPM( float rpm ) { m_clipRPM = rpm; }
+ float GetClipRPM() { return( m_clipRPM ); }
+
+ void SetEngineClipName( const char* clipName );
+ const char* GetEngineClipName() { return( m_engineClipName ); }
+
+ void SetEngineIdleClipName( const char* clipName );
+ const char* GetEngineIdleClipName() { return( m_idleClipName ); }
+
+ void SetDamagedEngineClipName( const char* clipName );
+ const char* GetDamagedEngineClipName() { return( m_damagedClipName ); }
+
+ void SetHornClipName( const char* clipName );
+ const char* GetHornClipName() { return( m_hornClipName ); }
+
+ void SetCarDoorOpenClipName( const char* clipName );
+ const char* GetCarDoorOpenClipName() { return( m_carOpenClipName ); }
+
+ void SetCarDoorCloseClipName( const char* clipName );
+ const char* GetCarDoorCloseClipName() { return( m_carCloseClipName ); }
+
+ void SetOverlayClipName( const char* clipName );
+ const char* GetOverlayClipName() { return( m_overlayClipName ); }
+
+ void SetRoadSkidClipName( const char* clipName );
+ const char* GetRoadSkidClipName() { return( m_roadSkidClipName ); }
+
+ void SetDirtSkidClipName( const char* clipName );
+ const char* GetDirtSkidClipName() { return( m_dirtSkidClipName ); }
+
+ void SetBackupClipName( const char* clipName );
+ const char* GetBackupClipName() { return( m_backupClipName ); }
+
+ void SetShiftPoint( unsigned int gear, float percent );
+ float GetShiftPoint( int gear );
+
+ void SetDownshiftDamperSize( float percent );
+ float GetDownshiftDamperSize() { return( m_downshiftDamper ); }
+
+ void SetGearPitchRange( unsigned int gear, float min, float max );
+
+ void SetNumberOfGears( unsigned int gear );
+
+ float GetMsecsPerOctaveCap() { return( m_msecsPerOctave ); }
+
+ //
+ // Attack/delay/decay
+ //
+ void SetAttackTimeMsecs( float msecs );
+ float GetAttackTimeMsecs() { return( m_attackTime ); }
+
+ void SetDelayTimeMsecs( unsigned int msecs );
+ unsigned int GetDelayTimeMsecs() { return( m_delayTime ); }
+
+ void SetDecayTimeMsecs( float msecs );
+ float GetDecayTimeMsecs() { return( m_decayTime ); }
+
+ void SetDecayFinishTrim( float trim );
+ float GetDecayFinishTrim() { return( m_decayFinishTrim ); }
+
+ //
+ // Reverse
+ //
+ void SetReversePitchCapKmh( float speed );
+ float GetReversePitchCapKmh() { return( m_maxReverseKmh ); }
+
+ void SetReversePitchRange( float min, float max );
+ void GetReversePitchRange( float& min, float& max )
+ { min = m_minReversePitch; max = m_maxReversePitch; }
+
+ //
+ // Gear shifts
+ //
+ void SetGearShiftPitchDrop( unsigned int gear, float drop );
+ float GetGearShiftPitchDrop( unsigned int gear );
+
+ //
+ // Damage
+ //
+ void SetDamageStartPcnt( float damagePercent );
+ float GetDamageStartPcnt() { return( m_damageStartPcnt ); }
+
+ void SetDamageMaxVolPcnt( float percent );
+ float GetDamageVolumeRange() { return( m_damageVolumeRange ); }
+
+ void SetDamageStartTrim( float trim );
+ float GetDamageStartTrim() { return( m_damageStartTrim ); }
+ void SetDamageMaxTrim( float trim );
+ float GetDamageMaxTrim() { return( m_damageMaxTrim ); }
+
+ //
+ // Idle
+ //
+ void SetIdleEnginePitch( float pitch );
+ float GetIdleEnginePitch() { return( m_idleEnginePitch ); }
+
+ //
+ // In-air sound characteristics
+ //
+ void SetInAirThrottlePitch( float pitch );
+ float GetInAirThrottlePitch();
+
+ void SetInAirIdlePitch( float pitch );
+ float GetInAirIdlePitch();
+
+ void SetInAirThrottleResponseTimeMsecs( unsigned int msecs );
+ unsigned int GetInAirThrottleResponseTimeMsecs() { return( m_inAirResponseMsecs ); }
+
+ //
+ // Burnout sound characteristics
+ //
+ void SetBurnoutMinPitch( float pitch );
+ float GetBurnoutMinPitch() { return( m_burnoutMinPitch ); }
+
+ void SetBurnoutMaxPitch( float pitch );
+ float GetBurnoutMaxPitch() { return( m_burnoutMaxPitch ); }
+
+ //
+ // Powerslide sound characteristics
+ //
+ void SetPowerslideMinPitch( float pitch );
+ float GetPowerslideMinPitch();
+
+ void SetPowerslideMaxPitch( float pitch );
+ float GetPowerslideMaxPitch();
+
+ //
+ // Given a vehicle's current speed and max speed, figure out the
+ // gear it's in
+ //
+ int CalculateCurrentGear( float currentSpeed, float previousSpeed,
+ float topSpeed, int previousGear );
+
+ //
+ // Given a vehicle's current gear, speed, and max speed, figure out the
+ // pitch for the engine clip
+ //
+ float CalculateEnginePitch( int gear, float currentSpeed, float topSpeed );
+
+ float GetRevLimit();
+
+ private:
+ //Prevent wasteful constructor creation.
+ carSoundParameters( const carSoundParameters& original );
+ carSoundParameters& operator=( const carSoundParameters& rhs );
+
+ static const unsigned int MAX_GEARS = 6;
+
+ float m_clipRPM;
+
+ float m_minPitch[MAX_GEARS];
+ float m_maxPitch[MAX_GEARS];
+
+ char* m_engineClipName;
+ char* m_idleClipName;
+ char* m_damagedClipName;
+ char* m_hornClipName;
+ char* m_carOpenClipName;
+ char* m_carCloseClipName;
+ char* m_overlayClipName;
+ char* m_roadSkidClipName;
+ char* m_dirtSkidClipName;
+ char* m_backupClipName;
+
+ //
+ // Percentages of top speed at which we shift gears.
+ // E.g. m_shiftPoints[0] == 0.01f means that we shift from idle
+ // to first at 1% of top speed. m_shiftPoints[MAX_GEARS+1] is
+ // 1.0f to simplify math.
+ //
+
+ // Used for shifting
+ float m_shiftPoints[MAX_GEARS+1];
+ float m_downshiftDamper;
+
+ //
+ // Attack/delay/decay
+ //
+ float m_attackTime;
+ unsigned int m_delayTime;
+ float m_decayTime;
+
+ float m_decayFinishTrim;
+
+ //
+ // Reverse
+ //
+ float m_maxReverseKmh;
+ float m_minReversePitch;
+ float m_maxReversePitch;
+
+ //
+ // Gear shifts
+ //
+ float m_gearShiftPitchDrop[MAX_GEARS];
+ unsigned int m_gearShiftTimeMsecs[MAX_GEARS];
+
+ //
+ // Damage
+ //
+ float m_damageStartPcnt;
+ float m_damageVolumeRange;
+
+ float m_damageStartTrim;
+ float m_damageMaxTrim;
+
+ //
+ // Idle
+ //
+ float m_idleEnginePitch;
+
+ //
+ // Airborne
+ //
+ float m_inAirThrottlePitch;
+ float m_inAirIdlePitch;
+ unsigned int m_inAirResponseMsecs;
+
+ //
+ // Burnout
+ //
+ float m_burnoutMinPitch;
+ float m_burnoutMaxPitch;
+
+ //
+ // Powerslide
+ //
+ float m_powerslideMinPitch;
+ float m_powerslideMaxPitch;
+
+ //
+ // Makes transitions a little less abrupt
+ //
+ float m_msecsPerOctave;
+};
+
+//=============================================================================
+// Factory Functions
+//=============================================================================
+
+//
+// Create a CarSoundParameters object
+//
+void CarSoundParameterObjCreate
+(
+ ICarSoundParameters** ppSoundResource,
+ radMemoryAllocator allocator
+);
+
+
+
+
+#endif // CARSOUNDPARAMETERS_H
+
diff --git a/game/code/sound/avatar/icarsoundparameters.h b/game/code/sound/avatar/icarsoundparameters.h
new file mode 100644
index 0000000..6fb8f9a
--- /dev/null
+++ b/game/code/sound/avatar/icarsoundparameters.h
@@ -0,0 +1,168 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: icarsoundparameters.h
+//
+// Description: Interface declaration for RadScript-created class for
+// tunable car sound parameters
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef ICARSOUNDPARAMETERS_H
+#define ICARSOUNDPARAMETERS_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <radobject.hpp>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: ICarSoundParameters
+//
+//=============================================================================
+
+struct ICarSoundParameters : public IRefCount
+{
+ //
+ // Vehicle RPM at which the engine sound clip should be played unchanged
+ //
+ virtual void SetClipRPM( float rpm ) = 0;
+
+ //
+ // Name of clip to use for engine sound
+ //
+ virtual void SetEngineClipName( const char* clipName ) = 0;
+
+ //
+ // Name of clip to use for engine idle sound
+ //
+ virtual void SetEngineIdleClipName( const char* clipName ) = 0;
+
+ //
+ // Name of clip to use for damaged engine sound
+ //
+ virtual void SetDamagedEngineClipName( const char* clipName ) = 0;
+
+ //
+ // Horn sound
+ //
+ virtual void SetHornClipName( const char* clipName ) = 0;
+
+ //
+ // Skid sounds
+ //
+ virtual void SetRoadSkidClipName( const char* clipName ) = 0;
+ virtual void SetDirtSkidClipName( const char* clipName ) = 0;
+
+ //
+ // Backup sound
+ //
+ virtual void SetBackupClipName( const char* clipName ) = 0;
+
+ //
+ // Car door entry/exit sounds
+ //
+ virtual void SetCarDoorOpenClipName( const char* clipName ) = 0;
+ virtual void SetCarDoorCloseClipName( const char* clipName ) = 0;
+
+ //
+ // Percentages of top speed for shift points
+ //
+ virtual void SetShiftPoint( unsigned int gear, float percent ) = 0;
+
+ //
+ // Percentage of top speed that we'll use as a range for dropping
+ // below the shift point to avoid downshifting
+ //
+ virtual void SetDownshiftDamperSize( float percent ) = 0;
+
+ //
+ // Pitch range for a particular gear
+ //
+ virtual void SetGearPitchRange( unsigned int gear, float min, float max ) = 0;
+
+ //
+ // Number of gears
+ //
+ virtual void SetNumberOfGears( unsigned int gear ) = 0;
+
+ //
+ // Attack/delay/decay
+ //
+ virtual void SetAttackTimeMsecs( float msecs ) = 0;
+ virtual void SetDelayTimeMsecs( unsigned int msecs ) = 0;
+ virtual void SetDecayTimeMsecs( float msecs ) = 0;
+
+ virtual void SetDecayFinishTrim( float trim ) = 0;
+
+ //
+ // Top speed for which we'll increase pitch in reverse
+ //
+ virtual void SetReversePitchCapKmh( float speed ) = 0;
+
+ //
+ // Reverse gear pitch range
+ //
+ virtual void SetReversePitchRange( float min, float max ) = 0;
+
+ //
+ // Amount of pitch drop and time to apply in gear shifts
+ //
+ virtual void SetGearShiftPitchDrop( unsigned int gear, float drop ) = 0;
+
+ //
+ // Percentage damage when we play damage sound
+ //
+ virtual void SetDamageStartPcnt( float damagePercent ) = 0;
+ virtual void SetDamageMaxVolPcnt( float percent ) = 0;
+
+ //
+ // Volume control on damage sounds
+ //
+ virtual void SetDamageStartTrim( float trim ) = 0;
+ virtual void SetDamageMaxTrim( float trim ) = 0;
+
+ //
+ // Pitch for idle engine clip (separate from sound resource in case
+ // we want to share resource between cars. Strictly a convenience,
+ // since multiple sound resources with the same sound file could be
+ // created instead).
+ //
+ virtual void SetIdleEnginePitch( float pitch ) = 0;
+
+ //
+ // In-air sound characteristics
+ //
+ virtual void SetInAirThrottlePitch( float pitch ) = 0;
+ virtual void SetInAirIdlePitch( float pitch ) = 0;
+ virtual void SetInAirThrottleResponseTimeMsecs( unsigned int msecs ) = 0;
+
+ //
+ // Burnout sound characteristics
+ //
+ virtual void SetBurnoutMinPitch( float pitch ) = 0;
+ virtual void SetBurnoutMaxPitch( float pitch ) = 0;
+
+ //
+ // Powerslide sound characteristics
+ //
+ virtual void SetPowerslideMinPitch( float pitch ) = 0;
+ virtual void SetPowerslideMaxPitch( float pitch ) = 0;
+
+ //
+ // Playing an overlay clip
+ //
+ virtual void SetOverlayClipName( const char* clipName ) = 0;
+};
+
+
+#endif // ICARSOUNDPARAMETERS_H
+
diff --git a/game/code/sound/avatar/soundavatar.cpp b/game/code/sound/avatar/soundavatar.cpp
new file mode 100644
index 0000000..b1e827f
--- /dev/null
+++ b/game/code/sound/avatar/soundavatar.cpp
@@ -0,0 +1,245 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundavatar.cpp
+//
+// Description: Implements SoundAvatar, which maintains a reference
+// to an avatar for which sounds are to be created, and directs
+// the playing of sound as either vehicle- or character-based,
+// whichever is appropriate at the time.
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/avatar/soundavatar.h>
+
+#include <sound/avatar/vehiclesoundplayer.h>
+#include <worldsim/avatar.h>
+#include <worldsim/character/character.h>
+#include <events/eventmanager.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundAvatar::SoundAvatar
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundAvatar::SoundAvatar( Avatar* avatarObj ) :
+ m_avatar( avatarObj ),
+ m_isInCar( false ),
+ m_turboTimer( 0 )
+{
+ rAssert( avatarObj != NULL );
+
+ //
+ // Register as an event listener
+ //
+ GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_MISSION_RESET );
+ GetEventManager()->AddListener( this, EVENT_VEHICLE_DESTROYED_SYNC_SOUND );
+ GetEventManager()->AddListener( this, EVENT_CHARACTER_POS_RESET );
+ GetEventManager()->AddListener( this, EVENT_CHASE_VEHICLE_SPAWNED );
+ GetEventManager()->AddListener( this, EVENT_CHASE_VEHICLE_DESTROYED );
+ GetEventManager()->AddListener( this, EVENT_TURBO_START );
+
+ syncCarSoundState();
+}
+
+//==============================================================================
+// SoundAvatar::~SoundAvatar
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundAvatar::~SoundAvatar()
+{
+ if( m_isInCar )
+ {
+ m_vehicleSoundPlayer.StopCarSounds();
+ }
+
+ //
+ // Deregister from EventManager
+ //
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// SoundAvatar::HandleEvent
+//=============================================================================
+// Description: Listen for events that tell us if we're swapping between
+// walking and driving
+//
+// Parameters: id - indicates which event has occurred
+// pEventData - ptr to Character class, must match to our avatar
+//
+// Return: void
+//
+//=============================================================================
+void SoundAvatar::HandleEvent( EventEnum id, void* pEventData )
+{
+ switch( id )
+ {
+ case EVENT_GETINTOVEHICLE_END:
+ if( static_cast<Character*>(pEventData) == m_avatar->GetCharacter() )
+ {
+ m_isInCar = true;
+
+ rAssert( m_avatar->GetVehicle() );
+ m_vehicleSoundPlayer.StartCarSounds( m_avatar->GetVehicle() );
+ }
+ break;
+
+ case EVENT_GETOUTOFVEHICLE_END:
+ if( static_cast<Character*>(pEventData) == m_avatar->GetCharacter() )
+ {
+ m_isInCar = false;
+
+ m_vehicleSoundPlayer.StopCarSounds();
+ }
+ break;
+
+ case EVENT_MISSION_RESET:
+ case EVENT_CHARACTER_POS_RESET:
+ case EVENT_VEHICLE_DESTROYED_SYNC_SOUND:
+ syncCarSoundState();
+ break;
+
+ case EVENT_CHASE_VEHICLE_SPAWNED:
+ m_vehicleSoundPlayer.AddAIVehicleProximityTest( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_CHASE_VEHICLE_DESTROYED:
+ m_vehicleSoundPlayer.DeleteAIVehicleProximityTest( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_TURBO_START:
+ //
+ // If event applies to this character, start a timer. When it expires,
+ // say something funny
+ //
+ if( ( m_turboTimer == 0 ) &&
+ ( static_cast<Character*>(pEventData) == m_avatar->GetCharacter() ) )
+ {
+ m_turboTimer = 5000;
+ }
+
+ default:
+ break;
+ }
+}
+
+//=============================================================================
+// SoundAvatar::UpdateOncePerFrame
+//=============================================================================
+// Description: Update function. Used for stuff that either doesn't need to
+// be called often and/or uses expensive math.
+//
+// Parameters: elapsedTime - time since last frame in msecs
+//
+// Return: void
+//
+//=============================================================================
+void SoundAvatar::UpdateOncePerFrame( unsigned int elapsedTime )
+{
+ if( m_isInCar )
+ {
+ m_vehicleSoundPlayer.UpdateOncePerFrame( elapsedTime );
+ }
+
+ if( m_turboTimer > 0 )
+ {
+ if( !(m_avatar->GetCharacter()->IsTurbo()) )
+ {
+ //
+ // Player no longer sprinting, stop the countdown
+ //
+ m_turboTimer = 0;
+ }
+ else if( elapsedTime >= m_turboTimer )
+ {
+ //
+ // Timer expired. Time to make with the funny.
+ //
+ GetEventManager()->TriggerEvent( EVENT_CHARACTER_TIRED_NOW );
+
+ //
+ // Set up for another line, but if it's a repeat, let's make
+ // it take a little longer
+ //m_turboTimer = 10000;
+
+ //
+ // Okay, the repeating line is unpopular. Just play it once
+ // and be done.
+ //
+ m_turboTimer = 0;
+ }
+ else
+ {
+ m_turboTimer -= elapsedTime;
+ }
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SoundAvatar::syncCarSoundState
+//=============================================================================
+// Description: Determine whether the avatar is in the car, and start or
+// stop engine sounds accordingly.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundAvatar::syncCarSoundState()
+{
+ m_isInCar = m_avatar->IsInCar();
+
+ if( m_isInCar )
+ {
+ rAssert( m_avatar->GetVehicle() );
+
+ m_vehicleSoundPlayer.StartCarSounds( m_avatar->GetVehicle() );
+ }
+ else
+ {
+ m_vehicleSoundPlayer.StopCarSounds();
+ }
+} \ No newline at end of file
diff --git a/game/code/sound/avatar/soundavatar.h b/game/code/sound/avatar/soundavatar.h
new file mode 100644
index 0000000..3ea676a
--- /dev/null
+++ b/game/code/sound/avatar/soundavatar.h
@@ -0,0 +1,78 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundavatar.h
+//
+// Description: Declaration of SoundAvatar class, which maintains a reference
+// to an avatar for which sounds are to be created, and directs
+// the playing of sound as either vehicle- or character-based,
+// whichever is appropriate at the time.
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDAVATAR_H
+#define SOUNDAVATAR_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <sound/avatar/vehiclesoundplayer.h>
+
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+class Avatar;
+
+//=============================================================================
+//
+// Synopsis: SoundAvatar
+//
+//=============================================================================
+
+class SoundAvatar : public EventListener
+{
+ public:
+ SoundAvatar( Avatar* avatarObj );
+ virtual ~SoundAvatar();
+
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ void UpdateOncePerFrame( unsigned int elapsedTime );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundAvatar();
+ SoundAvatar( const SoundAvatar& original );
+ SoundAvatar& operator=( const SoundAvatar& rhs );
+
+ void syncCarSoundState();
+
+ //
+ // Avatar object that we're going to keep an eye on
+ //
+ Avatar* m_avatar;
+
+ //
+ // Is the player in the car?
+ //
+ bool m_isInCar;
+
+ //
+ // Object for playing vehicle sounds
+ VehicleSoundPlayer m_vehicleSoundPlayer;
+
+ //
+ // Timer for character sprinting
+ //
+ unsigned int m_turboTimer;
+};
+
+
+#endif // SOUNDAVATAR_H
+
diff --git a/game/code/sound/avatar/vehiclesounddebugpage.cpp b/game/code/sound/avatar/vehiclesounddebugpage.cpp
new file mode 100644
index 0000000..20102b3
--- /dev/null
+++ b/game/code/sound/avatar/vehiclesounddebugpage.cpp
@@ -0,0 +1,138 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclesounddebugpage.cpp
+//
+// Description: Definition for VehicleSoundDebugPage class, which displays
+// vehicle sound info through Watcher
+//
+// History: 11/22/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/avatar/vehiclesounddebugpage.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// VehicleSoundDebugPage::VehicleSoundDebugPage
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+VehicleSoundDebugPage::VehicleSoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master ) :
+ SoundDebugPage( pageNum, master ),
+ m_shiftInProgress( false ),
+ m_currentGear( 0 ),
+ m_currentSpeed( 0.0f ),
+ m_shiftTime( 0 ),
+ m_downshiftSpeed( 0.0f ),
+ m_upshiftSpeed( 0.0f ),
+ m_currentPitch( 0.0f ),
+ m_isDamaged( false )
+{
+}
+
+//==============================================================================
+// VehicleSoundDebugPage::~VehicleSoundDebugPage
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+VehicleSoundDebugPage::~VehicleSoundDebugPage()
+{
+}
+
+//******************************************************************************
+//
+// Protected Member Functions
+//
+//******************************************************************************
+
+void VehicleSoundDebugPage::fillLineBuffer( int lineNum, char* buffer )
+{
+ switch( lineNum )
+ {
+ case 0:
+ sprintf( buffer, "Gear: %d Speed: %f", m_currentGear, m_currentSpeed );
+ break;
+
+ case 2:
+ sprintf( buffer, "Shift speeds: %f %f", m_downshiftSpeed, m_upshiftSpeed );
+ break;
+
+ case 4:
+ if( m_shiftInProgress )
+ {
+ sprintf( buffer, "SHIFTING - Time in msecs: %d", m_shiftTime );
+ }
+ else
+ {
+ buffer[0] = '\0';
+ }
+ break;
+
+ case 6:
+ sprintf( buffer, "Pitch: %f", m_currentPitch );
+ break;
+
+ case 8:
+ if( m_isDamaged )
+ {
+ sprintf( buffer, "Life: %f Threshold: %f CAR DAMAGE SOUND",
+ m_vehicleLife, m_damageThreshold );
+ }
+ else
+ {
+ sprintf( buffer, "Life: %f Threshold: %f",
+ m_vehicleLife, m_damageThreshold );
+ }
+ break;
+
+ default:
+ buffer[0] = '\0';
+ break;
+ }
+}
+
+//=============================================================================
+// VehicleSoundDebugPage::getNumLines
+//=============================================================================
+// Description: Returns number of lines that we'll display on screen
+//
+// Parameters: None
+//
+// Return: Line count
+//
+//=============================================================================
+int VehicleSoundDebugPage::getNumLines()
+{
+ return( 9 );
+}
diff --git a/game/code/sound/avatar/vehiclesounddebugpage.h b/game/code/sound/avatar/vehiclesounddebugpage.h
new file mode 100644
index 0000000..3259558
--- /dev/null
+++ b/game/code/sound/avatar/vehiclesounddebugpage.h
@@ -0,0 +1,75 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclesounddebugpage.h
+//
+// Description: Declaration for VehicleSoundDebugPage class, which displays
+// vehicle sound info through Watcher
+//
+// History: 11/22/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef VEHICLESOUNDDEBUGPAGE_H
+#define VEHICLESOUNDDEBUGPAGE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/sounddebug/sounddebugpage.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: VehicleSoundDebugPage
+//
+//=============================================================================
+
+class VehicleSoundDebugPage : public SoundDebugPage
+{
+ public:
+ VehicleSoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master );
+ virtual ~VehicleSoundDebugPage();
+
+ void SetShiftInProgress( bool inProgress ) { m_shiftInProgress = inProgress; }
+ void SetCurrentGear( int gear ) { m_currentGear = gear; }
+ void SetCurrentSpeed( float speed ) { m_currentSpeed = speed; }
+ void SetShiftTime( unsigned int time ) { m_shiftTime = time; }
+ void SetDownshiftSpeed( float speed ) { m_downshiftSpeed = speed; }
+ void SetUpshiftSpeed( float speed ) { m_upshiftSpeed = speed; }
+ void SetCurrentPitch( float pitch ) { m_currentPitch = pitch; }
+ void SetDamageEnabled( bool isDamaged ) { m_isDamaged = isDamaged; }
+ void SetVehicleLife( float life ) { m_vehicleLife = life; }
+ void SetDamageThreshold( float threshold ) { m_damageThreshold = threshold; }
+
+ protected:
+ //
+ // Pure virtual functions from SoundDebugPage
+ //
+ void fillLineBuffer( int lineNum, char* buffer );
+ int getNumLines();
+
+ private:
+ //Prevent wasteful constructor creation.
+ VehicleSoundDebugPage();
+ VehicleSoundDebugPage( const VehicleSoundDebugPage& original );
+ VehicleSoundDebugPage& operator=( const VehicleSoundDebugPage& rhs );
+
+ bool m_shiftInProgress;
+ int m_currentGear;
+ float m_currentSpeed;
+ unsigned int m_shiftTime;
+ float m_downshiftSpeed;
+ float m_upshiftSpeed;
+ float m_currentPitch;
+ bool m_isDamaged;
+ float m_vehicleLife;
+ float m_damageThreshold;
+};
+
+
+#endif // VEHICLESOUNDDEBUGPAGE_H
+
diff --git a/game/code/sound/avatar/vehiclesoundplayer.cpp b/game/code/sound/avatar/vehiclesoundplayer.cpp
new file mode 100644
index 0000000..257d342
--- /dev/null
+++ b/game/code/sound/avatar/vehiclesoundplayer.cpp
@@ -0,0 +1,2499 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclesoundplayer.cpp
+//
+// Description: Implement VehicleSoundPlayer
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <float.h>
+
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/avatar/vehiclesoundplayer.h>
+
+#include <sound/avatar/carsoundparameters.h>
+#include <sound/tuning/globalsettings.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundmanager.h>
+
+#include <worldsim/redbrick/vehicle.h>
+#include <worldsim/vehiclecentral.h>
+#include <worldsim/redbrick/vehiclecontroller/vehiclecontroller.h>
+
+#include <input/button.h>
+#include <events/eventmanager.h>
+#include <mission/gameplaymanager.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// For tuning
+//
+static bool s_resetEngineOnHonk = false;
+static bool s_resetEngineInitialized = false;
+
+static const char* s_skidResource = "skid";
+static const char* s_gearResource = "gearshift";
+
+static const float GAME_POWERSLIDE_TRIM_MIN = 0.6f;
+static const float GAME_POWERSLIDE_TRIM_MAX = 0.9f;
+
+static const float SUPERSPRINT_POWERSLIDE_TRIM_MIN = 0.4f;
+static const float SUPERSPRINT_POWERSLIDE_TRIM_MAX = 0.7f;
+
+//
+// MACROS FOR DEBUG INFO
+//
+#ifdef SOUND_DEBUG_INFO_ENABLED
+
+#define SET_SHIFT_IN_PROGRESS(inProgress) m_debugInfo->SetShiftInProgress(inProgress)
+#define SET_CURRENT_GEAR(gear) m_debugInfo->SetCurrentGear(gear)
+#define SET_CURRENT_SPEED(speed) m_debugInfo->SetCurrentSpeed(speed)
+#define SET_SHIFT_TIME_REMAINING(time) m_debugInfo->SetShiftTime(time)
+#define SET_DOWNSHIFT_SPEED(speed) m_debugInfo->SetDownshiftSpeed(speed)
+#define SET_UPSHIFT_SPEED(speed) m_debugInfo->SetUpshiftSpeed(speed)
+#define SET_CURRENT_PITCH(pitch) m_debugInfo->SetCurrentPitch(pitch)
+#define SET_IS_DAMAGED(isDamaged) m_debugInfo->SetDamageEnabled(isDamaged)
+#define SET_VEHICLE_LIFE(life) m_debugInfo->SetVehicleLife(life)
+#define SET_DAMAGE_THRESHOLD(threshold) m_debugInfo->SetDamageThreshold(threshold)
+
+//
+// This is annoying. Stinky bad design.
+//
+#define SET_LOCAL_SHIFT_IN_PROGRESS(inProgress) m_debugInfo.SetShiftInProgress(inProgress)
+#define SET_LOCAL_CURRENT_GEAR(gear) m_debugInfo.SetCurrentGear(gear)
+#define SET_LOCAL_CURRENT_SPEED(speed) m_debugInfo.SetCurrentSpeed(speed)
+#define SET_LOCAL_SHIFT_TIME_REMAINING(time) m_debugInfo.SetShiftTime(time)
+#define SET_LOCAL_DOWNSHIFT_SPEED(speed) m_debugInfo.SetDownshiftSpeed(speed)
+#define SET_LOCAL_UPSHIFT_SPEED(speed) m_debugInfo.SetUpshiftSpeed(speed)
+#define SET_LOCAL_CURRENT_PITCH(pitch) m_debugInfo.SetCurrentPitch(pitch)
+#define SET_LOCAL_IS_DAMAGED(isDamaged) m_debugInfo.SetDamageEnabled(isDamaged)
+#define SET_LOCAL_VEHICLE_LIFE(life) m_debugInfo.SetVehicleLife(life)
+#define SET_LOCAL_DAMAGE_THRESHOLD(threshold) m_debugInfo.SetDamageThreshold(threshold)
+
+#else
+
+#define SET_SHIFT_IN_PROGRESS(inProgress)
+#define SET_CURRENT_GEAR(gear)
+#define SET_CURRENT_SPEED(speed)
+#define SET_SHIFT_TIME_REMAINING(time)
+#define SET_DOWNSHIFT_SPEED(speed)
+#define SET_UPSHIFT_SPEED(speed)
+#define SET_CURRENT_PITCH(pitch)
+#define SET_IS_DAMAGED(isDamaged)
+#define SET_VEHICLE_LIFE(life)
+#define SET_DAMAGE_THRESHOLD(threshold)
+
+#define SET_LOCAL_SHIFT_IN_PROGRESS(inProgress)
+#define SET_LOCAL_CURRENT_GEAR(gear)
+#define SET_LOCAL_CURRENT_SPEED(speed)
+#define SET_LOCAL_SHIFT_TIME_REMAINING(time)
+#define SET_LOCAL_DOWNSHIFT_SPEED(speed)
+#define SET_LOCAL_UPSHIFT_SPEED(speed)
+#define SET_LOCAL_CURRENT_PITCH(pitch)
+#define SET_LOCAL_IS_DAMAGED(isDamaged)
+#define SET_LOCAL_VEHICLE_LIFE(life)
+#define SET_LOCAL_DAMAGE_THRESHOLD(threshold)
+
+#endif
+
+enum GearShiftResult
+{
+ GEARSHIFT_NONE,
+ GEARSHIFT_DAMPED,
+ GEARSHIFT_UP,
+ GEARSHIFT_DOWN
+};
+
+
+//
+// Classes for engine states. Each one represents a state
+// in which the engine will have different sound-speed characteristics
+// (e.g. car in air, gearshift in progress).
+//
+
+//
+// Base class for engine states
+//
+class EngineState
+{
+ public:
+ EngineState();
+ virtual ~EngineState();
+
+ void Initialize( Vehicle* vehicle, carSoundParameters* parameters,
+ SimpsonsSoundPlayer* player, radKey32 resourceKey,
+ VehicleSoundDebugPage* debugPtr );
+ bool StartNewState() { return( m_nextState != ENGINE_STATE_INVALID ); }
+ EngineStateEnum GetNewState() { return( m_nextState ); }
+ void Reset() { m_nextState = ENGINE_STATE_INVALID; }
+
+ virtual void SetDebugInfo();
+
+ virtual void Service( unsigned int elapsedTime ) = 0;
+
+ virtual float GetCurrentPitch();
+
+ bool IsActive() { return( m_isActive ); }
+ void SetActive( bool isActive, float prevPitch = 0.0f );
+
+ void StartFade( float initialTrim, bool stopAfterFade = true );
+ bool IsFading();
+ void ServiceFade( unsigned int elapsedTime );
+
+ void SetTrim( float trim );
+
+ protected:
+
+ virtual void startup( float prevPitch ) = 0;
+ bool isAtIdleSpeed();
+ bool isSkidding();
+
+ //
+ // True if this state is running and producing sound
+ //
+ bool m_isActive;
+
+ //
+ // When we want to kick off a new state, set this to something
+ // other than ENGINE_STATE_INVALID
+ //
+ EngineStateEnum m_nextState;
+
+ //
+ // Stuff for getting vehicle and sound parameter info
+ //
+ Vehicle* m_vehicle;
+ carSoundParameters* m_parameters;
+
+ //
+ // Sound player stuff
+ //
+ SimpsonsSoundPlayer* m_player;
+ radKey32 m_resourceKey;
+
+ //
+ // Rev limiter, calculated from pitch ranges
+ //
+ float m_revLimit;
+
+ //
+ // Debug stuff
+ //
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ VehicleSoundDebugPage* m_debugInfo;
+#endif
+
+ private:
+ //Prevent wasteful constructor creation.
+ EngineState( const EngineState& original );
+ EngineState& operator=( const EngineState& rhs );
+
+ float m_fadeTrim;
+ bool m_stopAfterFade;
+};
+
+//
+// State for normal, on-ground, no-shift engine sound
+//
+class NormalEngineState : public EngineState
+{
+ public:
+ NormalEngineState();
+ virtual ~NormalEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ float GetCurrentPitch();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ NormalEngineState( const NormalEngineState& original );
+ NormalEngineState& operator=( const NormalEngineState& rhs );
+
+ GearShiftResult updateCurrentGearFromVehicle( bool dampenShifts = false );
+
+ int m_currentGear;
+ float m_currentSpeed;
+ float m_currentPitch;
+ bool m_isAttacking;
+ float m_currentTrim;
+ unsigned int m_interpolateTime;
+};
+
+//
+// State for upshifts (e.g. 2nd to 3rd gear)
+//
+class UpshiftEngineState : public EngineState
+{
+ public:
+ UpshiftEngineState();
+ virtual ~UpshiftEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ UpshiftEngineState( const UpshiftEngineState& original );
+ UpshiftEngineState& operator=( const UpshiftEngineState& rhs );
+
+ float m_startPitch;
+ float m_pitchDrop;
+ float m_shiftTimeMsecs;
+ unsigned int m_remainingTime;
+};
+
+//
+// State for downshifts (e.g. 3rd to 2nd gear)
+//
+class DownshiftEngineState : public EngineState
+{
+ public:
+ DownshiftEngineState();
+ virtual ~DownshiftEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ float GetCurrentPitch();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ DownshiftEngineState( const DownshiftEngineState& original );
+ DownshiftEngineState& operator=( const DownshiftEngineState& rhs );
+
+ float m_startSpeed;
+ float m_startPitch;
+ float m_lastSpeed;
+ float m_currentPitch;
+};
+
+//
+// State for car in mid-air
+//
+class InAirEngineState : public EngineState
+{
+ public:
+ InAirEngineState();
+ virtual ~InAirEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ InAirEngineState( const InAirEngineState& original );
+ InAirEngineState& operator=( const InAirEngineState& rhs );
+
+ float m_currentPitch;
+};
+
+//
+// State for car in reverse
+//
+class ReverseEngineState : public EngineState
+{
+ public:
+ ReverseEngineState( SimpsonsSoundPlayer* beepPlayer );
+ virtual ~ReverseEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ ReverseEngineState( const ReverseEngineState& original );
+ ReverseEngineState& operator=( const ReverseEngineState& rhs );
+
+ SimpsonsSoundPlayer* m_beepPlayer;
+};
+
+//
+// State for car in idle
+//
+class IdleEngineState : public EngineState
+{
+ public:
+ IdleEngineState();
+ virtual ~IdleEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ float GetCurrentPitch();
+
+ protected:
+ void startup( float prevPitch );
+ private:
+ //Prevent wasteful constructor creation.
+ IdleEngineState( const IdleEngineState& original );
+ IdleEngineState& operator=( const IdleEngineState& rhs );
+
+ float m_currentPitch;
+};
+
+//
+// State for car when skidding
+//
+class SkidEngineState : public EngineState
+{
+ public:
+ SkidEngineState();
+ virtual ~SkidEngineState();
+
+ void Service( unsigned int elapsedTime );
+
+ void SetDebugInfo();
+
+ float GetCurrentPitch();
+
+ protected:
+ void startup( float prevPitch );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SkidEngineState( const SkidEngineState& original );
+ SkidEngineState& operator=( const SkidEngineState& rhs );
+
+ float m_currentPitch;
+};
+
+//******************************************************************************
+//
+// EngineState
+//
+//******************************************************************************
+
+EngineState::EngineState() :
+ m_isActive( false ),
+ m_nextState( ENGINE_STATE_INVALID ),
+ m_vehicle( NULL ),
+ m_parameters( NULL ),
+ m_player( NULL ),
+ m_resourceKey( 0 ),
+ m_fadeTrim( 0.0f ),
+ m_stopAfterFade( true )
+{
+}
+
+EngineState::~EngineState()
+{
+}
+
+void EngineState::Initialize( Vehicle* vehicle, carSoundParameters* parameters,
+ SimpsonsSoundPlayer* player, radKey32 resourceKey,
+ VehicleSoundDebugPage* debugPtr )
+{
+ rAssert( vehicle != NULL );
+ rAssert( parameters != NULL );
+ rAssert( player != NULL );
+
+ m_vehicle = vehicle;
+ m_parameters = parameters;
+ m_player = player;
+ m_resourceKey = resourceKey;
+
+ //
+ // Figure out a sensible rev limit
+ //
+ m_revLimit = parameters->GetRevLimit();
+
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ m_debugInfo = debugPtr;
+#endif
+}
+
+void EngineState::SetActive( bool isActive, float prevPitch )
+{
+ bool wasActive = m_isActive;
+
+ m_isActive = isActive;
+ if( m_isActive && !wasActive )
+ {
+ startup( prevPitch );
+ }
+}
+
+void EngineState::SetDebugInfo()
+{
+ // Do nothing by default
+}
+
+bool EngineState::isAtIdleSpeed()
+{
+ return( m_vehicle->GetSpeedKmh()
+ <= ( m_parameters->GetShiftPoint( 1 )
+ * m_vehicle->mDesignerParams.mDpTopSpeedKmh ) );
+}
+
+bool EngineState::isSkidding()
+{
+ return( m_vehicle->GetSkidLevel() > 0.0f );
+}
+
+float EngineState::GetCurrentPitch()
+{
+ //
+ // Not needed by all states, so return zero by default.
+ //
+ return( 0.0f );
+}
+
+bool EngineState::IsFading()
+{
+ return( m_fadeTrim > 0.0f );
+}
+
+void EngineState::StartFade( float initialTrim, bool stopAfterFade )
+{
+ m_fadeTrim = initialTrim;
+ m_stopAfterFade = stopAfterFade;
+
+ //
+ // Check whether we're already faded
+ //
+ if( ( m_fadeTrim <= 0.0f )
+ && stopAfterFade )
+ {
+ m_player->Stop();
+ }
+ else
+ {
+ //
+ // Set the trim, in case the parent hasn't done it already
+ //
+ m_player->SetTrim( initialTrim );
+ }
+}
+
+void EngineState::ServiceFade( unsigned int elapsedTime )
+{
+ //
+ // Fade from 1.0f to 0.0f in 1/10th of a second, time picked arbitrarily
+ //
+ m_fadeTrim -= static_cast<float>( elapsedTime ) / 100.0f;
+ if( m_fadeTrim < 0.0f )
+ {
+ m_fadeTrim = 0.0f;
+ }
+
+ m_player->SetTrim( m_fadeTrim );
+
+ if( ( m_fadeTrim == 0.0f )
+ && m_stopAfterFade )
+ {
+ m_player->Stop();
+ }
+}
+
+void EngineState::SetTrim( float trim )
+{
+ //
+ // Cancel fades in effect
+ //
+ m_fadeTrim = 0.0f;
+
+ m_player->SetTrim( trim );
+}
+
+//******************************************************************************
+//
+// NormalEngineState
+//
+//******************************************************************************
+
+NormalEngineState::NormalEngineState() :
+ m_currentGear( 0 ),
+ m_currentSpeed( 0.0f ),
+ m_isAttacking( false ),
+ m_currentTrim( 1.0f ),
+ m_interpolateTime( 0 )
+{
+}
+
+NormalEngineState::~NormalEngineState()
+{
+}
+
+void NormalEngineState::Service( unsigned int elapsedTime )
+{
+ GearShiftResult startedShift;
+ float newPitch;
+ float trimDiff;
+ float pitchDiff;
+ float maxDiff;
+ float speedPcnt;
+ float shiftPoint;
+ float shiftSpeed;
+ float topSpeed;
+
+ if( ( m_interpolateTime > 0 ) && !m_isAttacking )
+ {
+ //
+ // Delaying
+ //
+ if( elapsedTime > m_interpolateTime )
+ {
+ //
+ // Delay done, start attack
+ //
+ m_interpolateTime = static_cast<unsigned int>(m_parameters->GetAttackTimeMsecs());
+ m_isAttacking = true;
+ }
+ else
+ {
+ //
+ // Delay not done
+ //
+ m_interpolateTime -= elapsedTime;
+
+ if( m_interpolateTime <= m_parameters->GetDelayTimeMsecs() )
+ {
+ m_currentTrim = m_parameters->GetDecayFinishTrim();
+ m_player->SetPitch( 1.0f );
+ }
+
+ //
+ // Since we're delaying, don't do anything else
+ //
+ return;
+ }
+ }
+ else if( m_interpolateTime > 0 )
+ {
+ //
+ // Attacking
+ //
+ if( elapsedTime > m_interpolateTime )
+ {
+ m_currentTrim = 1.0f;
+ m_interpolateTime = 0;
+ m_isAttacking = false;
+ }
+ else
+ {
+ m_interpolateTime -= elapsedTime;
+ trimDiff = static_cast<float>(elapsedTime) / m_parameters->GetAttackTimeMsecs();
+ m_currentTrim += trimDiff * ( 1.0f - m_parameters->GetDecayFinishTrim() ); // Increase at half-speed because we start at 0.5 above
+ if( m_currentTrim > 1.0f )
+ {
+ //
+ // Interpolation error
+ //
+ m_currentTrim = 1.0f;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Regular engine playback, make sure the attack is off and the trim is maxed.
+ //
+ m_isAttacking = false;
+
+ if( m_currentTrim != 1.0f )
+ {
+ m_currentTrim = 1.0f;
+ }
+ }
+
+ m_currentSpeed = m_vehicle->GetSpeedKmh();
+
+ if( m_vehicle->IsMovingBackward() )
+ {
+ m_nextState = ENGINE_STATE_REVERSE;
+ }
+ else if( m_vehicle->IsAirborn() )
+ {
+ m_nextState = ENGINE_STATE_IN_AIR;
+ }
+ else if( isSkidding() )
+ {
+ m_nextState = ENGINE_STATE_SKIDDING;
+ }
+ else
+ {
+ startedShift = updateCurrentGearFromVehicle();
+ if( ( startedShift == GEARSHIFT_UP )
+ || ( startedShift == GEARSHIFT_DOWN ) )
+ {
+ if( startedShift == GEARSHIFT_UP )
+ {
+ m_nextState = ENGINE_STATE_UPSHIFTING;
+ //
+ // Don't stop the player, start delay
+ //
+ m_interpolateTime = m_parameters->GetDelayTimeMsecs()
+ + static_cast<unsigned int>(m_parameters->GetDecayTimeMsecs());
+ if( m_interpolateTime > 0 )
+ {
+ m_currentTrim = 0.0f;
+ }
+ }
+ else if( m_currentGear > 0 )
+ {
+ m_nextState = ENGINE_STATE_DOWNSHIFTING;
+ }
+ else
+ {
+ m_nextState = ENGINE_STATE_IDLING;
+ }
+ }
+ else
+ {
+ if( startedShift == GEARSHIFT_DAMPED )
+ {
+ //
+ // If we're going slower than the speed appropriate for the gear,
+ // don't let the pitch drop too low
+ //
+ shiftPoint = m_parameters->GetShiftPoint( m_currentGear );
+ topSpeed = m_vehicle->mDesignerParams.mDpTopSpeedKmh;
+ shiftSpeed = shiftPoint * topSpeed;
+ speedPcnt = m_currentSpeed / shiftSpeed;
+ newPitch = m_parameters->CalculateEnginePitch( m_currentGear, shiftSpeed, topSpeed );
+ newPitch *= speedPcnt;
+ }
+ else
+ {
+ //
+ // No shift, just set the pitch to value appropriate to the vehicle speed
+ //
+ newPitch = m_parameters->CalculateEnginePitch( m_currentGear, m_currentSpeed,
+ m_vehicle->mDesignerParams.mDpTopSpeedKmh );
+ }
+
+ pitchDiff = newPitch - m_currentPitch;
+ maxDiff = static_cast<float>(elapsedTime) / m_parameters->GetMsecsPerOctaveCap();
+
+ //
+ // Ignore the calculated pitch if it means we're going to jump around
+ // too suddenly
+ //
+ if( pitchDiff >= 0.0f )
+ {
+ // Pitch rising
+ m_currentPitch += ( pitchDiff > maxDiff ) ? maxDiff : pitchDiff;
+ }
+ else
+ {
+ // Pitch dropping
+ m_currentPitch += ( pitchDiff < -maxDiff ) ? -maxDiff : pitchDiff;
+ }
+
+ if( m_currentPitch > m_revLimit )
+ {
+ m_currentPitch = m_revLimit;
+ }
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+
+ if( !m_isAttacking )
+ {
+ m_currentTrim = 1.0f;
+ }
+ }
+ }
+
+ if( m_nextState != ENGINE_STATE_INVALID )
+ {
+ if( ( m_nextState == ENGINE_STATE_DOWNSHIFTING )
+ || ( m_nextState == ENGINE_STATE_UPSHIFTING ) )
+ {
+ StartFade( m_currentTrim, false );
+ }
+ else
+ {
+ SetTrim( m_currentTrim );
+ }
+
+ if( m_nextState != ENGINE_STATE_UPSHIFTING )
+ {
+ SetActive( false );
+ }
+ }
+ else
+ {
+ SetTrim( m_currentTrim );
+ }
+
+ rAssertMsg( m_currentPitch >= 0.0f, "If you're running a debugger, tell Esan about this" );
+}
+
+void NormalEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_CURRENT_GEAR( m_currentGear );
+ SET_CURRENT_SPEED( m_currentSpeed );
+ }
+}
+
+float NormalEngineState::GetCurrentPitch()
+{
+ return( m_currentPitch );
+}
+
+void NormalEngineState::startup( float prevPitch )
+{
+ m_currentSpeed = m_vehicle->GetSpeedKmh();
+ m_currentGear = m_parameters->CalculateCurrentGear( m_vehicle->GetSpeedKmh(), m_currentSpeed,
+ m_vehicle->mDesignerParams.mDpTopSpeedKmh,
+ -1 );
+
+ //
+ // Start the sound
+ //
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+
+ m_currentTrim = 1.0f;
+ m_interpolateTime = 0;
+ if( prevPitch > 0.0f )
+ {
+ m_currentPitch = prevPitch;
+ }
+ else
+ {
+ m_currentPitch = m_parameters->CalculateEnginePitch( m_currentGear, m_currentSpeed,
+ m_vehicle->mDesignerParams.mDpTopSpeedKmh );
+ }
+ SetTrim( m_currentTrim );
+
+ if( m_currentPitch > m_revLimit )
+ {
+ m_currentPitch = m_revLimit;
+ }
+ m_player->SetPitch( m_currentPitch );
+}
+
+//=============================================================================
+// NormalEngineState::updateCurrentGearFromVehicle
+//=============================================================================
+// Description: Update m_currentGear from the current state of m_vehicle
+//
+// Parameters: dampenShifts - indicates whether we want to eliminate unnecessary
+// gear shifts. Not needed when we get in the car.
+//
+// Return: enumeration indicating if we shifted and if so, which direction
+//
+//=============================================================================
+GearShiftResult NormalEngineState::updateCurrentGearFromVehicle( bool dampenShifts /* = false */ )
+{
+ int currentGear;
+ GearShiftResult shiftResult;
+ float damperSize;
+ float upperShiftSpeed;
+ int oldGear = m_currentGear;
+ float topSpeed = m_vehicle->mDesignerParams.mDpTopSpeedKmh;
+
+ if( dampenShifts )
+ {
+ currentGear = m_currentGear;
+ }
+ else
+ {
+ currentGear = -1;
+ }
+
+ m_currentGear = m_parameters->CalculateCurrentGear( m_vehicle->GetSpeedKmh(), m_currentSpeed,
+ topSpeed, -1 );
+
+ if( m_currentGear == oldGear )
+ {
+ shiftResult = GEARSHIFT_NONE;
+ }
+ else
+ {
+ if( m_currentGear > oldGear )
+ {
+ if( m_vehicle->IsSafeToUpShift() )
+ {
+ shiftResult = GEARSHIFT_UP;
+ }
+ else
+ {
+ //
+ // Don't upshift when we're climbing hills, because the engine
+ // tends to stay bogged down at low revs
+ //
+ m_currentGear = oldGear;
+ shiftResult = GEARSHIFT_NONE;
+ }
+ }
+ else if( m_currentGear == 0 )
+ {
+ //
+ // Don't damp going into idle
+ //
+ shiftResult = GEARSHIFT_DOWN;
+ }
+ else
+ {
+ //
+ // Apply some gearshift damping
+ //
+ damperSize = m_parameters->GetDownshiftDamperSize() * topSpeed;
+ upperShiftSpeed = m_parameters->GetShiftPoint( m_currentGear + 1 ) * topSpeed;
+ if( ( upperShiftSpeed - m_currentSpeed ) <= damperSize )
+ {
+ shiftResult = GEARSHIFT_DAMPED;
+
+ //
+ // Wah. I think there's a problem where having the top gear too narrow can
+ // cause us to bump up into a non-existent gear. Don't do that.
+ //
+ if( upperShiftSpeed < topSpeed )
+ {
+ ++m_currentGear;
+ }
+ //else
+ //{
+ // rDebugString("Gotcha!");
+ //}
+ }
+ else
+ {
+ shiftResult = GEARSHIFT_DOWN;
+ }
+ }
+ }
+
+ return( shiftResult );
+}
+
+//******************************************************************************
+//
+// UpshiftEngineState
+//
+//******************************************************************************
+
+UpshiftEngineState::UpshiftEngineState()
+{
+}
+
+UpshiftEngineState::~UpshiftEngineState()
+{
+}
+
+void UpshiftEngineState::Service( unsigned int elapsedTime )
+{
+ float newPitch;
+ float timePercent;
+ float newTrim;
+ float targetTrim;
+
+ if( elapsedTime > m_remainingTime )
+ {
+ //
+ // Upshift is done, return to normal engine sound
+ //
+
+ //
+ // No need for state change, normal doesn't shut off on
+ // upshifts anymore
+ //
+ //m_nextState = ENGINE_STATE_NORMAL;
+
+ SetTrim( 1.0f );
+ m_player->Stop();
+ SetActive( false );
+ }
+ else
+ {
+ //
+ // Calculate the amount we need to drop the pitch in this frame
+ //
+ m_remainingTime -= elapsedTime;
+ timePercent = static_cast<float>(m_remainingTime) / static_cast<float>(m_shiftTimeMsecs);
+ newPitch = m_startPitch - ( ( 1.0f - timePercent ) * m_pitchDrop );
+ targetTrim = m_parameters->GetDecayFinishTrim();
+ newTrim = targetTrim + ( ( 1.0f - targetTrim ) * timePercent );
+
+ m_player->SetPitch( newPitch );
+ SET_CURRENT_PITCH( newPitch );
+ SetTrim( newTrim );
+ }
+}
+
+void UpshiftEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_SHIFT_IN_PROGRESS( true );
+ SET_SHIFT_TIME_REMAINING( m_remainingTime );
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ }
+}
+
+void UpshiftEngineState::startup( float prevPitch )
+{
+ int currentGear;
+ float currentSpeed;
+
+ //
+ // Initialize the current pitch, the amount we're going to drop it by,
+ // and the length of time we'll take to drop it
+ //
+ currentSpeed = m_vehicle->GetSpeedKmh();
+ currentGear = m_parameters->CalculateCurrentGear( currentSpeed, currentSpeed,
+ m_vehicle->mDesignerParams.mDpTopSpeedKmh,
+ -1 );
+
+ //
+ // Don't forget to subtract one from the gear because the parameter calculation
+ // will already have signalled the upshift, and we still want the old gear's pitch
+ //
+ m_startPitch = m_parameters->CalculateEnginePitch( currentGear - 1, currentSpeed,
+ m_vehicle->mDesignerParams.mDpTopSpeedKmh );
+ m_pitchDrop = m_parameters->GetGearShiftPitchDrop( currentGear );
+ m_shiftTimeMsecs = m_parameters->GetDecayTimeMsecs();
+ m_remainingTime = static_cast<unsigned int>(m_shiftTimeMsecs);
+
+ //
+ // Start the player
+ //
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+ m_player->SetPitch( m_startPitch );
+ SetTrim( 1.0f );
+}
+
+//******************************************************************************
+//
+// DownshiftEngineState
+//
+//******************************************************************************
+
+DownshiftEngineState::DownshiftEngineState()
+{
+}
+
+DownshiftEngineState::~DownshiftEngineState()
+{
+}
+
+void DownshiftEngineState::Service( unsigned int elapsedTime )
+{
+ float speedPercent;
+ float idlePitch;
+ float currentSpeed = m_vehicle->GetSpeedKmh();
+
+ if( isAtIdleSpeed() )
+ {
+ //
+ // Switch to idle sound
+ //
+ m_nextState = ENGINE_STATE_IDLING;
+
+ m_player->Stop();
+ SetActive( false );
+ }
+ else if( currentSpeed > m_lastSpeed )
+ {
+ //
+ // We've started accelerating again, switch to normal engine sound
+ //
+ m_nextState = ENGINE_STATE_NORMAL;
+
+ StartFade( 1.0f );
+ SetActive( false );
+ }
+ else
+ {
+ //
+ // Calculate new engine pitch
+ //
+ speedPercent = m_vehicle->GetSpeedKmh() / m_startSpeed;
+ // For now, use idle engine pitch for bottom of pitch range
+ idlePitch = m_parameters->GetIdleEnginePitch();
+ m_currentPitch = idlePitch + ( speedPercent * ( m_startPitch - idlePitch ) );
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+
+ m_lastSpeed = currentSpeed;
+ }
+}
+
+void DownshiftEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_SHIFT_IN_PROGRESS( true );
+ SET_SHIFT_TIME_REMAINING( 0 );
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ }
+}
+
+float DownshiftEngineState::GetCurrentPitch()
+{
+ return( m_currentPitch );
+}
+
+void DownshiftEngineState::startup( float prevPitch )
+{
+ //int currentGear;
+
+ m_startSpeed = m_vehicle->GetSpeedKmh();
+ m_lastSpeed = m_startSpeed;
+
+ //
+ // Find the speed that we need to interpolate over
+ //
+
+ // "+ 1" is because we're already in the new gear, and we want to interpolate
+ // from the last one
+ //currentGear = m_parameters->CalculateCurrentGear( m_startSpeed, m_startSpeed,
+ // m_vehicle->mDesignerParams.mDpTopSpeedKmh,
+ // -1 ) + 1;
+
+ //m_startPitch = m_parameters->CalculateEnginePitch( currentGear, m_startSpeed,
+ // m_vehicle->mDesignerParams.mDpTopSpeedKmh );
+ m_startPitch = prevPitch;
+ m_currentPitch = m_startPitch;
+
+ //
+ // Start the sound
+ //
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+ m_player->SetPitch( m_startPitch );
+}
+
+//******************************************************************************
+//
+// InAirEngineState
+//
+//******************************************************************************
+
+InAirEngineState::InAirEngineState()
+{
+}
+
+InAirEngineState::~InAirEngineState()
+{
+}
+
+void InAirEngineState::Service( unsigned int elapsedTime )
+{
+ float maxPitchChange;
+ float idlePitch;
+ float throttlePitch;
+ unsigned int responseTime;
+ float targetPitch;
+ float newPitch;
+
+ if( !(m_vehicle->IsAirborn()) )
+ {
+ if( isAtIdleSpeed() )
+ {
+ m_nextState = ENGINE_STATE_IDLING;
+ }
+ else if( isSkidding() )
+ {
+ m_nextState = ENGINE_STATE_SKIDDING;
+ }
+ else
+ {
+ m_nextState = ENGINE_STATE_NORMAL;
+ }
+
+ m_player->Stop();
+ SetActive( false );
+ }
+ else
+ {
+ //
+ // Calculate the maximum pitch change given the car's responsiveness
+ idlePitch = m_parameters->GetInAirIdlePitch();
+ throttlePitch = m_parameters->GetInAirThrottlePitch();
+ responseTime = m_parameters->GetInAirThrottleResponseTimeMsecs();
+ maxPitchChange = ( throttlePitch - idlePitch )
+ * ( static_cast<float>(elapsedTime) / static_cast<float>(responseTime) );
+
+ //
+ // Get target pitch
+ //
+ targetPitch = idlePitch + ( m_vehicle->mGas * ( throttlePitch - idlePitch ) );
+ if( targetPitch > m_currentPitch )
+ {
+ if( m_currentPitch + maxPitchChange > targetPitch )
+ {
+ newPitch = targetPitch;
+ }
+ else
+ {
+ newPitch = m_currentPitch + maxPitchChange;
+ }
+ }
+ else
+ {
+ if( m_currentPitch - maxPitchChange < targetPitch )
+ {
+ newPitch = targetPitch;
+ }
+ else
+ {
+ newPitch = m_currentPitch - maxPitchChange;
+ }
+ }
+
+ m_player->SetPitch( newPitch );
+ m_currentPitch = newPitch;
+ }
+}
+
+void InAirEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_CURRENT_PITCH( m_currentPitch );
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ }
+}
+
+void InAirEngineState::startup( float prevPitch )
+{
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+
+ m_currentPitch = prevPitch;
+
+ m_player->SetPitch( m_currentPitch );
+}
+
+//******************************************************************************
+//
+// ReverseEngineState
+//
+//******************************************************************************
+
+ReverseEngineState::ReverseEngineState( SimpsonsSoundPlayer* beepPlayer ) :
+ m_beepPlayer( beepPlayer )
+{
+}
+
+ReverseEngineState::~ReverseEngineState()
+{
+}
+
+void ReverseEngineState::Service( unsigned int elapsedTime )
+{
+ float speed;
+ float maxReverseSpeed;
+ float minPitch;
+ float maxPitch;
+ float newPitch;
+
+ speed = m_vehicle->GetSpeedKmh();
+
+ if( !(m_vehicle->IsMovingBackward()) )
+ {
+ if( m_vehicle->IsAirborn() )
+ {
+ m_nextState = ENGINE_STATE_IN_AIR;
+ }
+ else if( isAtIdleSpeed() )
+ {
+ m_nextState = ENGINE_STATE_IDLING;
+ }
+ else if( isSkidding() )
+ {
+ m_nextState = ENGINE_STATE_SKIDDING;
+ }
+ else
+ {
+ m_nextState = ENGINE_STATE_NORMAL;
+ }
+
+ m_beepPlayer->Stop();
+ SetActive( false );
+ }
+ else
+ {
+ //
+ // Set pitch based on speed
+ //
+ maxReverseSpeed = m_parameters->GetReversePitchCapKmh();
+ m_parameters->GetReversePitchRange( minPitch, maxPitch );
+ if( speed > maxReverseSpeed )
+ {
+ newPitch = maxPitch;
+ }
+ else
+ {
+ newPitch = minPitch + ( ( speed / maxReverseSpeed ) * ( maxPitch - minPitch ) );
+ }
+
+ m_player->SetPitch( newPitch );
+ SET_CURRENT_PITCH( newPitch );
+ }
+}
+
+void ReverseEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ SET_CURRENT_GEAR( -1 );
+ }
+}
+
+void ReverseEngineState::startup( float prevPitch )
+{
+ const char* backupClipName;
+
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+
+ //
+ // Call Service() to set the pitch
+ //
+ Service( 0 );
+
+ //
+ // If we have a backup beep sound, play it
+ //
+ if( ( backupClipName = m_parameters->GetBackupClipName() ) != NULL )
+ {
+ m_beepPlayer->PlaySound( backupClipName );
+ }
+}
+
+//******************************************************************************
+//
+// IdleEngineState
+//
+//******************************************************************************
+
+IdleEngineState::IdleEngineState() :
+ m_currentPitch( 0.0f )
+{
+}
+
+IdleEngineState::~IdleEngineState()
+{
+}
+
+void IdleEngineState::Service( unsigned int elapsedTime )
+{
+ float idlePitch;
+ float pitchDiff;
+ float maxDiff;
+
+ //
+ // Check for car motion, indicating we're leaving the idle state
+ //
+ if( m_vehicle->IsMovingBackward() )
+ {
+ m_nextState = ENGINE_STATE_REVERSE;
+ }
+ else if( isSkidding() )
+ {
+ m_nextState = ENGINE_STATE_SKIDDING;
+ }
+ else if( !isAtIdleSpeed() )
+ {
+ m_nextState = ENGINE_STATE_NORMAL;
+ }
+
+ if( m_nextState != ENGINE_STATE_INVALID )
+ {
+ //
+ // Deactivate self
+ //
+ m_player->Stop();
+ SetActive( false );
+ }
+ else
+ {
+ //
+ // Keep playing idle. Interpolate to it if we're not playing
+ // the idle pitch already
+ //
+ idlePitch = m_parameters->GetIdleEnginePitch();
+ if( m_currentPitch != idlePitch )
+ {
+ pitchDiff = idlePitch - m_currentPitch;
+ maxDiff = static_cast<float>(elapsedTime) / m_parameters->GetMsecsPerOctaveCap();
+
+ //
+ // Ignore the calculated pitch if it means we're going to jump around
+ // too suddenly
+ //
+ if( pitchDiff >= 0.0f )
+ {
+ // Pitch rising
+ m_currentPitch += ( pitchDiff > maxDiff ) ? maxDiff : pitchDiff;
+ }
+ else
+ {
+ // Pitch dropping
+ m_currentPitch += ( pitchDiff < -maxDiff ) ? -maxDiff : pitchDiff;
+ }
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+ }
+ }
+}
+
+void IdleEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ SET_CURRENT_GEAR( 0 );
+ }
+}
+
+float IdleEngineState::GetCurrentPitch()
+{
+ return( m_currentPitch );
+}
+
+void IdleEngineState::startup( float prevPitch )
+{
+ rAssert( m_parameters != NULL );
+
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+
+ m_currentPitch = m_parameters->GetIdleEnginePitch();
+ if( prevPitch != m_currentPitch )
+ {
+ m_currentPitch = prevPitch;
+ }
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+}
+
+//******************************************************************************
+//
+// SkidEngineState
+//
+//******************************************************************************
+
+SkidEngineState::SkidEngineState() :
+ m_currentPitch( 0.0f )
+{
+}
+
+SkidEngineState::~SkidEngineState()
+{
+}
+
+void SkidEngineState::Service( unsigned int elapsedTime )
+{
+ float burnoutLevel;
+ float desiredPitch;
+ float minBurnoutPitch;
+ float minPowerslidePitch;
+ float pitchDiff;
+ float maxDiff;
+
+ //
+ // Get a desired pitch based on the burnout level that the
+ // vehicle object gives us
+ //
+ if( isSkidding() )
+ {
+ //
+ // Sometimes we're skidding, sometimes we're burning out. Try to figure out
+ // which value makes more sense.
+ //
+ if( m_vehicle->mBurnoutLevel > 0.0f )
+ {
+ burnoutLevel = m_vehicle->mBurnoutLevel;
+
+ minBurnoutPitch = m_parameters->GetBurnoutMinPitch();
+ desiredPitch = minBurnoutPitch +
+ ( ( m_parameters->GetBurnoutMaxPitch() - minBurnoutPitch )
+ * burnoutLevel );
+ }
+ else
+ {
+ //burnoutLevel = m_vehicle->GetSkidLevel();
+
+ //
+ // The skid level appears to be a constant value of 0.5. Try using the
+ // vehicle gas value instead, since the tires would be spinning kinda
+ // freely in the real world anyway.
+ //
+ // HACK: Since sliding skids seem to be quite different from burnouts,
+ // bump the burnout level beyond 1.0f at will to make this sound right.
+ // This should be a separate set of tuning parameters next time.
+ //
+ burnoutLevel = m_vehicle->mGas;
+
+ minPowerslidePitch = m_parameters->GetPowerslideMinPitch();
+ desiredPitch = minPowerslidePitch +
+ ( ( m_parameters->GetPowerslideMaxPitch() - minPowerslidePitch )
+ * burnoutLevel );
+ }
+
+ //
+ // Ease toward desired pitch
+ //
+ pitchDiff = desiredPitch - m_currentPitch;
+ maxDiff = static_cast<float>(elapsedTime) / ( m_parameters->GetMsecsPerOctaveCap() * 4 );
+
+ //
+ // Ignore the calculated pitch if it means we're going to jump around
+ // too suddenly
+ //
+ if( pitchDiff >= 0.0f )
+ {
+ // Pitch rising
+ m_currentPitch += ( pitchDiff > maxDiff ) ? maxDiff : pitchDiff;
+ }
+ else
+ {
+ // Pitch dropping
+ m_currentPitch += ( pitchDiff < -maxDiff ) ? -maxDiff : pitchDiff;
+ }
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+ }
+ else
+ {
+ if( isAtIdleSpeed() )
+ {
+ m_nextState = ENGINE_STATE_IDLING;
+ }
+ else if( m_vehicle->IsMovingBackward() )
+ {
+ m_nextState = ENGINE_STATE_REVERSE;
+ }
+ else
+ {
+ m_nextState = ENGINE_STATE_NORMAL;
+ }
+
+ SetActive( false );
+ }
+}
+
+void SkidEngineState::SetDebugInfo()
+{
+ if( IsActive() )
+ {
+ SET_CURRENT_SPEED( m_vehicle->GetSpeedKmh() );
+ }
+}
+
+float SkidEngineState::GetCurrentPitch()
+{
+ return( m_currentPitch );
+}
+
+void SkidEngineState::startup( float prevPitch )
+{
+ rAssert( m_parameters != NULL );
+
+ if( !(m_player->IsInUse()) )
+ {
+ m_player->PlaySound( m_resourceKey );
+ }
+
+ m_currentPitch = prevPitch;
+
+ m_player->SetPitch( m_currentPitch );
+ SET_CURRENT_PITCH( m_currentPitch );
+}
+
+//******************************************************************************
+//
+// VehicleSoundPlayer
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// VehicleSoundPlayer::VehicleSoundPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+VehicleSoundPlayer::VehicleSoundPlayer() :
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ m_debugInfo( 2, GetSoundManager()->GetDebugDisplay() ),
+#endif
+ m_vehicle( NULL ),
+ m_parameters( NULL ),
+ m_peeloutSettings( NULL ),
+ m_isSkidding( false ),
+ m_hornPlaying( false ),
+ m_oneTimeHorn( false ),
+ m_powerslideTrim( 0.0f ),
+ m_playingDamage( false ),
+ m_proximityAIVehicle( NULL ),
+ m_terrainType( TT_Road )
+{
+ m_engineStates[ENGINE_STATE_NORMAL] = new NormalEngineState();
+ m_engineStates[ENGINE_STATE_UPSHIFTING] = new UpshiftEngineState();
+ m_engineStates[ENGINE_STATE_DOWNSHIFTING] = new DownshiftEngineState();
+ m_engineStates[ENGINE_STATE_IN_AIR] = new InAirEngineState();
+ m_engineStates[ENGINE_STATE_REVERSE] = new ReverseEngineState( &(m_soundPlayers[CARPLAYER_BACKUP_BEEP]) );
+ m_engineStates[ENGINE_STATE_IDLING] = new IdleEngineState();
+ m_engineStates[ENGINE_STATE_SKIDDING] = new SkidEngineState();
+
+ if( !s_resetEngineInitialized )
+ {
+ radDbgWatchAddBoolean( &s_resetEngineOnHonk, "Reset engine on honk", "Sound Info" );
+ }
+}
+
+//==============================================================================
+// VehicleSoundPlayer::~VehicleSoundPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+VehicleSoundPlayer::~VehicleSoundPlayer()
+{
+ int i;
+
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ delete m_engineStates[i];
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::StartCarSounds
+//=============================================================================
+// Description: Begin playing car-related sounds
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::StartCarSounds( Vehicle* newVehicle )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ VehicleSoundDebugPage* debugPtr;
+ const char* overlayName;
+
+ rAssert( newVehicle != NULL );
+
+ GetEventManager()->TriggerEvent( EVENT_AVATAR_VEHICLE_TOGGLE, newVehicle );
+
+ //
+ // Don't bother switching sounds if we're already playing this car
+ //
+ if( ( newVehicle == m_vehicle ) && carSoundIsActive() )
+ {
+ return;
+ }
+
+ //
+ // Remember which vehicle we're playing
+ //
+ m_vehicle = newVehicle;
+
+ //
+ // Get the car sound parameter object for this vehicle.
+ //
+ // IMPORTANT: We assume that the object in the namespace has the same
+ // name as the one in the vehicle object, which comes from the loading
+ // script for that car, I think.
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ nameSpaceObj = nameSpace->GetInstance( m_vehicle->GetName() );
+ if( nameSpaceObj != NULL )
+ {
+ m_parameters = reinterpret_cast<carSoundParameters*>( nameSpaceObj );
+
+ //
+ // Set up the Watcher tuning
+ //
+ m_parameters->SetWatcherName( m_vehicle->GetName() );
+
+ //
+ // Get global car values
+ //
+ nameSpaceObj = nameSpace->GetInstance( "tuner" );
+ rAssert( nameSpaceObj != NULL );
+ m_peeloutSettings = reinterpret_cast<globalSettings*>( nameSpaceObj );
+
+ const char* clipName = m_parameters->GetEngineClipName();
+
+ const char* idleClipName = m_parameters->GetEngineIdleClipName();
+ if( idleClipName == NULL )
+ {
+ //
+ // No idle clip, use the engine clip by default
+ //
+ idleClipName = clipName;
+ }
+
+ if( ( clipName != NULL ) && ( idleClipName != NULL ) )
+ {
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ debugPtr = &m_debugInfo;
+#else
+ debugPtr = NULL;
+#endif
+
+ //
+ // Initialize the engine sound states
+ //
+ m_engineStates[ENGINE_STATE_NORMAL]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_ENGINE],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_UPSHIFTING]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_SHIFT],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_DOWNSHIFTING]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_SHIFT],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_IN_AIR]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_ENGINE],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_REVERSE]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_ENGINE],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_IDLING]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_ENGINE],
+ ::radMakeKey32( idleClipName ),
+ debugPtr );
+ m_engineStates[ENGINE_STATE_SKIDDING]->Initialize( newVehicle, m_parameters,
+ &m_soundPlayers[CARPLAYER_ENGINE],
+ ::radMakeKey32( clipName ),
+ debugPtr );
+
+ //
+ // Assume that we're getting into an idle car
+ //
+ m_engineStates[ENGINE_STATE_IDLING]->SetActive( true );
+ }
+ else
+ {
+ //
+ // What the...? No engine clip? That's not right.
+ //
+ rTuneString( "WARNING: No engine clip found. No engine sounds will be played.\n" );
+ m_vehicle = NULL;
+ }
+
+ //
+ // If we have an overlay clip, start it
+ //
+ overlayName = m_parameters->GetOverlayClipName();
+ if( overlayName != NULL )
+ {
+ m_soundPlayers[CARPLAYER_OVERLAY].PlaySound( overlayName );
+ }
+ }
+ else
+ {
+ rTunePrintf( "Couldn't find carSoundParameters object named %s, no sound played\n",
+ m_vehicle->GetName() );
+ m_vehicle = NULL;
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::StopCarSounds
+//=============================================================================
+// Description: Stop playing car-related sounds
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::StopCarSounds()
+{
+ unsigned int i;
+
+ for( i = 0; i < CARPLAYER_NUMPLAYERS; i++ )
+ {
+ m_soundPlayers[i].Stop();
+ }
+
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ m_engineStates[i]->SetActive( false );
+ m_engineStates[i]->Reset();
+ }
+
+ m_proximityAIVehicle = NULL;
+
+ GetEventManager()->TriggerEvent( EVENT_AVATAR_VEHICLE_TOGGLE, m_vehicle );
+}
+
+//=============================================================================
+// VehicleSoundPlayer::UpdateSoundParameters
+//=============================================================================
+// Description: Look at the car sound parameter object, and make sure that
+// the engine sound is being played at a pitch appropriate for
+// the vehicle RPMs.
+//
+// Parameters: elapsedTime - time since last frame in msecs
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::UpdateSoundParameters( unsigned int elapsedTime )
+{
+ //float newPitch;
+ //unsigned int shiftTime;
+ int i;
+ static bool warningPrinted = false;
+ bool activateState[NUM_ENGINE_STATES];
+ float prevStatePitch[NUM_ENGINE_STATES];
+ EngineStateEnum newState;
+
+ //
+ // Before updating, check to make sure we have a vehicle. If we don't,
+ // then we got into a car that didn't have a carSoundParameters object
+ // associated with it. Handle it gracefully, but we really should fix it
+ //
+ if( m_vehicle != NULL )
+ {
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ activateState[i] = false;
+ prevStatePitch[i] = 0.0f;
+ }
+
+ //
+ // Service the active engine states
+ //
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ if( m_engineStates[i]->IsActive() )
+ {
+ m_engineStates[i]->Service( elapsedTime );
+ if( m_engineStates[i]->StartNewState() )
+ {
+ newState = m_engineStates[i]->GetNewState();
+ activateState[newState] = true;
+ prevStatePitch[newState] = m_engineStates[i]->GetCurrentPitch();
+ }
+ }
+ }
+
+ //
+ // Service fades
+ //
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ if( m_engineStates[i]->IsFading() )
+ {
+ m_engineStates[i]->ServiceFade( elapsedTime );
+ }
+ }
+
+ //
+ // Initialize debug info
+ //
+ SET_LOCAL_SHIFT_IN_PROGRESS( false );
+
+ //
+ // Start up any states that were marked for activation during servicing
+ //
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ if( activateState[i] )
+ {
+ m_engineStates[i]->SetActive( true, prevStatePitch[i] );
+ }
+
+ m_engineStates[i]->Reset();
+
+ m_engineStates[i]->SetDebugInfo();
+ }
+ }
+ else
+ {
+ if( !warningPrinted )
+ {
+ rTuneString("Warning: Vehicle doesn't have a sound associated with it (CarSoundParameters)\n");
+ warningPrinted = true;
+ }
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::UpdateOncePerFrame
+//=============================================================================
+// Description: Update routine, used to set the engine RPMs correctly and
+// check for skids, gear changes, and horns
+//
+// Parameters: elapsedTime - time since last frame in msecs
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::UpdateOncePerFrame( unsigned int elapsedTime )
+{
+ UpdateSoundParameters( elapsedTime );
+ checkDamage();
+ CheckForSkid( elapsedTime );
+ CheckHorn();
+ checkProximity();
+
+ //
+ // Debug stuff
+ //
+ if( ( m_parameters != NULL ) && ( m_vehicle != NULL ) )
+ {
+ /*SET_SHIFT_IN_PROGRESS( m_gearChangeInProgress );
+ SET_CURRENT_GEAR( m_currentGear );
+ SET_CURRENT_SPEED( m_currentSpeed );
+ SET_SHIFT_TIME_REMAINING( m_gearChangeTimeRemaining );
+ SET_DOWNSHIFT_SPEED( m_parameters->GetLowShiftPoint( m_currentGear ) * m_vehicle->mDesignerParams.mDpTopSpeedKmh );
+ SET_UPSHIFT_SPEED( m_parameters->GetHighShiftPoint( m_currentGear ) * m_vehicle->mDesignerParams.mDpTopSpeedKmh );*/
+ SET_LOCAL_IS_DAMAGED( m_playingDamage );
+ SET_LOCAL_VEHICLE_LIFE( m_vehicle->GetVehicleLifePercentage(m_vehicle->mHitPoints) );
+ SET_LOCAL_DAMAGE_THRESHOLD( m_parameters->GetDamageStartPcnt() );
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::CheckForSkid
+//=============================================================================
+// Description: Check the vehicle object to see if we're skidding, and make
+// the appropriate noise
+//
+// Parameters: elapsedTime - time elapsed in the last frame
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::CheckForSkid( unsigned int elapsedTime )
+{
+ bool skidPlaySuccessful;
+ float trim;
+ float skidLevel;
+ float peeloutMin;
+ float peeloutMax;
+ const char* skidName;
+ bool isSupersprint;
+ float trimMax;
+
+ //
+ // If we don't have a car, don't do anything
+ //
+ if( m_vehicle == NULL )
+ {
+ return;
+ }
+
+ //
+ // Find out if the car is skidding
+ //
+ skidLevel = m_vehicle->GetSkidLevel();
+ peeloutMin = m_peeloutSettings->GetPeeloutMin();
+ peeloutMax = m_peeloutSettings->GetPeeloutMax();
+ if( skidLevel > peeloutMin )
+ {
+ //
+ // Vehicle skidding. Start making tire squeal if we're not doing it yet
+ //
+ if( !m_isSkidding )
+ {
+ //
+ // Get the terrain type underneath the car so we know which sound
+ // resource to play
+ //
+ m_terrainType = m_vehicle->mTerrainType;
+ skidName = getSkidResourceForTerrain( m_terrainType );
+
+ //
+ // Squeal like a pig, boy
+ //
+ skidPlaySuccessful =
+ m_soundPlayers[CARPLAYER_SKID].PlaySound( skidName );
+ rAssert( skidPlaySuccessful );
+
+ m_isSkidding = true;
+ m_powerslideTrim = 0.0f;
+
+ //
+ // If we're starting from a slow speed, assume this is a burnout
+ //
+
+ // move the triggering, and triggering of the END of this event, to
+ // Vehicle since Cary wants it also, to play with the camera
+
+ //if( m_vehicle->GetSpeedKmh() < 10.0f )
+ //{
+ // GetEventManager()->TriggerEvent( EVENT_BURNOUT );
+ //}
+ }
+ else
+ {
+ //
+ // Check for whether we've changed terrain types
+ //
+ if( m_vehicle->mTerrainType != m_terrainType )
+ {
+ m_terrainType = m_vehicle->mTerrainType;
+ skidName = getSkidResourceForTerrain( m_terrainType );
+
+ m_soundPlayers[CARPLAYER_SKID].Stop();
+
+ skidPlaySuccessful =
+ m_soundPlayers[CARPLAYER_SKID].PlaySound( skidName );
+ rAssert( skidPlaySuccessful );
+ }
+ }
+
+ if( m_vehicle->mBurnoutLevel > 0.0f )
+ {
+ //
+ // Burnout
+ //
+ if( skidLevel >= peeloutMax )
+ {
+ trim = m_peeloutSettings->GetPeeloutMaxTrim();
+ }
+ else
+ {
+ trim = ( ( skidLevel - peeloutMin ) / ( peeloutMax - peeloutMin ) )
+ * m_peeloutSettings->GetPeeloutMaxTrim();
+ }
+ }
+ else
+ {
+ //
+ // Powerslide
+ //
+ if( ( GetGameplayManager() != NULL )
+ && ( GetGameplayManager()->IsSuperSprint() ) )
+ {
+ isSupersprint = true;
+ trimMax = SUPERSPRINT_POWERSLIDE_TRIM_MAX;
+ }
+ else
+ {
+ isSupersprint = false;
+ trimMax = GAME_POWERSLIDE_TRIM_MAX;
+ }
+
+ if( m_powerslideTrim <= 0.0f )
+ {
+ if( isSupersprint )
+ {
+ m_powerslideTrim = SUPERSPRINT_POWERSLIDE_TRIM_MIN;
+ }
+ else
+ {
+ m_powerslideTrim = GAME_POWERSLIDE_TRIM_MIN;
+ }
+ }
+ else
+ {
+ m_powerslideTrim += static_cast<float>(elapsedTime) * 0.0003f;
+ }
+
+ if( m_powerslideTrim > trimMax )
+ {
+ m_powerslideTrim = trimMax;
+ }
+
+ trim = m_powerslideTrim;
+ }
+ m_soundPlayers[CARPLAYER_SKID].SetTrim( trim );
+ }
+ else
+ {
+ //
+ // Not skidding. Stop the noise if it's playing
+ //
+ if( m_isSkidding )
+ {
+ m_soundPlayers[CARPLAYER_SKID].Stop();
+ m_isSkidding = false;
+ }
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::CheckHorn
+//=============================================================================
+// Description: Find the vehicle controller, and check to see whether the horn
+// button is being pressed and play/stop/do nothing with the
+// horn clip appropriately
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::CheckHorn()
+{
+ int vehicleId;
+ VehicleController* controller;
+ bool hornPlaySuccessful;
+ float buttonVal = 0.0f;
+ const char* hornClipName;
+ IDaSoundResource* resource;
+
+ if( m_vehicle == NULL )
+ {
+ return;
+ }
+
+ //
+ // Find the horn button for this vehicle and get its state
+ //
+ vehicleId = GetVehicleCentral()->GetVehicleId( m_vehicle, false );
+ controller = GetVehicleCentral()->GetVehicleController( vehicleId );
+
+ //
+ // Controller might already be gone, if we're playing car sound while
+ // the player is getting out of the car.
+ //
+ if( controller != NULL )
+ {
+ buttonVal = controller->GetHorn();
+ }
+
+ //
+ // Look for whether we need to start/stop a sound
+ //
+ if( buttonVal > 0.05f )
+ {
+ if( !m_hornPlaying )
+ {
+ //
+ // Horn button has just been pressed, find the correct clip and play it
+ //
+ rAssert( m_parameters != NULL );
+ hornClipName = m_parameters->GetHornClipName();
+
+ if( hornClipName == NULL )
+ {
+ hornClipName = "horn";
+ }
+
+ //
+ // Just in case we were still playing a non-looping horn sound
+ //
+ m_soundPlayers[CARPLAYER_HORNPLAYER].Stop();
+
+ hornPlaySuccessful =
+ m_soundPlayers[CARPLAYER_HORNPLAYER].PlaySound( hornClipName );
+ rAssert( hornPlaySuccessful );
+
+ m_hornPlaying = true;
+
+ //
+ // Find out if this is looping horn sound
+ //
+ resource = Sound::daSoundRenderingManagerGet()->GetResourceManager()->FindResource( hornClipName );
+ rAssert( resource != NULL );
+
+ // Sanity check
+ if( resource == NULL )
+ {
+ rTunePrintf( "No horn named %s found\n", hornClipName );
+ m_oneTimeHorn = true;
+ }
+ else
+ {
+ m_oneTimeHorn = !( resource->GetLooping() );
+ }
+
+#ifndef RAD_RELEASE
+ //
+ // Tuning hack. Stop and restart the engine to pick up any trim changes
+ //
+ if( s_resetEngineOnHonk )
+ {
+ Vehicle* theCar = m_vehicle;
+ StopCarSounds();
+ StartCarSounds( theCar );
+ }
+#endif
+ }
+ }
+ else
+ {
+ if( m_hornPlaying )
+ {
+ //
+ // Horn button has just been released, stop the clip
+ //
+ if( !m_oneTimeHorn )
+ {
+ m_soundPlayers[CARPLAYER_HORNPLAYER].Stop();
+ }
+ m_hornPlaying = false;
+ }
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::OnPlaybackComplete
+//=============================================================================
+// Description: SimpsonsSoundPlayer callback, used when gearshift is done
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::OnPlaybackComplete()
+{
+}
+
+//=============================================================================
+// VehicleSoundPlayer::OnSoundReady
+//=============================================================================
+// Description: Unused, required for SimpsonsSoundPlayerCallback interface
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::OnSoundReady()
+{
+}
+
+//=============================================================================
+// VehicleSoundPlayer::AddAIVehicleProximityTest
+//=============================================================================
+// Description: Add check for proximity to newly spawned AI vehicle
+//
+// Parameters: aiVehicle - vehicle to test
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::AddAIVehicleProximityTest( Vehicle* aiVehicle )
+{
+ if( m_proximityAIVehicle == NULL )
+ {
+ m_proximityAIVehicle = aiVehicle;
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::DeleteAIVehicleProximityTest
+//=============================================================================
+// Description: Stop proximity testing for given vehicle, if that's the one
+// we're currently testing.
+//
+// Parameters: aiVehicle - vehicle to stop testing for
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::DeleteAIVehicleProximityTest( Vehicle* aiVehicle )
+{
+ if( m_proximityAIVehicle == aiVehicle )
+ {
+ m_proximityAIVehicle = NULL;
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::PlayDoorOpen
+//=============================================================================
+// Description: Play a door opening sound
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::PlayDoorOpen()
+{
+}
+
+//=============================================================================
+// VehicleSoundPlayer::PlayDoorClose
+//=============================================================================
+// Description: Play a door closing sound
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::PlayDoorClose()
+{
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// VehicleSoundPlayer::checkDamage
+//=============================================================================
+// Description: Start or stop the damage sound for this vehicle as appropriate
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::checkDamage()
+{
+ float damagePercentage;
+ float lifePercentage;
+ float damageTrimPercentage;
+ float damageTrim;
+ float trimRange;
+ float minTrim;
+
+ if( m_vehicle == NULL )
+ {
+ return;
+ }
+
+ damagePercentage = m_parameters->GetDamageStartPcnt();
+ lifePercentage = m_vehicle->GetVehicleLifePercentage(m_vehicle->mHitPoints);
+ minTrim = m_parameters->GetDamageStartTrim();
+ trimRange = m_parameters->GetDamageMaxTrim() - m_parameters->GetDamageStartTrim();
+
+ if( ( lifePercentage <= damagePercentage ) && ( !m_playingDamage ) )
+ {
+ m_playingDamage = true;
+ m_soundPlayers[CARPLAYER_DAMAGE].PlaySound( m_parameters->GetDamagedEngineClipName() );
+
+ //
+ // Scale volume by amount of damage
+ //
+ damageTrimPercentage = ( damagePercentage - lifePercentage ) / m_parameters->GetDamageVolumeRange();
+ if( damageTrimPercentage > 1.0f )
+ {
+ damageTrimPercentage = 1.0f;
+ }
+ damageTrim = minTrim + ( damageTrimPercentage * trimRange );
+ m_soundPlayers[CARPLAYER_DAMAGE].SetTrim( damageTrim );
+ }
+ else if( m_playingDamage )
+ {
+ if( lifePercentage > damagePercentage )
+ {
+ //
+ // Must've reset or something
+ //
+ m_playingDamage = false;
+ m_soundPlayers[CARPLAYER_DAMAGE].Stop();
+ }
+ else
+ {
+ //
+ // Adjust volume
+ //
+ damageTrimPercentage = ( damagePercentage - lifePercentage ) / m_parameters->GetDamageVolumeRange();
+ if( damageTrimPercentage > 1.0f )
+ {
+ damageTrimPercentage = 1.0f;
+ }
+ damageTrim = minTrim + ( damageTrimPercentage * trimRange );
+ m_soundPlayers[CARPLAYER_DAMAGE].SetTrim( damageTrim );
+ }
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::carSoundIsActive
+//=============================================================================
+// Description: Indicate whether any of the engine sound states are going
+//
+// Parameters: None
+//
+// Return: true if a state is active, false otherwise
+//
+//=============================================================================
+bool VehicleSoundPlayer::carSoundIsActive()
+{
+ int i;
+ bool isActive = false;
+
+ for( i = 0; i < NUM_ENGINE_STATES; i++ )
+ {
+ if( m_engineStates[i]->IsActive() )
+ {
+ isActive = true;
+ break;
+ }
+ }
+
+ return( isActive );
+}
+
+//=============================================================================
+// VehicleSoundPlayer::checkProximity
+//=============================================================================
+// Description: Determine whether AI vehicle has gotten close enough to
+// trigger an event
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehicleSoundPlayer::checkProximity()
+{
+ rmt::Vector position1;
+ rmt::Vector position2;
+
+ //rAssert( m_vehicle != NULL );
+
+ if( m_proximityAIVehicle != NULL && m_vehicle != NULL )
+ {
+ m_vehicle->GetPosition( &position1 );
+ m_proximityAIVehicle->GetPosition( &position2 );
+
+ //
+ // Trigger event at 20 (use 20^2 for efficiency) metres
+ //
+ position1.Sub( position2 );
+ if( position1.MagnitudeSqr() < 400.0f )
+ {
+ GetEventManager()->TriggerEvent( EVENT_CHASE_VEHICLE_PROXIMITY );
+ m_proximityAIVehicle = NULL;
+ }
+ }
+}
+
+//=============================================================================
+// VehicleSoundPlayer::getSkidResourceForTerrain
+//=============================================================================
+// Description: Find the name of the sound resource for a skid appropriate
+// for the kind of ground we're driving over
+//
+// Parameters: terrain - type of terrain the car is over right now
+//
+// Return: name of sound resource to use
+//
+//=============================================================================
+const char* VehicleSoundPlayer::getSkidResourceForTerrain( eTerrainType terrain )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ globalSettings* clipNameObj;
+ const char* name;
+ bool terrainIsDirt = ( terrain == TT_Dirt )
+ || ( terrain == TT_Sand )
+ || ( terrain == TT_Gravel )
+ || ( terrain == TT_Grass );
+
+ //
+ // First, see if we have something specific for this car
+ //
+ rAssert( m_parameters != NULL );
+ if( terrainIsDirt )
+ {
+ name = m_parameters->GetDirtSkidClipName();
+ }
+ else
+ {
+ name = m_parameters->GetRoadSkidClipName();
+ }
+
+ if( name == NULL )
+ {
+ //
+ // No car-specific skid, get the global one from the globalSettings
+ // object
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( "tuner" );
+ rAssert( nameSpaceObj != NULL );
+
+ clipNameObj = static_cast<globalSettings*>( nameSpaceObj );
+
+ if( terrainIsDirt )
+ {
+ name = clipNameObj->GetSkidDirtClipName();
+ }
+ else
+ {
+ name = clipNameObj->GetSkidRoadClipName();
+ }
+ }
+
+ rAssert( name != NULL );
+
+ return( name );
+}
diff --git a/game/code/sound/avatar/vehiclesoundplayer.h b/game/code/sound/avatar/vehiclesoundplayer.h
new file mode 100644
index 0000000..45e9665
--- /dev/null
+++ b/game/code/sound/avatar/vehiclesoundplayer.h
@@ -0,0 +1,162 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclesoundplayer.h
+//
+// Description: Declaration of the VehicleSoundPlayer class, which plays sounds
+// for user-controlled vehicles in game.
+//
+// History: 30/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef VEHICLESOUNDPLAYER_H
+#define VEHICLESOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <sound/simpsonssoundplayer.h>
+#include <sound/avatar/vehiclesounddebugpage.h>
+#include <render/IntersectManager/IntersectManager.h>
+
+//========================================
+// Forward References
+//========================================
+
+class Vehicle;
+class carSoundParameters;
+class globalSettings;
+class VehicleSoundPlayer;
+class EngineState;
+
+//
+// Enumerated list of temporary engine states
+//
+enum EngineStateEnum
+{
+ ENGINE_STATE_NORMAL,
+ ENGINE_STATE_UPSHIFTING,
+ ENGINE_STATE_DOWNSHIFTING,
+ ENGINE_STATE_IN_AIR,
+ ENGINE_STATE_REVERSE,
+ ENGINE_STATE_IDLING,
+ ENGINE_STATE_SKIDDING,
+
+ NUM_ENGINE_STATES,
+
+ ENGINE_STATE_INVALID
+};
+
+//=============================================================================
+//
+// Synopsis: VehicleSoundPlayer
+//
+//=============================================================================
+
+class VehicleSoundPlayer : public SimpsonsSoundPlayerCallback
+{
+ public:
+ VehicleSoundPlayer();
+ virtual ~VehicleSoundPlayer();
+
+ //
+ // Update routines
+ //
+ void UpdateOncePerFrame( unsigned int elapsedTime );
+
+ void UpdateSoundParameters( unsigned int elapsedTime );
+
+ //
+ // Check the vehicle to see if we should be playing a skid noise
+ //
+ void CheckForSkid( unsigned int elapsedTime );
+
+ //
+ // Check the vehicle controller to see if we should be playing
+ // a horn noise
+ //
+ void CheckHorn();
+
+ //
+ // Start and stop sound when the player gets in and out of the car
+ //
+ void StartCarSounds( Vehicle* newVehicle );
+ void StopCarSounds();
+
+ //
+ // Play door sounds
+ //
+ void PlayDoorOpen();
+ void PlayDoorClose();
+
+ //
+ // Called when gearshift is done playing
+ //
+ void OnPlaybackComplete();
+
+ //
+ // Needed to complete SimpsonsSoundPlayerCallback interface
+ //
+ void OnSoundReady();
+
+ //
+ // Proximity testing for AI vehicle dialog (better here than
+ // anywhere else)
+ //
+ void AddAIVehicleProximityTest( Vehicle* aiVehicle );
+ void DeleteAIVehicleProximityTest( Vehicle* aiVehicle );
+
+ private:
+ //Prevent wasteful constructor creation.
+ VehicleSoundPlayer( const VehicleSoundPlayer& original );
+ VehicleSoundPlayer& operator=( const VehicleSoundPlayer& rhs );
+
+ bool carSoundIsActive();
+
+ void checkDamage();
+ void checkProximity();
+
+ const char* getSkidResourceForTerrain( eTerrainType terrain );
+
+ enum CarSoundPlayers
+ {
+ CARPLAYER_ENGINE,
+ CARPLAYER_SHIFT,
+ CARPLAYER_SKID,
+ CARPLAYER_HORNPLAYER,
+ CARPLAYER_DAMAGE,
+ CARPLAYER_OVERLAY,
+ CARPLAYER_BACKUP_BEEP,
+ CARPLAYER_DOOR,
+
+ CARPLAYER_NUMPLAYERS
+ };
+
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ VehicleSoundDebugPage m_debugInfo;
+#endif
+
+ SimpsonsSoundPlayer m_soundPlayers[CARPLAYER_NUMPLAYERS];
+ EngineState* m_engineStates[NUM_ENGINE_STATES];
+
+ Vehicle* m_vehicle;
+ carSoundParameters* m_parameters;
+ globalSettings* m_peeloutSettings;
+
+ bool m_isSkidding;
+ bool m_hornPlaying;
+ bool m_oneTimeHorn;
+ float m_powerslideTrim;
+
+ bool m_playingDamage;
+
+ Vehicle* m_proximityAIVehicle;
+
+ eTerrainType m_terrainType;
+};
+
+
+#endif // VEHICLESOUNDPLAYER_H
+
diff --git a/game/code/sound/dialog/alldialog.cpp b/game/code/sound/dialog/alldialog.cpp
new file mode 100644
index 0000000..b4681d5
--- /dev/null
+++ b/game/code/sound/dialog/alldialog.cpp
@@ -0,0 +1,11 @@
+#include <sound/dialog/conversation.cpp>
+#include <sound/dialog/conversationmatcher.cpp>
+#include <sound/dialog/dialogcoordinator.cpp>
+#include <sound/dialog/dialogline.cpp>
+#include <sound/dialog/dialoglist.cpp>
+#include <sound/dialog/dialogpriorityqueue.cpp>
+#include <sound/dialog/dialogqueueelement.cpp>
+#include <sound/dialog/dialogselectiongroup.cpp>
+#include <sound/dialog/playabledialog.cpp>
+#include <sound/dialog/selectabledialog.cpp>
+#include <sound/dialog/dialogsounddebugpage.cpp>
diff --git a/game/code/sound/dialog/conversation.cpp b/game/code/sound/dialog/conversation.cpp
new file mode 100644
index 0000000..4aac61b
--- /dev/null
+++ b/game/code/sound/dialog/conversation.cpp
@@ -0,0 +1,408 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: conversation.cpp
+//
+// Description: Conversation objects aggregate groups of DialogLine objects
+// which are intended to be played without interruption, like
+// a conversation. Hence the name.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <stdio.h>
+#include <raddebug.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/conversation.h>
+
+#include <sound/dialog/dialogline.h>
+#include <sound/dialog/dialogselectiongroup.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// Conversation::Conversation
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Conversation::Conversation( DialogLine& line ) :
+ PlayableDialog( line.GetLevel(), line.GetMission(), line.GetEvent() ),
+ m_maxOrderNumber( line.GetConversationPosition() ),
+ m_dialogList( NULL ),
+ m_currentLine( NULL )
+{
+ line.AddToDialogList( reinterpret_cast<SelectableDialog**>(&m_dialogList) );
+}
+
+//==============================================================================
+// Conversation::~Conversation
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Conversation::~Conversation()
+{
+}
+
+//=============================================================================
+// Conversation::LineFits
+//=============================================================================
+// Description: Determine whether the given line matches this conversation
+//
+// Parameters: line - dialog line to test
+//
+// Return: true if it fits in this conversation, false otherwise
+//
+//=============================================================================
+bool Conversation::LineFits( DialogLine& line )
+{
+ bool matches;
+ DialogLine* existingLine = m_dialogList;
+
+ rAssert( existingLine != NULL );
+
+ //
+ // If the new line matches one dialog line in this conversation, it should
+ // match them all
+ //
+ matches = ( line.GetLevel() == existingLine->GetLevel() )
+ && ( line.GetMission() == existingLine->GetMission() )
+ && ( line.GetEvent() == existingLine->GetEvent() )
+ && ( line.GetConversationName() == existingLine->GetConversationName() );
+
+#ifdef RAD_DEBUG
+ if( matches )
+ {
+ rAssert( line.GetConversationPosition() != existingLine->GetConversationPosition() );
+ }
+#endif
+
+ return( matches );
+}
+
+//=============================================================================
+// Conversation::AddToConversation
+//=============================================================================
+// Description: Add the given dialog line to this conversation
+//
+// Parameters: line - line to be added
+//
+// Return: void
+//
+//=============================================================================
+void Conversation::AddToConversation( DialogLine& line )
+{
+ int position = line.GetConversationPosition();
+ DialogLine* listObj;
+ DialogLine* nextListObj;
+
+ if( ( m_dialogList == NULL )
+ || ( position < m_dialogList->GetConversationPosition() ) )
+ {
+ line.AddToDialogList( reinterpret_cast<SelectableDialog**>(&m_dialogList) );
+ }
+ else
+ {
+ listObj = m_dialogList;
+ // ARGH! Stinky downcast! I hate this!
+ nextListObj = reinterpret_cast<DialogLine*>(listObj->GetNextInList());
+ while( ( nextListObj != NULL )
+ && ( nextListObj->GetConversationPosition() < position ) )
+ {
+ listObj = nextListObj;
+ nextListObj = reinterpret_cast<DialogLine*>(listObj->GetNextInList());
+ }
+
+ line.AddToDialogList( listObj );
+ }
+}
+
+//=============================================================================
+// Conversation::IsComplete
+//=============================================================================
+// Description: Returns true if we have a set of consecutively-numbered
+// dialog lines, starting from 1.
+//
+// Parameters: None
+//
+// Return: true if conversation valid and complete, false otherwise
+//
+//=============================================================================
+bool Conversation::IsComplete()
+{
+ bool complete = true;
+ int nextPosition = 1;
+ DialogLine* nextDialogLine = m_dialogList;
+
+ while( nextDialogLine != NULL )
+ {
+ if( nextDialogLine->GetConversationPosition() != nextPosition )
+ {
+ complete = false;
+ break;
+ }
+
+ // Stinky downcast!
+ nextDialogLine = reinterpret_cast<DialogLine*>(nextDialogLine->GetNextInList());
+ ++nextPosition;
+ }
+
+ return( complete );
+}
+
+//=============================================================================
+// Conversation::PlayLine
+//=============================================================================
+// Description: Comment
+//
+// Parameters: lineIndex - index for the DialogLine we want to play
+// player - player to play it with
+// callback - callback to call when we're done
+//
+// Return: void
+//
+//=============================================================================
+void Conversation::PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ DialogLine* currentDialog = findDialogLineByIndex( lineIndex );
+
+ currentDialog->PlayLine( 0, player, callback );
+}
+
+void Conversation::QueueLine( unsigned int lineIndex, SimpsonsSoundPlayer& player )
+{
+ m_currentLine = findDialogLineByIndex( lineIndex );
+
+ m_currentLine->QueueLine( 0, player );
+}
+
+void Conversation::PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ m_currentLine->PlayQueuedLine( player, callback );
+}
+
+//=============================================================================
+// Conversation::GetNumDialogLines
+//=============================================================================
+// Description: Returns the number of DialogLine objects associated with
+// this conversation.
+//
+// Parameters: None
+//
+// Return: number of dialog lines
+//
+//=============================================================================
+unsigned int Conversation::GetNumDialogLines() const
+{
+ unsigned int lineCount = 0;
+ DialogLine* lineObj = m_dialogList;
+
+ while( lineObj != NULL )
+ {
+ ++lineCount;
+ lineObj = static_cast<DialogLine*>(lineObj->GetNextInList());
+ }
+
+ return( lineCount );
+}
+
+//=============================================================================
+// Conversation::UsesCharacter
+//=============================================================================
+// Description: Indicate if any of our dialog lines are from the given
+// character
+//
+// Parameters: characterObj - character to match
+//
+// Return: true if >=1 dialog line comes from the given character,
+// false otherwise
+//
+//=============================================================================
+bool Conversation::UsesCharacter( tUID characterUID )
+{
+ bool match = false;
+ DialogLine* lineObj = m_dialogList;
+
+ while( lineObj != NULL )
+ {
+ if( lineObj->UsesCharacter( characterUID ) )
+ {
+ match = true;
+ break;
+ }
+ lineObj = static_cast<DialogLine*>(lineObj->GetNextInList());
+ }
+
+ return( match );
+}
+
+//=============================================================================
+// Conversation::IsVillainLine
+//=============================================================================
+// Description: Indicate if this is a villain one-liner (answer: no)
+//
+// Parameters: None
+//
+// Return: false
+//
+//=============================================================================
+bool Conversation::IsVillainLine()
+{
+ //
+ // No conversations are villain one-liners
+ //
+ return( false );
+}
+
+//=============================================================================
+// Conversation::GetDialogLineCharacterUID
+//=============================================================================
+// Description: Indicate which character is speaking with the given line
+//
+// Parameters: lineNum - indicates which dialog line we want the UID for
+//
+// Return: tUID of character associated with dialog line
+//
+//=============================================================================
+tUID Conversation::GetDialogLineCharacterUID( unsigned int lineNum )
+{
+ unsigned int lineCount = lineNum;
+ DialogLine* lineObj = m_dialogList;
+
+ rAssert( lineNum > 0 );
+
+ while( ( --lineCount > 0 ) && ( lineObj != NULL ) )
+ {
+ lineObj = static_cast<DialogLine*>(lineObj->GetNextInList());
+ }
+
+ if( lineObj != NULL )
+ {
+ return( lineObj->GetCharacterUID() );
+ }
+ else
+ {
+ return( 0 );
+ }
+}
+
+//=============================================================================
+// Conversation::GetConversationName
+//=============================================================================
+// Description: I don't really expect this to be used, but that's no reason
+// to return garbage here. Find the name stored with one of the
+// individual lines.
+//
+// Parameters: None
+//
+// Return: radKey32 representing conversation name field
+//
+//=============================================================================
+radKey32 Conversation::GetConversationName()
+{
+ rAssert( m_dialogList != NULL );
+
+ return( m_dialogList->GetConversationName() );
+}
+
+//=============================================================================
+// Conversation::AddMatchingDialog
+//=============================================================================
+// Description: Remove self from the given list and add ourself and the new
+// dialog back in within a DialogSelectionGroup object
+//
+// Parameters: newDialog - new dialog with same characteristics as self
+// list - list to add to
+//
+// Return: void
+//
+//=============================================================================
+void Conversation::AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ DialogSelectionGroup* group = new DialogSelectionGroup( *this, newDialog );
+
+ rAssert( group != NULL );
+
+ list.remove( this );
+ list.push_back( group );
+
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//=============================================================================
+// Conversation::PrintDialogLineNames
+//=============================================================================
+// Description: For debugging. Print the names of the dialog lines.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Conversation::PrintDialogLineNames()
+{
+#ifndef RAD_RELEASE
+ DialogLine* currentDialog = m_dialogList;
+
+ rDebugString( "Conversation contents:\n" );
+ while( currentDialog != NULL )
+ {
+ currentDialog->PrintResourceName();
+ currentDialog = static_cast<DialogLine*>(currentDialog->GetNextInList());
+ }
+#endif
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+DialogLine* Conversation::findDialogLineByIndex( unsigned int lineIndex )
+{
+ unsigned int lineCount = lineIndex;
+ DialogLine* currentDialog = m_dialogList;
+
+ rAssert( currentDialog != NULL );
+
+ while( lineCount > 0 )
+ {
+ currentDialog = static_cast<DialogLine*>(currentDialog->GetNextInList());
+ rAssert( currentDialog != NULL );
+ --lineCount;
+ }
+
+ return( currentDialog );
+} \ No newline at end of file
diff --git a/game/code/sound/dialog/conversation.h b/game/code/sound/dialog/conversation.h
new file mode 100644
index 0000000..29459f0
--- /dev/null
+++ b/game/code/sound/dialog/conversation.h
@@ -0,0 +1,79 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: conversation.h
+//
+// Description: Conversation objects aggregate groups of DialogLine objects
+// which are intended to be played without interruption, like
+// a conversation. Hence the name.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef CONVERSATION_H
+#define CONVERSATION_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/dialog/playabledialog.h>
+
+//========================================
+// Forward References
+//========================================
+class DialogLine;
+
+//=============================================================================
+//
+// Synopsis: Conversation
+//
+//=============================================================================
+
+class Conversation : public PlayableDialog
+{
+ public:
+ Conversation( DialogLine& line );
+ virtual ~Conversation();
+
+ bool LineFits( DialogLine& line );
+ void AddToConversation( DialogLine& line );
+ bool IsComplete();
+
+ //
+ // Pure virtual functions from SelectableDialog
+ //
+ void PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+ void QueueLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player );
+ void PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+
+ unsigned int GetNumDialogLines() const;
+ bool UsesCharacter( tUID characterUID );
+ tUID GetDialogLineCharacterUID( unsigned int lineNum );
+ radKey32 GetConversationName();
+ bool IsVillainLine();
+
+ void AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list );
+
+ void PrintDialogLineNames();
+
+ private:
+ //Prevent wasteful constructor creation.
+ Conversation();
+ Conversation( const Conversation& original );
+ Conversation& operator=( const Conversation& rhs );
+
+ DialogLine* findDialogLineByIndex( unsigned int lineIndex );
+
+ unsigned int m_maxOrderNumber;
+ DialogLine* m_dialogList;
+ DialogLine* m_currentLine;
+};
+
+
+#endif // CONVERSATION_H
+
diff --git a/game/code/sound/dialog/conversationmatcher.cpp b/game/code/sound/dialog/conversationmatcher.cpp
new file mode 100644
index 0000000..db49580
--- /dev/null
+++ b/game/code/sound/dialog/conversationmatcher.cpp
@@ -0,0 +1,237 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: conversationmatcher.cpp
+//
+// Description: Takes sound resource names which form individual dialog lines
+// and groups them into the intended conversations.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/conversationmatcher.h>
+
+#include <sound/dialog/conversation.h>
+#include <sound/dialog/dialogline.h>
+#include <sound/dialog/dialoglist.h>
+
+#include <memory/srrmemory.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// ConversationMatcher::ConversationMatcher
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+ConversationMatcher::ConversationMatcher() :
+ m_conversationList( NULL )
+{
+}
+
+//==============================================================================
+// ConversationMatcher::~ConversationMatcher
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+ConversationMatcher::~ConversationMatcher()
+{
+}
+
+//=============================================================================
+// ConversationMatcher::AddNewLine
+//=============================================================================
+// Description: Make a new DialogLine object for the resource and add it to
+// the list of conversations to be grouped together.
+//
+// Parameters: resource - conversation sound resource
+//
+// Return: void
+//
+//=============================================================================
+void ConversationMatcher::AddNewLine( IDaSoundResource* resource )
+{
+ DialogLine* line;
+ Conversation* conversationObj;
+ Conversation* newConversation;
+
+ //
+ // Create a DialogLine object
+ //
+#ifdef RAD_GAMECUBE
+ line = new( GMA_GC_VMM ) DialogLine( resource );
+#else
+ line = new( GMA_PERSISTENT ) DialogLine( resource );
+#endif
+ rAssert( line != NULL );
+
+ //
+ // Work through the conversation list, trying to find an existing
+ // conversation that matches this line
+ //
+ conversationObj = m_conversationList;
+
+ while( conversationObj != NULL )
+ {
+ if( conversationObj->LineFits( *line ) )
+ {
+ conversationObj->AddToConversation( *line );
+ break;
+ }
+
+ //
+ // Argh! This must go. Stinky downcast.
+ //
+ conversationObj = reinterpret_cast<Conversation*>(conversationObj->GetNextInList());
+ }
+
+ if( conversationObj == NULL )
+ {
+ //
+ // No conversation matched, create a new conversation
+ //
+#ifdef RAD_GAMECUBE
+ newConversation = new( GMA_GC_VMM ) Conversation( *line );
+#else
+ newConversation = new( GMA_PERSISTENT ) Conversation( *line );
+#endif
+ newConversation->AddToDialogList( reinterpret_cast<SelectableDialog**>(&m_conversationList) );
+ }
+}
+
+//=============================================================================
+// ConversationMatcher::AreAllConversationsComplete
+//=============================================================================
+// Description: Determine whether all the conversations have been filled out.
+// Sanity check function.
+//
+// Parameters: None
+//
+// Return: true if all conversations complete, false otherwise
+//
+//=============================================================================
+bool ConversationMatcher::AreAllConversationsComplete()
+{
+ Conversation* current;
+ bool allComplete = true;
+
+ current = m_conversationList;
+ while( current != NULL )
+ {
+ if( !(current->IsComplete()) )
+ {
+ allComplete = false;
+ current->PrintDialogLineNames();
+
+ //
+ // We know we're incomplete at this point, but keep going so that
+ // we get everything printed out in one go.
+ //
+ }
+
+ current = reinterpret_cast<Conversation*>(current->GetNextInList());
+ }
+
+ return( allComplete );
+}
+
+//=============================================================================
+// ConversationMatcher::AddConversationsToList
+//=============================================================================
+// Description: Transfer all of our conversations from our own list to the
+// list given that match the specification
+//
+// Parameters: level - level of conversations for list (NO_LEVEL if N/A)
+// mission - mission of conversations for list (NO_MISSION if N/A)
+// list - list to add to
+//
+// Return: void
+//
+//=============================================================================
+void ConversationMatcher::AddConversationsToList( unsigned int level,
+ unsigned int mission,
+ SelectableDialogList& list )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ Conversation* conversationObj;
+ Conversation* nextConversation = NULL;
+ Conversation* temp;
+
+ //
+ // First, deal with the head of the list as a special case. This can
+ // probably be cleaned up
+ //
+ while( ( m_conversationList != NULL )
+ && ( m_conversationList->GetLevel() == level )
+ && ( m_conversationList->GetMission() == mission ) )
+ {
+ temp = m_conversationList;
+ m_conversationList = reinterpret_cast<Conversation*>( m_conversationList->GetNextInList() );
+ list.push_back( temp );
+ }
+
+ //
+ // Now, the first one in the list, if it exists, doesn't match the spec
+ //
+ conversationObj = m_conversationList;
+ if( conversationObj != NULL )
+ {
+ nextConversation = reinterpret_cast<Conversation*>( conversationObj->GetNextInList() );
+ }
+
+ while( ( conversationObj != NULL )
+ && ( nextConversation != NULL ) )
+ {
+ if( ( nextConversation->GetLevel() == level )
+ && ( nextConversation->GetMission() == mission ) )
+ {
+ //
+ // Remove conversation from our list and add it to the one supplied
+ //
+ conversationObj->RemoveNextFromList();
+ list.push_back( nextConversation );
+ }
+ else
+ {
+ conversationObj = nextConversation;
+ }
+
+ nextConversation = reinterpret_cast<Conversation*>( conversationObj->GetNextInList() );
+ }
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/dialog/conversationmatcher.h b/game/code/sound/dialog/conversationmatcher.h
new file mode 100644
index 0000000..18e9b15
--- /dev/null
+++ b/game/code/sound/dialog/conversationmatcher.h
@@ -0,0 +1,57 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: conversationmatcher.h
+//
+// Description: Takes sound resource names which form individual dialog lines
+// and groups them into the intended conversations.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef CONVERSATIONMATCHER_H
+#define CONVERSATIONMATCHER_H
+
+//========================================
+// Nested Includes
+//========================================
+//
+// I'd like a forward declaration, but it's a little complicated with
+// STL lists
+//
+#include <sound/dialog/selectabledialoglist.h>
+
+//========================================
+// Forward References
+//========================================
+struct IDaSoundResource;
+class Conversation;
+
+//=============================================================================
+//
+// Synopsis: ConversationMatcher
+//
+//=============================================================================
+
+class ConversationMatcher
+{
+ public:
+ ConversationMatcher();
+ virtual ~ConversationMatcher();
+
+ void AddNewLine( IDaSoundResource* resource );
+ bool AreAllConversationsComplete();
+ void AddConversationsToList( unsigned int level, unsigned int mission, SelectableDialogList& list );
+
+ private:
+ //Prevent wasteful constructor creation.
+ ConversationMatcher( const ConversationMatcher& original );
+ ConversationMatcher& operator=( const ConversationMatcher& rhs );
+
+ Conversation* m_conversationList;
+};
+
+
+#endif // CONVERSATIONMATCHER_H
+
diff --git a/game/code/sound/dialog/dialogcoordinator.cpp b/game/code/sound/dialog/dialogcoordinator.cpp
new file mode 100644
index 0000000..ba6e269
--- /dev/null
+++ b/game/code/sound/dialog/dialogcoordinator.cpp
@@ -0,0 +1,971 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogcoordinator.cpp
+//
+// Description: The main interface class for the dialog system. It listens
+// for game events and cues the appropriate line of dialog.
+// Objects representing lines or sets of lines are obtained
+// from the SpeechCoordinator, and are passed to the
+// DialogPriorityQueue, which determines when playback is
+// ready to begin.
+//
+// History: 30/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogcoordinator.h>
+
+#include <sound/dialog/dialoglist.h>
+#include <sound/dialog/dialogpriorityqueue.h>
+#include <sound/dialog/dialogline.h>
+
+#include <memory/srrmemory.h>
+#include <events/eventmanager.h>
+#include <events/eventdata.h>
+#include <worldsim/avatarmanager.h>
+#include <worldsim/vehiclecentral.h>
+#include <worldsim/character/charactermanager.h>
+#include <mission/objectives/missionobjective.h>
+#include <mission/conditions/missioncondition.h>
+#include <gameflow/gameflow.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+struct TutorialConversationData
+{
+ const char* convName;
+ radKey32 convNameKey;
+ bool platformSpecificLine;
+};
+
+//
+// IMPORTANT: needs to line up with TutorialMode enumeration in tutorialmode.h.
+// Not ideal, but we're three days from alpha.
+//
+TutorialConversationData tutorialConvNames[] =
+{
+ { "camera", 0, false },
+ { "bonus", 0, false },
+ { "start", 0, true },
+ { "drive", 0, true },
+ { "traffic", 0, false },
+ { "gag", 0, false },
+ { "race", 0, false },
+ { "card", 0, false },
+ { "coin", 0, false },
+ { "reward", 0, true },
+ { "outcar", 0, true },
+ { "break", 0, true },
+ { "broken", 0, false },
+ { "interior", 0, true },
+ { "unknown", 0, false },
+ { "damaged", 0, false },
+ { "Gil", 0, false },
+ { "wrench", 0, false },
+ { "incar", 0, true },
+ { "unknown", 0, false },
+ { "timetrial", 0, false }
+};
+
+static unsigned int tutorialTableLength = sizeof( tutorialConvNames ) / sizeof( TutorialConversationData );
+
+static tUID genericTrafficUIDs[] =
+{
+ tEntity::MakeUID( "traffic1" ),
+ tEntity::MakeUID( "traffic2" ),
+ tEntity::MakeUID( "traffic3" ),
+ tEntity::MakeUID( "traffic4" )
+};
+
+static radKey32 s_failDialog1 = ::radMakeKey32( "fail1" );
+static radKey32 s_failDialog2 = ::radMakeKey32( "fail2" );
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogCoordinator::DialogCoordinator
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogCoordinator::DialogCoordinator( IRadNameSpace* namespaceObj ) :
+ m_dialogNamespace( namespaceObj ),
+ m_dialogList( new( GMA_PERSISTENT ) DialogList() ),
+ m_playbackQueue( new( GMA_PERSISTENT ) DialogPriorityQueue() ),
+ m_dialogOn( true ),
+ m_phoneBoothRequestMade( false )
+{
+ unsigned int i;
+ char buffer[50];
+
+ rAssert( m_dialogList != NULL );
+ rAssert( m_dialogNamespace != NULL );
+ rAssert( m_playbackQueue != NULL );
+
+ //
+ // Initialize the tutorial dialog table
+ //
+ for( i = 0; i < tutorialTableLength; i++ )
+ {
+ if( tutorialConvNames[i].platformSpecificLine )
+ {
+#ifdef RAD_PS2
+ sprintf( buffer, "%sps2", tutorialConvNames[i].convName );
+#elif RAD_GAMECUBE
+ sprintf( buffer, "%sngc", tutorialConvNames[i].convName );
+#else
+ sprintf( buffer, "%sxbx", tutorialConvNames[i].convName );
+#endif
+
+ tutorialConvNames[i].convNameKey = ::radMakeKey32( buffer );
+ }
+ else
+ {
+ tutorialConvNames[i].convNameKey = ::radMakeKey32( tutorialConvNames[i].convName );
+ }
+ }
+}
+
+//==============================================================================
+// DialogCoordinator::~DialogCoordinator
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogCoordinator::~DialogCoordinator()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// DialogCoordinator::HandleEvent
+//=============================================================================
+// Description: Pass the event to the DialogList, which will find a suitable
+// SelectableDialog for us, and give it to the priority queue
+// for playback.
+//
+// Parameters: id - event ID
+// pEventData - user data, unused here
+//
+// Return: void
+//
+//=============================================================================
+void DialogCoordinator::HandleEvent( EventEnum id, void* pEventData )
+{
+ unsigned int tutorialIndex;
+ SelectableDialog* dialog;
+ DialogEventData* eventData;
+ DialogEventData raceEventData;
+ bool dialogWasPlaying;
+ AvatarManager* avatarMgr;
+ Vehicle* vehicleEventData = NULL;
+ Vehicle* minigameVehicle;
+ Vehicle* avatarVehicle;
+ tUID charUID1 = 0;
+ tUID charUID2 = 0;
+ int i;
+ int numPlayers;
+ const char* charName;
+ rmt::Vector dlgPosition;
+ rmt::Vector* dlgPositionPtr = NULL;
+ radKey32 convName = 0;
+ Character* character1 = NULL;
+ Character* character2 = NULL;
+ Avatar* playerAvatar = GetAvatarManager()->GetAvatarForPlayer( 0 );
+ bool overridePositional = false;
+ int coinToss;
+
+ if( GetGameplayManager() != NULL )
+ {
+ //
+ // Filter out the crap we don't want in supersprint
+ //
+ if( GetGameplayManager()->IsSuperSprint()
+ && ( id != EVENT_BIG_VEHICLE_CRASH )
+ && ( id != EVENT_BIG_BOOM_SOUND )
+ && ( id != EVENT_DEATH_VOLUME_SOUND ) )
+ {
+ return;
+ }
+
+ //
+ // Filter out the crap we don't want in race missions
+ //
+ if( ( GetGameplayManager()->GetCurrentMission() != NULL )
+ && ( GetGameplayManager()->GetCurrentMission()->IsRaceMission() ) )
+ {
+ if( id == EVENT_MISSION_FAILURE )
+ {
+ const char* modelName;
+
+ //
+ // Hack!
+ // Turn this into a Patty/walker failure conversation.
+ // Randomly choose between fail1 and fail2.
+ //
+ rAssert( playerAvatar != NULL );
+ modelName = GetCharacterManager()->GetModelName( playerAvatar->GetCharacter() );
+ raceEventData.charUID1 = tEntity::MakeUID( modelName );
+ raceEventData.charUID2 = tEntity::MakeUID( "patty" );
+ if( rand() % 2 == 0 )
+ {
+ raceEventData.dialogName = s_failDialog1;
+ }
+ else
+ {
+ raceEventData.dialogName = s_failDialog2;
+ }
+
+ pEventData = &raceEventData;
+ id = EVENT_IN_GAMEPLAY_CONVERSATION;
+ }
+ else if( id == EVENT_MISSION_BRIEFING_ACCEPTED )
+ {
+ return;
+ }
+ }
+ }
+
+ //**********************************************************
+ //
+ // TODO: this is becoming a bit of an if-statement mess. We're getting close
+ // to alpha, so I'm not changing it now. In the sequel, pEventData should
+ // point to a parameter object which can be created in a variety of ways with
+ // a variety of data, and you should be able to ask it for a tUID or
+ // something when it gets here.
+ //
+ //**********************************************************
+
+ //
+ // Hack!!
+ //
+ if( id == EVENT_PHONE_BOOTH_RIDE_REQUEST )
+ {
+ m_phoneBoothRequestMade = true;
+ }
+ else if( ( id == EVENT_PHONE_BOOTH_NEW_VEHICLE_SELECTED )
+ || ( id == EVENT_PHONE_BOOTH_OLD_VEHICLE_RESELECTED ) )
+ {
+ if( !m_phoneBoothRequestMade )
+ {
+ //
+ // This isn't a phone booth car request, it's just a regular
+ // vehicle load. Throw the event out.
+ //
+ return;
+ }
+ else
+ {
+ m_phoneBoothRequestMade = false;
+ }
+ }
+ else if( id == EVENT_PHONE_BOOTH_CANCEL_RIDEREPLY_LINE )
+ {
+ m_phoneBoothRequestMade = false;
+ return;
+ }
+ else
+ {
+ //
+ // We expect those requests to be made back-to-back. Anything else,
+ // and we're done with the phone booth.
+ //
+ m_phoneBoothRequestMade = false;
+ }
+
+ //
+ // Filter out the reverse burnouts we don't want
+ //
+ if( id == EVENT_BURNOUT )
+ {
+ //
+ // Need to check the mBrake value, calling IsInReverse() or
+ // IsMovingBackward() filters out the small velocities we're
+ // getting at the start of the burnout
+ //
+ if( playerAvatar->IsInCar()
+ && ( playerAvatar->GetVehicle()->mBrake > 0.0f ) )
+ {
+ return;
+ }
+ }
+
+ //
+ // Turn wasp zaps into hit by car to play HitByC dialog lines
+ //
+ if( id == EVENT_WASP_BULLET_HIT_CHARACTER_STYLIZED_VIOLENCE_FOLLOWS )
+ {
+ id = EVENT_PLAYER_CAR_HIT_NPC;
+ overridePositional = true;
+ }
+
+ if( id == EVENT_DIALOG_SHUTUP )
+ {
+ m_playbackQueue->StopAllDialog();
+ }
+ else if( id == EVENT_CONVERSATION_SKIP )
+ {
+ //
+ // Stop anything that might be playing
+ //
+ dialogWasPlaying = m_playbackQueue->StopAllDialog();
+ if( dialogWasPlaying )
+ {
+ GetEventManager()->TriggerEvent( EVENT_CONVERSATION_DONE );
+ }
+ }
+ else if( m_dialogOn )
+ {
+ if( id == EVENT_TUTORIAL_DIALOG_PLAY )
+ {
+ tutorialIndex = *(reinterpret_cast<unsigned int*>( pEventData ));
+ if( tutorialIndex < tutorialTableLength )
+ {
+ //
+ // It's always Bart. Specify him by UID (his Character
+ // object isn't loaded for these)
+ //
+ character1 = NULL;
+ character2 = NULL;
+ charUID1 = tEntity::MakeUID( "bart" );
+ charUID2 = tEntity::MakeUID( "homer" );
+ convName = tutorialConvNames[tutorialIndex].convNameKey;
+ }
+ else
+ {
+ //
+ // No line exists here, play nothing
+ //
+ rDebugString( "No tutorial dialog exists for event data\n" );
+ return;
+ }
+ }
+ else if( ( id == EVENT_CONVERSATION_INIT_DIALOG )
+ || ( id == EVENT_IN_GAMEPLAY_CONVERSATION ) )
+ {
+ //
+ // Get characters to match
+ //
+ eventData = static_cast<DialogEventData*>( pEventData );
+ character1 = eventData->char1;
+ character2 = eventData->char2;
+ charUID1 = eventData->charUID1;
+ charUID2 = eventData->charUID2;
+
+ //
+ // Assumption: if eventData->dialogNameis zero,
+ // that's an indication that no name is to be matched
+ //
+ convName = eventData->dialogName;
+ }
+ else if( id == EVENT_TRAFFIC_IMPEDED )
+ {
+ //
+ // Almost-final hack!
+ //
+ // Special case, of course. For this one, toss a coin between
+ // playing the avatar line and the traffic line. For the
+ // traffic, play one of the four generic vehicles.
+ //
+ if( playerAvatar->IsInCar() )
+ {
+ coinToss = rand() % 2;
+ }
+ else
+ {
+ coinToss = 1;
+ }
+
+ if( coinToss == 0 )
+ {
+ character1 = playerAvatar->GetCharacter();
+ overridePositional = true;
+ }
+ else
+ {
+ coinToss = rand() % 4;
+ charUID1 = genericTrafficUIDs[coinToss];
+ vehicleEventData = static_cast<Vehicle*>( pEventData );
+ }
+ }
+ else if( ( pEventData != NULL )
+ && ( id != EVENT_LOCATOR + LocatorEvent::BOUNCEPAD ) )
+ {
+ if( GetGameplayManager()->IsSuperSprint() )
+ {
+ minigameVehicle = static_cast<Vehicle*>(pEventData);
+
+ avatarMgr = GetAvatarManager();
+ numPlayers = GetGameplayManager()->GetNumPlayers();
+ for( i = 0; i < numPlayers; i++ )
+ {
+ playerAvatar = avatarMgr->GetAvatarForPlayer( i );
+ if( playerAvatar->GetVehicle() == minigameVehicle )
+ {
+ character1 = playerAvatar->GetCharacter();
+ break;
+ }
+ }
+
+ if( i >= numPlayers )
+ {
+ //
+ // Not the player, so use the driver name
+ //
+ charUID1 = tEntity::MakeUID( minigameVehicle->mDriverName );
+ }
+ }
+ else if( id == EVENT_WRONG_SIDE_DUMBASS )
+ {
+ //
+ // Stinky special case. pEventData is actually a Vehicle in this case, since
+ // we can't use the character, since drivers have different names
+ //
+ vehicleEventData = static_cast<Vehicle*>(pEventData);
+ dialog = m_dialogList->FindDialogForEvent( id, NULL, NULL,
+ tEntity::MakeUID( vehicleEventData->mDriverName ), 0, convName, false );
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No driver dialog found for event %d\n", static_cast<int>( id ) );
+ }
+ else
+ {
+ m_playbackQueue->AddDialogToQueue( *dialog );
+ }
+
+ return;
+ }
+ else if( id == EVENT_DING_DONG )
+ {
+ //
+ // Yet Another Special Case. Doorbells play dialog for unloaded characters.
+ // We're getting a string with the character name
+ //
+ charName = static_cast<char*>(pEventData);
+ dialog = m_dialogList->FindDialogForEvent( id, NULL, NULL, tEntity::MakeUID( charName ), 0, 0, false );
+
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No doorbell dialog found for character %s\n", charName );
+ }
+ else
+ {
+ m_playbackQueue->AddDialogToQueue( *dialog );
+ }
+
+ return;
+ }
+ else if( id == EVENT_BIG_BOOM_SOUND )
+ {
+ Vehicle* blowedUpCar = static_cast<Vehicle*>(pEventData);
+
+ //
+ // Can't handle below because we can get thrown out of the car before the
+ // explosion.
+ //
+ if( playerAvatar->IsInCar() && ( blowedUpCar != playerAvatar->GetVehicle() ) )
+ {
+ return;
+ }
+
+ character1 = playerAvatar->GetCharacter();
+ rAssert( character1 != NULL );
+
+ //
+ // Play funny driver line
+ //
+ if( blowedUpCar->GetDriver() != NULL )
+ {
+ dialog = m_dialogList->FindDialogForEvent( id, NULL, NULL,
+ tEntity::MakeUID(blowedUpCar->mDriverName), 0, 0, false );
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No driver dialog found for event %d\n", static_cast<int>( id ) );
+ }
+ else
+ {
+ m_playbackQueue->AddDialogToQueue( *dialog );
+ }
+ }
+ }
+ else if( eventHasVehicleData( id )
+ || ( id == EVENT_MISSION_FAILURE )
+ || ( id == EVENT_HIT_BREAKABLE )
+ || ( id == EVENT_DEATH_VOLUME_SOUND )
+ || ( id == EVENT_CARD_COLLECTED ) )
+ {
+ if( eventHasVehicleData( id )
+ && ( !(playerAvatar->IsInCar())
+ || ( static_cast<Vehicle*>(pEventData) != playerAvatar->GetVehicle() ) ) )
+ {
+ //
+ // We're only interested in our own vehicle
+ //
+ return;
+ }
+
+ //
+ // Another stinky special case. Event data is used in the call
+ // to queueVillainDialog below.
+ //
+ character1 = playerAvatar->GetCharacter();
+ rAssert( character1 != NULL );
+ }
+ else
+ {
+ //
+ // We expect a Character* as the event data,
+ //
+ character1 = static_cast<Character*>( pEventData );
+ }
+ }
+ else
+ {
+ //
+ // If nothing is supplied as event data, we assume that the character
+ // referred to is avatar 0
+ //
+ character1 = playerAvatar->GetCharacter();
+ rAssert( character1 != NULL );
+ }
+
+ //
+ // Check for events where we want to queue up a villain line before the walker/driver
+ //
+ queueVillainDialog( id, pEventData );
+
+ //
+ // Driver lines
+ //
+ if( ( playerAvatar != NULL )
+ && playerAvatar->IsInCar() )
+ {
+ avatarVehicle = playerAvatar->GetVehicle();
+ if( ( avatarVehicle->mpDriver != NULL ) && ( avatarVehicle->mpDriver != character1 ) )
+ {
+ tUID driverUID;
+
+ //
+ // Character is in car and not driving. Trigger driver dialog
+ // as well as character dialog below
+ //
+ driverUID = tEntity::MakeUID(avatarVehicle->mDriverName);
+
+ dialog = m_dialogList->FindDialogForEvent( id, NULL, NULL, driverUID, charUID2, convName, false );
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No driver dialog found for event %d\n", static_cast<int>( id ) );
+ }
+ else
+ {
+ m_playbackQueue->AddDialogToQueue( *dialog );
+ }
+ }
+ }
+
+ dialog = m_dialogList->FindDialogForEvent( id, character1, character2, charUID1, charUID2, convName, false );
+
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No dialog found for event %d\n", static_cast<int>( id ) );
+ }
+ else
+ {
+ if( playLinePositionally( id ) && !overridePositional )
+ {
+ if( character1 != NULL )
+ {
+ getCharacterPosition( character1, dlgPosition );
+ }
+ else
+ {
+ vehicleEventData->GetPosition( &dlgPosition );
+ }
+ dlgPositionPtr = &dlgPosition;
+ }
+ m_playbackQueue->AddDialogToQueue( *dialog, dlgPositionPtr );
+ }
+ }
+}
+
+//=============================================================================
+// DialogCoordinator::Initialize
+//=============================================================================
+// Description: Parse the namespace for dialog resources and register for
+// dialog-related events
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogCoordinator::Initialize()
+{
+ m_dialogList->OrganizeDialog( m_dialogNamespace );
+
+ registerDialogEvents();
+}
+
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogCoordinator::registerDialogEvents
+//=============================================================================
+// Description: Register as a listener for the dialog-related events with
+// the event manager.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogCoordinator::registerDialogEvents()
+{
+ unsigned int tableSize = DialogLine::GetEventTableSize();
+ unsigned int i;
+
+ for( i = 0; i < tableSize; i++ )
+ {
+ GetEventManager()->AddListener( this, DialogLine::GetEventTableEntry( i )->event );
+ }
+
+ GetEventManager()->AddListener( this, EVENT_CONVERSATION_SKIP );
+ GetEventManager()->AddListener( this, EVENT_TUTORIAL_DIALOG_PLAY );
+ GetEventManager()->AddListener( this, EVENT_DIALOG_SHUTUP );
+ GetEventManager()->AddListener( this, EVENT_WASP_BULLET_HIT_CHARACTER_STYLIZED_VIOLENCE_FOLLOWS );
+ GetEventManager()->AddListener( this, EVENT_PHONE_BOOTH_CANCEL_RIDEREPLY_LINE );
+}
+
+//=============================================================================
+// DialogCoordinator::queueVillainDialog
+//=============================================================================
+// Description: If this is a villain event, queue up some villain dialog
+//
+// Parameters: id - walker/driver event to be mapped to villain event
+// eventData - user data passed in with event
+//
+// Return: void
+//
+//=============================================================================
+void DialogCoordinator::queueVillainDialog( EventEnum id, void* eventData )
+{
+ EventEnum villainID = NUM_EVENTS; // Invalid placeholder value, shouldn't be used
+ Mission* currentMission;
+ MissionStage* currentStage;
+ MissionObjective* currentObjective;
+ MissionCondition* failureCondition;
+ Vehicle* eventCar;
+ Vehicle* AICar;
+ VehicleAI* AICarAI;
+ const char* villainName;
+ SelectableDialog* dialog;
+ GameplayManager* gameplayMgr;
+ rmt::Vector villainPosn;
+ rmt::Vector avatarPosn;
+ rmt::Vector diff;
+ bool noVillainLine = false;
+
+ if( GetGameFlow()->GetCurrentContext() == CONTEXT_FRONTEND )
+ {
+ //
+ // No villains in the FE
+ //
+ return;
+ }
+
+ gameplayMgr = GetGameplayManager();
+ if( ( gameplayMgr == NULL ) || ( gameplayMgr->IsSuperSprint() ) )
+ {
+ return;
+ }
+
+ //
+ // See if the given event ID is one that has corresponding villain dialog
+ //
+ switch( id )
+ {
+ case EVENT_TAIL_LOST_DIALOG:
+ villainID = EVENT_VILLAIN_TAIL_EVADE;
+ break;
+
+ case EVENT_MINOR_VEHICLE_CRASH:
+ case EVENT_BIG_VEHICLE_CRASH:
+ eventCar = static_cast<Vehicle*>(eventData);
+ if( ( eventCar != NULL )
+ && ( gameplayMgr->GetCurrentMission() != NULL )
+ && ( gameplayMgr->GetCurrentMission()->GetCurrentStage() != NULL )
+ && ( gameplayMgr->GetCurrentMission()->GetCurrentStage()->GetMainAIVehicleForThisStage() != NULL ) )
+ {
+ //
+ // Hack!
+ //
+ // Ideally, we should only play villain car crash dialogue if it's involved in the
+ // collision, apparently. Since we're trying to go final, just check to see if
+ // it's close by. Good enough.
+ //
+ AICar = gameplayMgr->GetCurrentMission()->GetCurrentStage()->GetMainAIVehicleForThisStage();
+ AICar->GetPosition( &villainPosn );
+ GetAvatarManager()->GetAvatarForPlayer( 0 )->GetPosition( avatarPosn );
+ diff.Sub( villainPosn, avatarPosn );
+ if( diff.MagnitudeSqr() > 75.0f )
+ {
+ noVillainLine = true;
+ }
+ else
+ {
+ //
+ // Dig through the GameplayManager stuff to find out who is
+ // attacking who
+ //
+ currentMission = gameplayMgr->GetCurrentMission();
+ rAssert( currentMission != NULL );
+ currentStage = currentMission->GetCurrentStage();
+ if (currentStage != NULL)
+ {
+ currentObjective = currentStage->GetObjective();
+ rAssert( currentObjective != NULL );
+
+ if( currentObjective->GetObjectiveType() == MissionObjective::OBJ_DESTROY )
+ {
+ villainID = EVENT_BIG_CRASH;
+ }
+ else
+ {
+ villainID = EVENT_VILLAIN_CAR_HIT_PLAYER;
+ }
+ }
+ else
+ {
+ noVillainLine = true;
+ }
+ }
+ }
+ else
+ {
+ noVillainLine = true;
+ }
+ break;
+
+ case EVENT_MISSION_FAILURE:
+ failureCondition = static_cast<MissionCondition*>(eventData);
+
+ //
+ // We only play villain dialog on mission failure
+ // when the player blew a tail mission
+ //
+ if( failureCondition->GetType() == MissionCondition::COND_FOLLOW_DISTANCE )
+ {
+ villainID = EVENT_TAIL_LOST_DIALOG;
+ }
+ else if( failureCondition->IsChaseCondition() )
+ {
+ villainID = EVENT_MISSION_FAILURE;
+ }
+ else
+ {
+ //
+ // No villain involved
+ //
+ noVillainLine = true;
+ }
+ break;
+
+ case EVENT_MISSION_SUCCESS_DIALOG:
+ currentMission = gameplayMgr->GetCurrentMission();
+ rAssert( currentMission != NULL );
+ currentStage = currentMission->GetCurrentStage();
+ if( currentStage != NULL )
+ {
+ currentObjective = currentStage->GetObjective();
+ rAssert( currentObjective != NULL );
+
+ if( currentObjective->GetObjectiveType() == MissionObjective::OBJ_DESTROY )
+ {
+ villainID = EVENT_MISSION_SUCCESS_DIALOG;
+ }
+ else
+ {
+ noVillainLine = true;
+ }
+ }
+ else
+ {
+ noVillainLine = true;
+ }
+ break;
+
+ default:
+ //
+ // No villain line needed for this type of event
+ //
+ noVillainLine = true;
+ break;
+ }
+
+ if( noVillainLine )
+ {
+ return;
+ }
+
+ //
+ // Find out who the driver of the AI vehicle is and play the line
+ // if the dialog exists
+ //
+ // AICar = gameplayMgr->GetVehicleInSlot( GameplayManager::eAICar );
+
+ //Chuck: Esan use this method for getting the mainAI for a stage. It should work
+
+ AICar = gameplayMgr->GetCurrentMission()->GetCurrentStage()->GetMainAIVehicleForThisStage();
+
+ if( AICar != NULL )
+ {
+ if( ( id != EVENT_MISSION_FAILURE )
+ && ( id != EVENT_MISSION_SUCCESS_DIALOG ) )
+ {
+ // HACK:
+ // [Dusit Matthew Eakkachaichanvet: July 3rd, 2003]
+ // When a vehicle is destroyed and we ask for the AI, well,
+ // it wont' find that vehicle in the database... So.. we have some
+ // possible REAL fixes:
+ // - When a car is destroyed, I should send you an event and you should remember the new husk (or lack thereof).
+ // For this particular dialogue it doesn't matter. But y'know... maybe there are other bugs associated with this.
+ // - We check it here. I would prefer we STILL play the sound, but it's really your call.
+ if( !AICar->mVehicleDestroyed )
+ {
+ AICarAI = GetVehicleCentral()->GetVehicleAI( AICar );
+
+ // At the end of the mission, we don't seem to have AI anymore...
+ if( ( AICarAI == NULL )
+ || ( AICarAI->GetState() == VehicleAI::STATE_WAITING ) )
+ {
+ //
+ // Don't play dialogue for inactive AI vehicles
+ //
+ return;
+ }
+ }
+ }
+ villainName = AICar->GetDriverName();
+ rAssert( villainName != NULL );
+
+ //
+ // If the villain isn't there, then we're probably in a race mission or something
+ // where it isn't loaded
+ //
+ if( villainName != NULL )
+ {
+ dialog = m_dialogList->FindDialogForEvent( villainID, NULL, NULL, tEntity::MakeUID( villainName ), 0, 0, true );
+
+ if( dialog == NULL )
+ {
+ rDebugPrintf( "No dialog found for villain event %d\n", static_cast<int>( villainID ) );
+ }
+ else
+ {
+ m_playbackQueue->AddDialogToQueue( *dialog );
+ }
+ }
+ }
+}
+
+//=============================================================================
+// DialogCoordinator::playLinePositionally
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( EventEnum id )
+//
+// Return: bool
+//
+//=============================================================================
+bool DialogCoordinator::playLinePositionally( EventEnum id )
+{
+ return( ( id == EVENT_KICK_NPC_SOUND )
+ || ( id == EVENT_PEDESTRIAN_DODGE )
+ || ( id == EVENT_PLAYER_CAR_HIT_NPC )
+ || ( id == EVENT_TRAFFIC_IMPEDED ) );
+}
+
+//=============================================================================
+// DialogCoordinator::getCharacterPosition
+//=============================================================================
+// Description: Comment
+//
+// Parameters: thePed - character to get position for.
+//
+// Return: position
+//
+//=============================================================================
+void DialogCoordinator::getCharacterPosition( Character* thePed, rmt::Vector& posn )
+{
+ rAssert( thePed != NULL );
+
+ //
+ // Get position from the character
+ //
+ thePed->GetPosition( posn );
+}
+
+//=============================================================================
+// DialogCoordinator::eventHasVehicleData
+//=============================================================================
+// Description: Indicate whether the given event has a vehicle as a data
+// parameter (stinky void*'s)
+//
+// Parameters: id - event ID to check
+//
+// Return: true if vehicle parameter expected, false otherwise
+//
+//=============================================================================
+bool DialogCoordinator::eventHasVehicleData( EventEnum id )
+{
+ bool retVal = false;
+
+ switch( id )
+ {
+ case EVENT_MINOR_VEHICLE_CRASH:
+ case EVENT_BIG_VEHICLE_CRASH:
+ case EVENT_WRONG_SIDE_DUMBASS:
+ case EVENT_TRAFFIC_IMPEDED:
+ case EVENT_BIG_BOOM_SOUND:
+ case EVENT_DEATH_VOLUME_SOUND:
+ retVal = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return( retVal );
+}
diff --git a/game/code/sound/dialog/dialogcoordinator.h b/game/code/sound/dialog/dialogcoordinator.h
new file mode 100644
index 0000000..e162de4
--- /dev/null
+++ b/game/code/sound/dialog/dialogcoordinator.h
@@ -0,0 +1,84 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogcoordinator.h
+//
+// Description: The main interface class for the dialog system. It listens
+// for game events and cues the appropriate line of dialog.
+// Objects representing lines or sets of lines are obtained
+// from the SpeechCoordinator, and are passed to the
+// DialogPriorityQueue, which determines when playback is
+// ready to begin.
+//
+// History: 30/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGCOORDINATOR_H
+#define DIALOGCOORDINATOR_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/dialog/dialogpriorityqueue.h>
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+struct IRadNameSpace;
+class DialogList;
+class Character;
+class Vehicle;
+
+//=============================================================================
+//
+// Synopsis: DialogCoordinator
+//
+//=============================================================================
+
+class DialogCoordinator : public EventListener
+{
+ public:
+ DialogCoordinator( IRadNameSpace* namespaceObj );
+ virtual ~DialogCoordinator();
+
+ void Initialize();
+ void OnGameplayEnd() { m_playbackQueue->StopAllDialog(); }
+
+ void OnPauseStart() { m_playbackQueue->PauseDialog(); }
+ void OnPauseEnd() { m_playbackQueue->UnpauseDialog(); }
+
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ void ServiceOncePerFrame() { m_playbackQueue->ServiceOncePerFrame(); }
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogCoordinator();
+ DialogCoordinator( const DialogCoordinator& original );
+ DialogCoordinator& operator=( const DialogCoordinator& rhs );
+
+ void registerDialogEvents();
+ void queueVillainDialog( EventEnum id, void* eventData );
+ bool playLinePositionally( EventEnum id );
+ void getCharacterPosition( Character* thePed, rmt::Vector& posn );
+ bool eventHasVehicleData( EventEnum id );
+
+ IRadNameSpace* m_dialogNamespace;
+
+ DialogList* m_dialogList;
+ DialogPriorityQueue* m_playbackQueue;
+
+ bool m_dialogOn;
+
+ //
+ // Hack!
+ //
+ bool m_phoneBoothRequestMade;
+};
+
+
+#endif // DIALOGCOORDINATOR_H
+
diff --git a/game/code/sound/dialog/dialogline.cpp b/game/code/sound/dialog/dialogline.cpp
new file mode 100644
index 0000000..d23c3f2
--- /dev/null
+++ b/game/code/sound/dialog/dialogline.cpp
@@ -0,0 +1,1018 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogline.cpp
+//
+// Description: Atomic unit of dialog. A DialogLine object represents a
+// complete line of dialog spoken by a single character.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radkey.hpp>
+#include <radnamespace.hpp>
+#include <p3d/anim/skeleton.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogline.h>
+
+#include <sound/dialog/dialogselectiongroup.h>
+
+#include <sound/simpsonssoundplayer.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <mission/gameplaymanager.h>
+#include <worldsim/character/character.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+EventTableEntry eventTable[] =
+{
+ { "GIC", 0, EVENT_GETINTOVEHICLE_START, 2500 },
+ { "GOC", 0, EVENT_GETOUTOFVEHICLE_START, 2500 },
+ { "convinit", 0, EVENT_CONVERSATION_INIT_DIALOG, 2500 },
+ { "noboxconv", 0, EVENT_IN_GAMEPLAY_CONVERSATION, 2500 },
+ { "tutorial", 0, EVENT_TUTORIAL_DIALOG_PLAY, 2500 },
+ { "Mcrash", 0, EVENT_MINOR_VEHICLE_CRASH, 2500 },
+ { "Bcrash", 0, EVENT_BIG_VEHICLE_CRASH, 2500 },
+ { "Arrive", 0, EVENT_DESTINATION_REACHED, 2500 },
+ { "Air", 0, EVENT_BIG_AIR, 2500 },
+ { "Burn", 0, EVENT_BURNOUT, 2500 },
+ { "ObjectW", 0, EVENT_COLLECT_OBJECT, 2500 },
+ { "Break", 0, EVENT_HIT_BREAKABLE, 2500 },
+ { "Mfail", 0, EVENT_MISSION_FAILURE, 4000 },
+ { "Mvic", 0, EVENT_MISSION_SUCCESS_DIALOG, 4000 },
+ { "Tail", 0, EVENT_TAIL_LOST_DIALOG, 2500 },
+ { "NewAI", 0, EVENT_CHASE_VEHICLE_PROXIMITY, 2500 },
+ { "Time", 0, EVENT_TIME_RUNNING_OUT, 2500 },
+ { "Pass", 0, EVENT_RACE_PASSED_AI, 2500 },
+ { "Passed", 0, EVENT_RACE_GOT_PASSED_BY_AI, 2500 },
+ { "Activate", 0, EVENT_BIG_RED_SWITCH_PRESSED, 250 }, // Make this quite short
+ { "Fall", 0, EVENT_DEATH_VOLUME_SOUND, 2500 },
+ { "Char", 0, EVENT_PEDESTRIAN_SMACKDOWN, 2500 },
+ { "HitByW", 0, EVENT_KICK_NPC_SOUND, 2500 },
+ { "BreakCa", 0, EVENT_BREAK_CAMERA_OR_BOX, 2500 },
+ { "Turbo", 0, EVENT_CHARACTER_TIRED_NOW, 2500 },
+ { "Springboard", 0, static_cast<EventEnum>(EVENT_LOCATOR + LocatorEvent::BOUNCEPAD), 2500 },
+ { "NHitByC", 0, EVENT_PEDESTRIAN_DODGE, 2500 },
+ { "HitByC", 0, EVENT_PLAYER_CAR_HIT_NPC, 2500 },
+ { "HitP", 0, EVENT_PLAYER_MAKES_LIGHT_OF_CAR_HITTING_NPC, 2500 },
+ { "Damage", 0, EVENT_BIG_CRASH, 2500 },
+ { "Door", 0, EVENT_WRONG_SIDE_DUMBASS, 2500 },
+ { "CarWay", 0, EVENT_TRAFFIC_IMPEDED, 2500 },
+ { "Doorbell", 0, EVENT_DING_DONG, 2500 },
+ { "Askride", 0, EVENT_PHONE_BOOTH_RIDE_REQUEST, 0 },
+ { "Ridereply", 0, EVENT_PHONE_BOOTH_NEW_VEHICLE_SELECTED, 0 },
+ { "Answer", 0, EVENT_PHONE_BOOTH_OLD_VEHICLE_RESELECTED, 0 },
+ { "HitCar", 0, EVENT_VILLAIN_CAR_HIT_PLAYER, 2500 },
+ { "Greeting", 0, EVENT_AMBIENT_GREETING, 2500 },
+ { "Idlereply", 0, EVENT_AMBIENT_RESPONSE, 0 },
+ { "Askfood", 0, EVENT_AMBIENT_ASKFOOD, 2500 },
+ { "Foodreply", 0, EVENT_AMBIENT_FOODREPLY, 0 },
+ { "CarBuy", 0, EVENT_HAGGLING_WITH_GIL, 2500 },
+ { "Dcar", 0, EVENT_BIG_BOOM_SOUND, 5000 },
+ { "Card", 0, EVENT_CARD_COLLECTED, 2500 },
+ { "Mstart", 0, EVENT_MISSION_BRIEFING_ACCEPTED, 0 }
+};
+
+static unsigned int eventTableLength = sizeof( eventTable ) / sizeof( EventTableEntry );
+
+CharacterTableEntry characterTable[] =
+{
+ { 0, "Hom", 0, "homer" },
+ { 0, "Mrg", 0, "marge" },
+ { 0, "Brt", 0, "bart" },
+ { 0, "Lis", 0, "lisa" },
+ { 0, "Apu", 0, "apu" },
+ { 0, "Agn", 0, "askinner" },
+ { 0, "Brn", 0, "barney" },
+ { 0, "Bee", 0, "beeman" },
+ { 0, "Crl", 0, "carl" },
+ { 0, "Cbg", 0, "cbg" },
+ { 0, "Clt", 0, "cletus" },
+ { 0, "Dol", 0, "dolph" },
+ { 0, "Nic", 0, "nriviera" },
+ { 0, "Frk", 0, "frink" },
+ { 0, "Fla", 0, "ned" },
+ { 0, "By1", 0, "boy1" },
+ { 0, "By2", 0, "boy2" },
+ { 0, "Fm1", 0, "fem1" },
+ { 0, "Fm2", 0, "fem2" },
+ { 0, "Gil", 0, "gil" },
+ { 0, "Gr1", 0, "girl1" },
+ { 0, "Gr2", 0, "girl2" },
+ { 0, "Kan", 0, "kang" },
+ { 0, "Kod", 0, "kodos" },
+ { 0, "Mn1", 0, "male1" },
+ { 0, "Mn2", 0, "male2" },
+ { 0, "Grp", 0, "grandpa" },
+ { 0, "Mol", 0, "moleman" },
+ { 0, "Jas", 0, "jasper" },
+ { 0, "Jim", 0, "jimbo" },
+ { 0, "Kea", 0, "kearney" },
+ { 0, "Kru", 0, "krusty" },
+ { 0, "Len", 0, "lenny" },
+ { 0, "Loe", 0, "lou" },
+ { 0, "Lou", 0, "louie" },
+ { 0, "Mil", 0, "milhouse" },
+ { 0, "Moe", 0, "moe" },
+ { 0, "Nel", 0, "nelson" },
+ { 0, "Oto", 0, "otto" },
+ { 0, "Pat", 0, "patty" },
+ { 0, "Qim", 0, "quimby" },
+ { 0, "Ral", 0, "ralph" },
+ { 0, "Sea", 0, "captain" },
+ { 0, "Sel", 0, "selma" },
+ { 0, "Skn", 0, "skinner" },
+ { 0, "Smi", 0, "smithers" },
+ { 0, "Snk", 0, "snake" },
+ { 0, "Svt", 0, "teen" },
+ { 0, "Wig", 0, "wiggum" },
+ { 0, "Wil", 0, "willie" },
+ { 0, "Zom", 0, "zombie" },
+ { 0, "Zm1", 0, "zombie1" },
+ { 0, "Zm2", 0, "zombie2" },
+ { 0, "Zm3", 0, "zombie3" },
+ { 0, "Zm4", 0, "zombie4" },
+ { 0, "Hib", 0, "hibbert" },
+ { 0, "Bur", 0, "burns" },
+ { 0, "Rod", 0, "rod" },
+ { 0, "Todd", 0, "todd" },
+ { 0, "Bkm", 0, "brockman" },
+ { 0, "Hbn", 0, "homerbrain" },
+ { 0, "Vm1", 0, "traffic1" },
+ { 0, "Vm2", 0, "traffic2" },
+ { 0, "Vm3", 0, "traffic3" },
+ { 0, "Vm4", 0, "traffic4" }
+};
+
+static unsigned int characterTableLength = sizeof( characterTable ) / sizeof( CharacterTableEntry );
+
+//
+// The food guys
+//
+static unsigned int APU_INDEX = 4;
+static unsigned int TEEN_INDEX = 47;
+
+//
+// Arbitrary number, used in field name buffers
+//
+static const int FIELD_BUFFER_LEN = 64;
+static const int MY_FILENAME_BUFFER_LEN = 150;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogLine::DialogLine
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogLine::DialogLine( IDaSoundResource* resource )
+{
+ m_resource = resource;
+ m_characterIndex = -1;
+ m_role = ROLE_NONE;
+ m_conversationPosition = NOT_CONVERSATION_LINE;
+ m_ConversationName = 0;
+
+ static bool tablesInitialized = false;
+
+ if( !tablesInitialized )
+ {
+ initializeTables();
+ tablesInitialized = true;
+ }
+
+ parseResourceFilename();
+}
+
+//==============================================================================
+// DialogLine::~DialogLine
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogLine::~DialogLine()
+{
+}
+
+//==============================================================================
+// DialogLine::PlayLine
+//==============================================================================
+// Description: Play the dialog line
+//
+// Parameters: lineIndex - ignored, only used for other SelectableDialog subclasses
+// player - what we use for the playing
+// callback - who we call when we're done
+//
+// Return: N/A.
+//
+//==============================================================================
+void DialogLine::PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ player.PlayResource( m_resource, callback );
+}
+
+//=============================================================================
+// DialogLine::QueueLine
+//=============================================================================
+// Description: Buffer a line of dialog for playback
+//
+// Parameters: lineIndex - ignored, only used for other SelectableDialog subclasses
+// player - what we use for the queueing
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::QueueLine( unsigned int lineIndex, SimpsonsSoundPlayer& player )
+{
+ player.QueueSound( m_resource );
+}
+
+//=============================================================================
+// DialogLine::PlayQueuedLine
+//=============================================================================
+// Description: Play the sound we queued with QueueLine
+//
+// Parameters: player - what we use for the playing
+// callback - if non-NULL, object to notify when playback done
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ player.PlayQueuedSound( callback );
+}
+
+//=============================================================================
+// DialogLine::StripDirectoryCrud
+//=============================================================================
+// Description: Utility function for stripping directory prefix from filenames
+//
+// Parameters: filename - filename to strip
+// buffer - holds stripped filename
+// bufferLen - length of buffer
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::StripDirectoryCrud( const char* filename, char* buffer, int bufferLen )
+{
+ const char* charPtr;
+ int i, j;
+ int strippedLength = 0;
+
+ i = strlen( filename );
+ charPtr = &(filename[i]);
+ while( i > 0 )
+ {
+ if( ( *charPtr == '/' ) || ( *charPtr == '\\' ) )
+ {
+ break;
+ }
+ else
+ {
+ ++strippedLength;
+ --i;
+ --charPtr;
+ }
+ }
+
+ //
+ // Copy stripped filename to buffer
+ //
+ if( i > 0 )
+ {
+ ++charPtr;
+ }
+
+ if( strippedLength > bufferLen )
+ {
+ strippedLength = bufferLen;
+ }
+
+ for( j = 0; j < strippedLength; j++ )
+ {
+ buffer[j] = *charPtr++;
+ }
+}
+
+//=============================================================================
+// DialogLine::GetEventTableEntry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int index )
+//
+// Return: EventTableEntry
+//
+//=============================================================================
+const EventTableEntry* DialogLine::GetEventTableEntry( unsigned int index )
+{
+ if( index >= eventTableLength )
+ {
+ return( NULL );
+ }
+ else
+ {
+ return( &(eventTable[index]) );
+ }
+}
+
+//=============================================================================
+// DialogLine::GetEventTableSize
+//=============================================================================
+// Description: Return the number of entries in the event table
+//
+// Parameters: None
+//
+// Return: table size
+//
+//=============================================================================
+unsigned int DialogLine::GetEventTableSize()
+{
+ return( eventTableLength );
+}
+
+//=============================================================================
+// DialogLine::GetCharacterTableEntry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int index )
+//
+// Return: CharacterTableEntry
+//
+//=============================================================================
+const CharacterTableEntry* DialogLine::GetCharacterTableEntry( unsigned int index )
+{
+ if( index >= characterTableLength )
+ {
+ return( NULL );
+ }
+ else
+ {
+ return( &(characterTable[index]) );
+ }
+}
+
+//=============================================================================
+// DialogLine::GetCharacterTableSize
+//=============================================================================
+// Description: Return the number of entries in the character table
+//
+// Parameters: None
+//
+// Return: table size
+//
+//=============================================================================
+unsigned int DialogLine::GetCharacterTableSize()
+{
+ return( characterTableLength );
+}
+
+//=============================================================================
+// DialogLine::UsesCharacter
+//=============================================================================
+// Description: Indicate whether this dialog line comes from
+// the character given
+//
+// Parameters: characterObj - character to match
+//
+// Return: true if character matches this line, false otherwise
+//
+//=============================================================================
+bool DialogLine::UsesCharacter( tUID characterUID )
+{
+ return( characterUID == GetCharacterUID( ) );
+}
+
+//=============================================================================
+// DialogLine::AddMatchingDialog
+//=============================================================================
+// Description: Request to a SelectableDialog object (this one) to add a new
+// DialogLine or such with the same characteristics. Since this
+// object represents a single line, we need to create a
+// DialogSelectionGroup and add self and the new dialog line to it,
+// and put it in our spot in the list.
+//
+// Parameters: newDialog - dialogLine that matches this one
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ DialogSelectionGroup* group = new DialogSelectionGroup( *this, newDialog );
+
+ rAssert( group != NULL );
+
+ list.remove( this );
+ list.push_back( group );
+
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//=============================================================================
+// DialogLine::GetConversationName
+//=============================================================================
+// Description: Returns the name of the conversation this line belongs to,
+// if this is a conversation line. We'll calculate it on the
+// fly, no sense in wasting more space than we already are.
+//
+// Parameters: None
+//
+// Return: radKey32 representation of conversation name field, or 0
+// if this isn't a conversation line
+//
+//=============================================================================
+
+void DialogLine::parseConversationName( )
+{
+ bool fieldFound;
+ char fieldBuffer[FIELD_BUFFER_LEN];
+ char filenameBuffer[MY_FILENAME_BUFFER_LEN];
+ char tempBuffer[MY_FILENAME_BUFFER_LEN];
+
+ //
+ // Strip the directory crud
+ //
+ m_resource->GetFileNameAt( 0, tempBuffer, MY_FILENAME_BUFFER_LEN );
+ StripDirectoryCrud( tempBuffer, filenameBuffer, MY_FILENAME_BUFFER_LEN );
+
+ fieldFound = getNameField( filenameBuffer, 0, fieldBuffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ if( ( fieldBuffer[0] == 'C') && ( fieldBuffer[1] == '\0' ) )
+ {
+ //
+ // Conversation line
+ //
+ fieldFound = getNameField( filenameBuffer, 1, fieldBuffer, FIELD_BUFFER_LEN );
+ m_ConversationName = radMakeKey32( fieldBuffer );
+ }
+ else
+ {
+ //
+ // Not conversation line
+ //
+ rTuneAssert( false );
+ }
+}
+
+//=============================================================================
+// DialogLine::IsFoodCharacter
+//=============================================================================
+// Description: Determine whether this character gets Askfood lines or
+// Idlereply
+//
+// Parameters: theGuy - ambient character being talked to
+//
+// Return: true for Askfood, false for Idlereply
+//
+//=============================================================================
+bool DialogLine::IsFoodCharacter( Character* theGuy )
+{
+ tUID UID1;
+ bool retVal = false;
+
+ choreo::Puppet* puppet = theGuy->GetPuppet();
+ if( puppet != NULL )
+ {
+ UID1 = puppet->GetPose()->GetSkeleton()->GetUID();
+
+ //
+ // Hard-coded hack
+ //
+ rAssert( strcmp( "Apu", characterTable[APU_INDEX].characterString ) == 0 );
+ rAssert( strcmp( "Svt", characterTable[TEEN_INDEX].characterString ) == 0 );
+
+ if( ( UID1 == static_cast< tUID >( characterTable[APU_INDEX].realCharacterUID ) )
+ || ( UID1 == static_cast< tUID >( characterTable[TEEN_INDEX].realCharacterUID ) ) )
+ {
+ retVal = true;
+ }
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// DialogLine::GetLifeInMsecsForEvent
+//=============================================================================
+// Description: Given an event, return the number of milliseconds that the
+// dialog for that event should be allowed to live in the queue
+//
+// Parameters: eventID - ID for event
+//
+// Return: lifetime in msecs, 0 for infinite lifetime
+//
+//=============================================================================
+unsigned int DialogLine::GetLifeInMsecsForEvent( EventEnum eventID )
+{
+ unsigned int i;
+ unsigned int lifetime = 2500; // 2.5 sec. default
+
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ if( eventTable[i].event == eventID )
+ {
+ lifetime = eventTable[i].lifeInMsecs;
+ break;
+ }
+ }
+
+ return( lifetime );
+}
+
+//=============================================================================
+// DialogLine::FillCharacterName
+//=============================================================================
+// Description: Fill the given buffer with the text name of the character
+// matching the given UID
+//
+// Parameters: buffer - buffer to write name to
+// bufferSize - length of buffer
+// characterUID - UID of character to find name for
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::FillCharacterName( char* buffer, unsigned int bufferSize, tUID characterUID )
+{
+ unsigned int i;
+ unsigned int tableSize;
+ const CharacterTableEntry* charTableLine;
+
+ tableSize = GetCharacterTableSize();
+
+ for( i = 0; i < tableSize; i++ )
+ {
+ charTableLine = GetCharacterTableEntry( i );
+ if( charTableLine->realCharacterUID == characterUID )
+ {
+ break;
+ }
+ }
+
+ if( i < tableSize )
+ {
+ rAssert( strlen( charTableLine->characterString ) < bufferSize );
+ strcpy( buffer, charTableLine->characterString );
+ }
+ else
+ {
+ rAssert( bufferSize >= 4 );
+ strcpy( buffer, "???" );
+ }
+}
+
+//=============================================================================
+// DialogLine::FillEventName
+//=============================================================================
+// Description: Fill the given buffer with the text name of the event
+// matching the given ID
+//
+// Parameters: buffer - buffer to write name to
+// bufferSize - length of buffer
+// eventID - ID of event to find name for
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::FillEventName( char* buffer, unsigned int bufferSize, EventEnum eventID )
+{
+ unsigned int i;
+ unsigned int tableSize;
+ const EventTableEntry* eventTableLine;
+
+ tableSize = GetEventTableSize();
+
+ for( i = 0; i < tableSize; i++ )
+ {
+ eventTableLine = GetEventTableEntry( i );
+ if( eventTableLine->event == eventID )
+ {
+ break;
+ }
+ }
+
+ if( i < tableSize )
+ {
+ rAssert( strlen( eventTableLine->eventString ) < bufferSize );
+ strcpy( buffer, eventTableLine->eventString );
+ }
+ else
+ {
+ rAssert( bufferSize >= 4 );
+ strcpy( buffer, "???" );
+ }
+}
+
+//=============================================================================
+// DialogLine::PrintResourceName
+//=============================================================================
+// Description: Dump out the name of the sound resource. For debugging.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::PrintResourceName()
+{
+#ifndef RAD_RELEASE
+ char buffer[256];
+
+ rAssert( m_resource != NULL );
+
+ m_resource->GetFileNameAt( 0, buffer, 256 );
+ rDebugPrintf( "DialogLine - %s\n", buffer );
+#endif
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogLine::parseResourceFilename
+//=============================================================================
+// Description: Look at the resource filename and fill out the dialog line
+// attributes based on what we find
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::parseResourceFilename()
+{
+ bool fieldFound;
+ char fieldBuffer[FIELD_BUFFER_LEN];
+ char filenameBuffer[MY_FILENAME_BUFFER_LEN];
+ char tempBuffer[MY_FILENAME_BUFFER_LEN];
+
+ //
+ // Strip the directory crud
+ //
+ m_resource->GetFileNameAt( 0, tempBuffer, MY_FILENAME_BUFFER_LEN );
+ StripDirectoryCrud( tempBuffer, filenameBuffer, MY_FILENAME_BUFFER_LEN );
+
+ fieldFound = getNameField( filenameBuffer, 0, fieldBuffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ if( ( fieldBuffer[0] == 'C') && ( fieldBuffer[1] == '\0' ) )
+ {
+ //
+ // Conversation line
+ //
+ parseConversationName( );
+ matchOrderField( filenameBuffer, 2 );
+ matchEventField( filenameBuffer, 3 );
+ matchCharacterField( filenameBuffer, 4 );
+ matchLevelField( filenameBuffer, 5 );
+ }
+ else
+ {
+ //
+ // One-liner
+ //
+ matchRoleField( filenameBuffer, 0 );
+ matchEventField( filenameBuffer, 1 );
+ matchCharacterField( filenameBuffer, 2 );
+ matchLevelField( filenameBuffer, 3 );
+ }
+}
+
+void DialogLine::matchRoleField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ switch( buffer[0] )
+ {
+ case 'W':
+ m_role = ROLE_WALKER;
+ break;
+ case 'D':
+ m_role = ROLE_DRIVER;
+ break;
+ case 'P':
+ m_role = ROLE_PEDESTRIAN;
+ break;
+ case 'V':
+ m_role = ROLE_VILLAIN;
+ break;
+ default:
+ rAssertMsg( false, "Unknown role field in dialog file\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// DialogLine::matchEventField
+//=============================================================================
+// Description: Parse the field at the given position and store the eventEnum
+// that matches it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchEventField( const char* filename, int field )
+{
+ unsigned int i;
+ char buffer[FIELD_BUFFER_LEN];
+ radKey32 fieldKey;
+ bool fieldFound;
+
+ //
+ // Event name. Use a lookup table to translate to the event
+ // enumeration.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ fieldKey = ::radMakeCaseInsensitiveKey32( buffer );
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ if( fieldKey == eventTable[i].eventKey )
+ {
+ m_event = eventTable[i].event;
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// DialogLine::matchOrderField
+//=============================================================================
+// Description: Parse the field at the given position and store it as the value
+// for the conversation position
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchOrderField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ //
+ // Event name. Use a lookup table to translate to the event
+ // enumeration.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ rAssert( buffer[0] >= '0' );
+ rAssert( buffer[0] <= '9' );
+
+ m_conversationPosition = buffer[0] - '0';
+}
+
+//=============================================================================
+// DialogLine::matchCharacterField
+//=============================================================================
+// Description: Parse the field at the given position and store the characterEnum
+// that matches it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchCharacterField( const char* filename, int field )
+{
+ unsigned int i;
+ char buffer[FIELD_BUFFER_LEN];
+ radKey32 fieldKey;
+ bool fieldFound;
+
+ //
+ // Character. Use another lookup table.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+ rAssert( fieldFound );
+
+ fieldKey = ::radMakeCaseInsensitiveKey32( buffer );
+ for( i = 0; i < characterTableLength; i++ )
+ {
+ if( fieldKey == characterTable[i].characterKey )
+ {
+ m_characterIndex = i;
+ break;
+ }
+ }
+
+ rAssert( ( i < characterTableLength )
+ || ( filename[0] != 'C' ) );
+}
+
+//=============================================================================
+// DialogLine::matchLevelField
+//=============================================================================
+// Description: Parse the field at the given position and store the level
+// and mission numbers that match it
+//
+// Parameters: field - number of field to parse
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::matchLevelField( const char* filename, int field )
+{
+ char buffer[FIELD_BUFFER_LEN];
+ bool fieldFound;
+
+ //
+ // Level/Mission.
+ //
+ fieldFound = getNameField( filename, field, buffer, FIELD_BUFFER_LEN );
+
+ if( fieldFound )
+ {
+ if( ( buffer[0] == 'L' )
+ && ( buffer[1] >= '0' )
+ && ( buffer[1] <= '9' ) )
+ {
+ //
+ // Level number, start to string is "Lx"
+ //
+ m_levelNum = buffer[1] - '0';
+ rAssert( m_levelNum > 0 );
+ rAssert( m_levelNum < GameplayManager::MAX_LEVELS );
+
+ if( strlen( buffer ) >= 4 )
+ {
+ //
+ // Level and mission, expected string is "LxMy"
+ //
+ rAssert( ( buffer[2] == 'M' ) || ( buffer[2] == 'B' ) || ( buffer[2] == 'R' ) || ( buffer[2] == 'T' ) );
+ m_missionNum = buffer[3] - '0';
+ rAssert( m_missionNum >= 1 );
+ rAssert( m_missionNum <= 7 );
+
+ //
+ // Bonus == 8
+ // Races == 9-11
+ // Tutorial == 12
+ //
+ if( buffer[2] == 'B' )
+ {
+ rAssert( m_missionNum == 1 );
+ m_missionNum = BONUS_MISSION_NUMBER;
+ }
+ else if( buffer[2] == 'R' )
+ {
+ rAssert( m_missionNum >= 1 );
+ rAssert( m_missionNum <= 3 );
+ m_missionNum += FIRST_RACE_MISSION_NUMBER - 1;
+ }
+ else if( buffer[2] == 'T' )
+ {
+ rAssert( m_missionNum == 1 );
+ m_missionNum = TUTORIAL_MISSION_NUMBER;
+ }
+ }
+ else
+ {
+ m_missionNum = NO_MISSION;
+ }
+ }
+ }
+}
+
+//=============================================================================
+// DialogLine::getNameField
+//=============================================================================
+// Description: Parse the filename for a particular field, and return it in
+// the given buffer
+//
+// Parameters: filename -- name of file to parse
+// field -- number of field to find (counting from 0)
+// buffer -- buffer to copy field into
+// bufferLen -- length of buffer
+//
+// Return: true if requested field exists, false otherwise
+//
+//=============================================================================
+bool DialogLine::getNameField( const char* filename, int field, char* buffer, int bufferLen )
+{
+ const char* currentChar;
+ int i;
+ int fieldCount = field;
+ bool fieldFound = false;
+
+ currentChar = filename;
+ while( ( fieldCount > 0 ) && ( *currentChar != '\0' ) && ( *currentChar != '.' ) )
+ {
+ if( *currentChar == '_' )
+ {
+ --fieldCount;
+ }
+
+ ++currentChar;
+ }
+
+ if( ( *currentChar != '\0' ) && ( *currentChar != '.' ) )
+ {
+ //
+ // Field found, copy to buffer. Since GC has no string functions (argh),
+ // use hand-rolled strncpy
+ //
+ for( i = 0;
+ ( (i < bufferLen-1) && (currentChar[i] != '\0') && (currentChar[i] != '_') && (currentChar[i] != '.') );
+ i++ )
+ {
+ buffer[i] = currentChar[i];
+ }
+ buffer[i] = '\0';
+
+ fieldFound = true;
+ }
+
+ return( fieldFound );
+}
+
+//=============================================================================
+// DialogLine::initializeTables
+//=============================================================================
+// Description: Fill out the radKey32 entries in the event table.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogLine::initializeTables()
+{
+ unsigned int i;
+
+ for( i = 0; i < eventTableLength; i++ )
+ {
+ eventTable[i].eventKey = ::radMakeCaseInsensitiveKey32( eventTable[i].eventString );
+ }
+
+ for( i = 0; i < characterTableLength; i++ )
+ {
+ characterTable[i].characterKey = ::radMakeCaseInsensitiveKey32( characterTable[i].characterString );
+ characterTable[i].realCharacterUID = tEntity::MakeUID( characterTable[i].realCharacterName );
+ }
+}
+
+tUID DialogLine::GetCharacterUID( void )
+{
+ if ( -1 == m_characterIndex )
+ {
+ return 0;
+ }
+
+ tUID uid = characterTable[ m_characterIndex ].realCharacterUID;
+ return uid;
+}
+
+tUID DialogLine::GetDialogLineCharacterUID( unsigned int lineNum )
+{
+ return GetCharacterUID( );
+}
+ \ No newline at end of file
diff --git a/game/code/sound/dialog/dialogline.h b/game/code/sound/dialog/dialogline.h
new file mode 100644
index 0000000..1d72cdb
--- /dev/null
+++ b/game/code/sound/dialog/dialogline.h
@@ -0,0 +1,172 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogline.h
+//
+// Description: Atomic unit of dialog. A DialogLine object represents a
+// complete line of dialog spoken by a single character.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGLINE_H
+#define DIALOGLINE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <p3d/p3dtypes.hpp>
+
+#include <sound/dialog/playabledialog.h>
+#include <sound/dialog/selectabledialoglist.h>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundresource.h>
+//========================================
+// Forward References
+//========================================
+
+class Character;
+
+//
+// Table entry structure for mapping between event strings in filenames
+// and events responded to in dialog system
+//
+struct EventTableEntry
+{
+ const char* eventString;
+ radKey32 eventKey;
+ EventEnum event;
+ unsigned int lifeInMsecs;
+};
+
+//
+// Table entry structure for mapping between character strings in filenames
+// and tUIDs that we pull out of the Character objects.
+//
+struct CharacterTableEntry
+{
+ radInt64 realCharacterUID;
+ const char* characterString;
+ radKey32 characterKey;
+ const char* realCharacterName;
+};
+
+const char ROLE_NONE = 0;
+const char ROLE_WALKER = 1;
+const char ROLE_DRIVER = 2;
+const char ROLE_PEDESTRIAN = 3;
+const char ROLE_VILLAIN = 4;
+
+typedef char DialogRole;
+
+//=============================================================================
+//
+// Synopsis: DialogLine
+//
+//=============================================================================
+
+class DialogLine : public PlayableDialog
+{
+ public:
+ DialogLine( IDaSoundResource* resource );
+ virtual ~DialogLine();
+
+ static const int NOT_CONVERSATION_LINE = -1;
+
+ static const int BONUS_MISSION_NUMBER = 8;
+ static const int FIRST_RACE_MISSION_NUMBER = 9;
+ static const int TUTORIAL_MISSION_NUMBER = 12;
+
+ int GetConversationPosition() { return( m_conversationPosition ); }
+ tUID GetCharacterUID();
+ tUID GetDialogLineCharacterUID( unsigned int lineNum );
+ bool IsVillainLine() { return( m_role == ROLE_VILLAIN ); }
+
+ inline radKey32 GetConversationName( );
+
+ //
+ // Pure virtual functions from SelectableDialog
+ //
+ void PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+ void QueueLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player );
+ void PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+
+ unsigned int GetNumDialogLines() const { return( 1 ); }
+ bool UsesCharacter( tUID characterUID );
+ void AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list );
+
+ static bool IsFoodCharacter( Character* theGuy );
+ static unsigned int GetLifeInMsecsForEvent( EventEnum eventID );
+
+ //
+ // Utility for stripping the directory crud off of filenames
+ //
+ static void StripDirectoryCrud( const char* filename, char* buffer, int bufferLen );
+
+ //
+ // Accessors for tables
+ //
+ static const EventTableEntry* GetEventTableEntry( unsigned int index );
+ static unsigned int GetEventTableSize();
+
+ static const CharacterTableEntry* GetCharacterTableEntry( unsigned int index );
+ static unsigned int GetCharacterTableSize();
+
+ static void FillEventName( char* buffer, unsigned int bufferSize, EventEnum eventID );
+ static void FillCharacterName( char* buffer, unsigned int bufferSize, tUID characterUID );
+
+ //
+ // For debugging
+ //
+ void PrintResourceName();
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogLine();
+ DialogLine( const DialogLine& original );
+ DialogLine& operator=( const DialogLine& rhs );
+
+ void parseResourceFilename();
+ bool getNameField( const char* filename, int field, char* buffer, int bufferLen );
+ void initializeTables();
+
+ void matchRoleField( const char* filename, int field );
+ void matchOrderField( const char* filename, int field );
+ void matchEventField( const char* filename, int field );
+ void matchCharacterField( const char* filename, int field );
+ void matchLevelField( const char* filename, int field );
+ void parseConversationName( );
+ //
+ // Sound resource to play
+ //
+ IDaSoundResource* m_resource;
+
+ radKey32 m_ConversationName;
+
+ DialogRole /* (char)*/ m_role;
+
+ //
+ // Position within conversation if this is a conversation line
+ //
+
+ char m_conversationPosition;
+
+ //
+ // Character that this line belongs to
+ //
+ char m_characterIndex;
+};
+
+inline radKey32 DialogLine::GetConversationName( )
+{
+ return m_ConversationName;
+}
+
+#endif // DIALOGLINE_H
+
diff --git a/game/code/sound/dialog/dialoglist.cpp b/game/code/sound/dialog/dialoglist.cpp
new file mode 100644
index 0000000..0dcab5e
--- /dev/null
+++ b/game/code/sound/dialog/dialoglist.cpp
@@ -0,0 +1,1259 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialoglist.cpp
+//
+// Description: Loads and maintains the list of dialog lines and conversations
+// (which group multiple dialog lines, and potentially link
+// conversations to other conversations that occur later).
+//
+// History: 01/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+#include <raddebugwatch.hpp>
+
+#include <p3d/anim/skeleton.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialoglist.h>
+
+#include <sound/dialog/dialogline.h>
+#include <sound/dialog/conversationmatcher.h>
+#include <sound/soundrenderer/idasoundresource.h>
+
+#include <memory/srrmemory.h>
+#include <mission/gameplaymanager.h>
+#include <render/Enums/RenderEnums.h>
+#include <gameflow/gameflow.h>
+#include <worldsim/character/charactermanager.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Arbitrary buffer length for filenames
+//
+static const int FILENAME_BUFFER_LEN = 100;
+
+//
+// Stinky hack support
+//
+radKey32 DialogList::s_introKey = 0;
+radKey32 DialogList::s_aztecKey = 0;
+tUID DialogList::s_milhouseKey = 0;
+tUID DialogList::s_nelsonKey = 0;
+tUID DialogList::s_raceZombie1 = 0;
+tUID DialogList::s_raceZombie2 = 0;
+
+enum pedDialogType
+{
+ PED_MALE1,
+ PED_MALE2,
+ PED_FEMALE1,
+ PED_FEMALE2,
+ PED_BOY1,
+ PED_BOY2,
+ PED_GIRL1,
+ PED_GIRL2,
+ PED_ZOMBIE1,
+ PED_ZOMBIE2,
+ PED_ZOMBIE3,
+ PED_ZOMBIE4,
+
+ PED_NUM_TYPES
+};
+
+enum skinDialogType
+{
+ SKIN_APU,
+ SKIN_BART,
+ SKIN_HOMER,
+ SKIN_LISA,
+ SKIN_MARGE,
+ SKIN_BARNEY,
+ SKIN_MILHOUSE,
+ SKIN_NELSON,
+ SKIN_RALPH,
+ SKIN_CLETUS,
+ SKIN_ZOMBIE1,
+ SKIN_ZOMBIE2,
+ SKIN_ZOMBIE3,
+ SKIN_ZOMBIE4,
+ SKIN_OTTO,
+ SKIN_WILLIE,
+ SKIN_KEARNEY,
+ SKIN_SKINNER,
+ SKIN_GRANDPA,
+ SKIN_CBG,
+ SKIN_FRINK,
+ SKIN_SNAKE,
+ SKIN_SMITHERS,
+
+ SKIN_NUM_TYPES
+};
+
+struct pedTypeInfo
+{
+ radInt64 pedUID;
+ const char* pedName;
+ pedDialogType dialogGroup;
+};
+
+static pedTypeInfo pedestrianNameTable[] =
+{
+ { 0, "boy", PED_BOY1 },
+ { 0, "boy2", PED_BOY2 },
+ { 0, "boy3", PED_BOY1 },
+ { 0, "bum", PED_MALE1 },
+ { 0, "busm1", PED_MALE2 },
+ { 0, "busm2", PED_MALE1 },
+ { 0, "busw1", PED_FEMALE1 },
+ { 0, "const1", PED_MALE2 },
+ { 0, "const2", PED_MALE1 },
+ { 0, "farmr1", PED_MALE2 },
+ { 0, "fem1", PED_FEMALE2 },
+ { 0, "fem2", PED_FEMALE1 },
+ { 0, "fem3", PED_FEMALE2 },
+ { 0, "fem4", PED_FEMALE1 },
+ { 0, "girl1", PED_GIRL1 },
+ { 0, "girl2", PED_GIRL2 },
+ { 0, "hooker", PED_FEMALE2 },
+ { 0, "joger1", PED_FEMALE1 },
+ { 0, "joger2", PED_MALE1 },
+ { 0, "male1", PED_MALE2 },
+ { 0, "male2", PED_MALE1 },
+ { 0, "male3", PED_MALE2 },
+ { 0, "male4", PED_MALE1 },
+ { 0, "male5", PED_MALE2 },
+ { 0, "male6", PED_MALE1 },
+ { 0, "mobstr", PED_MALE2 },
+ { 0, "nuclear", PED_MALE1 },
+ { 0, "olady1", PED_FEMALE2 },
+ { 0, "olady2", PED_FEMALE1 },
+ { 0, "olady3", PED_FEMALE2 },
+ { 0, "rednk1", PED_BOY2 },
+ { 0, "rednk2", PED_BOY1 },
+ { 0, "sail1", PED_MALE2 },
+ { 0, "sail2", PED_MALE1 },
+ { 0, "sail3", PED_MALE2 },
+ { 0, "sail4", PED_MALE1 },
+ { 0, "witch", PED_GIRL1 },
+ { 0, "frankenstein", PED_BOY2 },
+ { 0, "zfem1", PED_ZOMBIE3 },
+ { 0, "zfem5", PED_ZOMBIE3 },
+ { 0, "zmale1", PED_ZOMBIE1 },
+ { 0, "zmale3", PED_ZOMBIE2 },
+ { 0, "zmale4", PED_ZOMBIE4 }
+};
+
+static unsigned int pedestrianTableLength = sizeof( pedestrianNameTable ) / sizeof( pedTypeInfo );
+
+struct skinTypeInfo
+{
+ radInt64 skinUID;
+ const char* skinName;
+ skinDialogType dialogGroup;
+};
+
+static skinTypeInfo skinNameTable[] =
+{
+ { 0, "a_american", SKIN_APU },
+ { 0, "a_army", SKIN_APU },
+ { 0, "a_besharp", SKIN_APU },
+ { 0, "b_football", SKIN_BART },
+ { 0, "b_hugo", SKIN_BART },
+ { 0, "b_man", SKIN_BART },
+ { 0, "b_military", SKIN_BART },
+ { 0, "b_ninja", SKIN_BART },
+ { 0, "b_tall", SKIN_BART },
+ { 0, "h_donut", SKIN_HOMER },
+ { 0, "h_evil", SKIN_HOMER },
+ { 0, "h_fat", SKIN_HOMER },
+ { 0, "h_scuzzy", SKIN_HOMER },
+ { 0, "h_stcrobe", SKIN_HOMER },
+ { 0, "h_undrwr", SKIN_HOMER },
+ { 0, "reward_homer", SKIN_HOMER },
+ { 0, "l_cool", SKIN_LISA },
+ { 0, "l_florida", SKIN_LISA },
+ { 0, "l_jersey", SKIN_LISA },
+ { 0, "m_pink", SKIN_MARGE },
+ { 0, "m_police", SKIN_MARGE },
+ { 0, "m_prison", SKIN_MARGE },
+ { 0, "brn_unf", SKIN_BARNEY },
+ { 0, "reward_barney", SKIN_BARNEY },
+ { 0, "b_milhouse", SKIN_MILHOUSE },
+ { 0, "b_nelson", SKIN_NELSON },
+ { 0, "b_ralph", SKIN_RALPH },
+ { 0, "b_cletus", SKIN_CLETUS },
+ { 0, "b_zmale1", SKIN_ZOMBIE1 },
+ { 0, "b_zmale3", SKIN_ZOMBIE2 },
+ { 0, "b_zfem5", SKIN_ZOMBIE3 },
+ { 0, "b_zmale4", SKIN_ZOMBIE4 },
+ { 0, "b_zfem1", SKIN_ZOMBIE3 },
+ { 0, "b_skinner", SKIN_SKINNER },
+ { 0, "b_grandpa", SKIN_GRANDPA },
+ { 0, "b_cbg", SKIN_CBG },
+ { 0, "b_barney", SKIN_BARNEY },
+ { 0, "b_frink", SKIN_FRINK },
+ { 0, "b_snake", SKIN_SNAKE },
+ { 0, "b_smithers", SKIN_SMITHERS },
+ { 0, "reward_otto", SKIN_OTTO },
+ { 0, "reward_willie", SKIN_WILLIE },
+ { 0, "reward_kearney", SKIN_KEARNEY }
+};
+
+static unsigned int skinTableLength = sizeof( skinNameTable ) / sizeof( skinTypeInfo );
+
+struct pedDialogGroupInfo
+{
+ radInt64 pedUID;
+ const char* pedName;
+};
+
+//
+// Size must be PED_NUM_TYPES
+//
+static pedDialogGroupInfo dialogGroupTable[] =
+{
+ { 0, "male1" },
+ { 0, "male2" },
+ { 0, "fem1" },
+ { 0, "fem2" },
+ { 0, "boy1" },
+ { 0, "boy2" },
+ { 0, "girl1" },
+ { 0, "girl2" },
+ { 0, "zombie1" },
+ { 0, "zombie2" },
+ { 0, "zombie3" },
+ { 0, "zombie4" }
+};
+
+struct skinDialogGroupInfo
+{
+ radInt64 charUID;
+ const char* charName;
+};
+
+//
+// Size must be SKIN_NUM_TYPES
+//
+static skinDialogGroupInfo skinDialogGroupTable[] =
+{
+ { 0, "apu" },
+ { 0, "bart" },
+ { 0, "homer" },
+ { 0, "lisa" },
+ { 0, "marge" },
+ { 0, "barney" },
+ { 0, "milhouse" },
+ { 0, "nelson" },
+ { 0, "ralph" },
+ { 0, "cletus" },
+ { 0, "zombie1" },
+ { 0, "zombie2" },
+ { 0, "zombie3" },
+ { 0, "zombie4" },
+ { 0, "otto" },
+ { 0, "willie" },
+ { 0, "kearney" },
+ { 0, "skinner" },
+ { 0, "grandpa" },
+ { 0, "cbg" },
+ { 0, "frink" },
+ { 0, "snake" },
+ { 0, "smithers" }
+};
+
+//
+// Debug flag
+//
+bool DialogList::s_showDialogSpew = false;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogList::DialogList
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogList::DialogList()
+{
+ unsigned int i;
+
+ //
+ // Lazy initialization
+ //
+ if( s_introKey == 0 )
+ {
+ s_introKey = ::radMakeKey32( "intro" );
+ s_aztecKey = ::radMakeKey32( "aztec" );
+ s_milhouseKey = tEntity::MakeUID( "milhouse" );
+ s_nelsonKey = tEntity::MakeUID( "nelson" );
+ s_raceZombie1 = tEntity::MakeUID( "zmale3" );
+ s_raceZombie2 = tEntity::MakeUID( "zfem1" );
+
+ //
+ // Also do the tables of UIDs we use to identify peds and skins
+ //
+ for( i = 0; i < pedestrianTableLength; i++ )
+ {
+ pedestrianNameTable[i].pedUID = tEntity::MakeUID( pedestrianNameTable[i].pedName );
+ }
+
+ for( i = 0; i < PED_NUM_TYPES; i++ )
+ {
+ dialogGroupTable[i].pedUID = tEntity::MakeUID( dialogGroupTable[i].pedName );
+ }
+
+ for( i = 0; i < skinTableLength; i++ )
+ {
+ skinNameTable[i].skinUID = tEntity::MakeUID( skinNameTable[i].skinName );
+ }
+
+ for( i = 0; i < SKIN_NUM_TYPES; i++ )
+ {
+ skinDialogGroupTable[i].charUID = tEntity::MakeUID( skinDialogGroupTable[i].charName );
+ }
+
+ //
+ // Debug spew
+ //
+ radDbgWatchAddBoolean( &s_showDialogSpew, "Show Dialog Spew", "Sound Info" );
+ radDbgWatchAddFunction( "Print Dialog Coverage", &dumpDialogCoverage, this, "Sound Info" );
+ }
+}
+
+//==============================================================================
+// DialogList::~DialogList
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogList::~DialogList()
+{
+}
+
+//=============================================================================
+// DialogList::OrganizeDialog
+//=============================================================================
+// Description: Go through the list of dialog resources, creating SelectableDialog
+// objects organized as directed by the naming conventions.
+//
+// Parameters: namespaceObj -- object containing the list of dialog resources
+// as read from the script file
+//
+// Return: void
+//
+//=============================================================================
+void DialogList::OrganizeDialog( IRadNameSpace* namespaceObj )
+{
+ int mission;
+ int level;
+ IDaSoundResource* resource;
+ DialogLine* newLine;
+ ConversationMatcher matcher;
+ SelectableDialogList* dialogList;
+ SelectableDialog* foundDialog;
+
+ //
+ // Go through the list of sound resources looking for dialog
+ //
+ resource = reinterpret_cast< IDaSoundResource* >( namespaceObj->GetFirst( NULL) );
+ while( resource != NULL )
+ {
+ if( isIndividualLine( resource ) )
+ {
+ //
+ // Resource is dialog but not conversation. Create a DialogLine object
+ // to hold the information about it and store it in the appropriate list.
+ //
+#ifdef RAD_GAMECUBE
+ newLine = new( GMA_GC_VMM ) DialogLine( resource );
+#else
+ newLine = new( GMA_PERSISTENT ) DialogLine( resource );
+#endif
+ if( newLine->IsLevelSpecific() )
+ {
+ dialogList = &(m_missionLists[newLine->GetLevel() - 1][newLine->GetMission()]);
+ }
+ else
+ {
+ dialogList = &m_genericDialogList;
+ }
+
+ //
+ // Search the list. If we've already got a dialog for the same situation, lump
+ // this one in with it, otherwise stash it straight into the list
+ //
+ foundDialog = searchDialogList( newLine->GetEvent(), newLine->GetCharacterUID(), 0,
+ *dialogList, 0, newLine->IsVillainLine(), false );
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+ if( foundDialog != NULL )
+ {
+ foundDialog->AddMatchingDialog( *newLine, *dialogList );
+ }
+ else
+ {
+ dialogList->push_back( newLine );
+ }
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+ }
+ else if( isConversationLine( resource ) )
+ {
+ //
+ // Resource is part of a conversation. Give it to the object
+ // responsible for matching the pieces together
+ //
+ matcher.AddNewLine( resource );
+ }
+ //
+ // Otherwise, this isn't dialog, so we don't have to do anything with it
+ //
+
+ //
+ // Next resource in the list
+ //
+ resource = reinterpret_cast< IDaSoundResource* >( namespaceObj->GetNext( NULL) );
+ }
+
+ //
+ // Do a sanity check on the conversations
+ //
+ rAssert( matcher.AreAllConversationsComplete() );
+
+ //
+ // Add the completed conversations to the appropriate lists
+ //
+ for( level = 0; level < GameplayManager::MAX_LEVELS; level++ )
+ {
+ for( mission = 0; mission < GameplayManager::MAX_MISSIONS; mission++ )
+ {
+ matcher.AddConversationsToList( level + 1, mission, m_missionLists[level][mission] );
+ }
+ }
+
+ matcher.AddConversationsToList( SelectableDialog::NO_LEVEL, SelectableDialog::NO_MISSION, m_genericDialogList );
+}
+
+//=============================================================================
+// DialogList::FindDialogForEvent
+//=============================================================================
+// Description: Search through the dialog lists to find something appropriate
+// for the given dialog event
+//
+// Parameters: id - Event ID that we need to find dialog for
+// character1 - character who will say the dialog
+// character2 - if conversation, second character in conversation.
+// NULL otherwise.
+// charUID1 - if we're searching by UID, this is non-zero and
+// character1 and character2 are NULL.
+// charUID2 - second character, used for searching by UID
+// convKey - name of conversation, 0 if not applicable
+//
+// Return: Const pointer to SelectableDialog object best matching the
+// event, or NULL if nothing found
+//
+//=============================================================================
+SelectableDialog* DialogList::FindDialogForEvent( EventEnum id,
+ Character* character1,
+ Character* character2,
+ tUID charUID1,
+ tUID charUID2,
+ radKey32 convKey,
+ bool isVillain )
+{
+ int mission;
+ tUID char1UID;
+ tUID char2UID;
+ char nameBuffer[20];
+ unsigned int aztecNumber;
+ GameplayManager* gameplayMgr = NULL;
+ // For indexing purposes, levels count from zero.
+ int level;
+ SelectableDialog* dialogMatch = NULL;
+ Mission* missionObj;
+
+ if( GetGameFlow()->GetCurrentContext() == CONTEXT_FRONTEND )
+ {
+ //
+ // Playing dialog in front end, so any level will do
+ //
+ level = 0;
+ missionObj = NULL;
+ }
+ else
+ {
+ gameplayMgr = GetGameplayManager();
+ rAssert( gameplayMgr != NULL );
+
+ level = gameplayMgr->GetCurrentLevelIndex() - RenderEnums::L1;
+ missionObj = gameplayMgr->GetCurrentMission();
+ }
+
+ //
+ // First, search the list for the current mission. If it's a conversation
+ // event, those only happen during missions even if we're in Sunday Drive
+ // (they're the conversations that start the missions) so just start looking there.
+ //
+ if( missionObj != NULL )
+ {
+ if( ( !(gameplayMgr->IsSuperSprint()) )
+ && ( (!(missionObj->IsSundayDrive()) )
+ || ( id == EVENT_CONVERSATION_INIT_DIALOG )
+ || ( id == EVENT_TUTORIAL_DIALOG_PLAY ) ) )
+ {
+ if( id == EVENT_TUTORIAL_DIALOG_PLAY )
+ {
+ mission = DialogLine::TUTORIAL_MISSION_NUMBER;
+ }
+ else if( missionObj->IsBonusMission() )
+ {
+ mission = DialogLine::BONUS_MISSION_NUMBER;
+ }
+ else if( missionObj->IsRaceMission() )
+ {
+ mission = DialogLine::FIRST_RACE_MISSION_NUMBER +
+ ( gameplayMgr->GetCurrentMissionNum() - GameplayManager::MAX_MISSIONS );
+ }
+ else
+ {
+ if( convKey == s_introKey )
+ {
+ //
+ // Stinky race missions. The "intro" conversation happens before we've
+ // started the race. I can't rename them to simple L1, since characters like Homer
+ // have multiple C_intro_*_L1.rsd lines, so there's a naming clash. Ugh.
+ // To make matters worse, since some of these conversations involve only Homer (or
+ // whoever the driver is), we need to check if either character is Milhouse, Nelson,
+ // Ralph, or their zombie counterparts
+ //
+ rAssert( character1 != NULL );
+ rAssert( character2 != NULL );
+
+ char1UID = getPuppetUID( character1 );
+ char2UID = getPuppetUID( character2 );
+ if( ( char1UID == s_milhouseKey )
+ || ( char2UID == s_milhouseKey )
+ || ( char1UID == s_raceZombie1 )
+ || ( char2UID == s_raceZombie1 ) )
+ {
+ mission = DialogLine::FIRST_RACE_MISSION_NUMBER;
+ }
+ else if( ( char1UID == s_nelsonKey )
+ || ( char2UID == s_nelsonKey )
+ || ( char1UID == s_raceZombie2 )
+ || ( char2UID == s_raceZombie2 ) )
+ {
+ mission = DialogLine::FIRST_RACE_MISSION_NUMBER + 1;
+ }
+ else
+ {
+ //
+ // This had better be Ralph or zombie Ralph
+ //
+ mission = DialogLine::FIRST_RACE_MISSION_NUMBER + 2;
+ }
+ }
+ else if( level == 0 )
+ {
+ //
+ // Stinky level 1, tutorial mission screws everything up
+ //
+ mission = gameplayMgr->GetCurrentMissionIndex();
+ }
+ else
+ {
+ mission = gameplayMgr->GetCurrentMissionIndex() + 1;
+
+#ifdef RAD_E3
+ //
+ // E3 hack. L2M5 is our only mission, and it's going to
+ // come back as mission 1. Hack it to 5.
+ //
+ mission = 5;
+#endif
+ }
+
+ if ( convKey == s_aztecKey )
+ {
+ //
+ // Another stinky hack. The teen at the Aztec needs randomized conversations.
+ // Conversations don't really randomize because the conversation builder assumes
+ // that identically-named conversations result from misnamed files. And the
+ // key isn't a straightforward randomization on the caller's end, since it's
+ // a scripted value. I'll handle it here.
+ //
+ aztecNumber = ( rand() % 4 ) + 1;
+ sprintf( nameBuffer, "aztec%d", aztecNumber );
+ convKey = ::radMakeKey32( nameBuffer );
+ }
+ }
+
+ if( s_showDialogSpew )
+ {
+ rTuneString( "Searching mission-specific dialog\n" );
+ }
+
+ if( character1 == NULL )
+ {
+ // Already have UIDs
+ dialogMatch = searchDialogList( id, charUID1, charUID2, m_missionLists[level][mission], convKey, isVillain );
+ }
+ else
+ {
+ // Take UID from character objects
+ dialogMatch = searchDialogList( id, character1, character2, m_missionLists[level][mission], convKey, isVillain );
+ }
+ }
+ }
+
+ if( dialogMatch == NULL )
+ {
+ //
+ // No mission-specific dialog, search the level-specific stuff
+ //
+ if( s_showDialogSpew )
+ {
+ rTuneString( "Searching level-specific dialog\n" );
+ }
+
+ if( character1 == NULL )
+ {
+ dialogMatch = searchDialogList( id, charUID1, charUID2, m_missionLists[level][0], convKey, isVillain );
+ }
+ else
+ {
+ dialogMatch = searchDialogList( id, character1, character2, m_missionLists[level][0], convKey, isVillain );
+ }
+
+ if( dialogMatch == NULL )
+ {
+ //
+ // No mission- or level-specific dialog, search the generic list
+ //
+ if( s_showDialogSpew )
+ {
+ rTuneString( "Searching generic dialog\n" );
+ }
+
+ if( character1 == NULL )
+ {
+ dialogMatch = searchDialogList( id, charUID1, charUID2, m_genericDialogList, convKey, isVillain );
+ }
+ else
+ {
+ dialogMatch = searchDialogList( id, character1, character2, m_genericDialogList, convKey, isVillain );
+ }
+ }
+ }
+
+ return( dialogMatch );
+}
+
+//=============================================================================
+// DialogList::GetStinkySkinPointer
+//=============================================================================
+// Description: Given a UID, see if we can dig up a character for it looking
+// through all the possible skins.
+//
+// Parameters: charUID - tUID of character
+//
+// Return: Character* if match found, NULL otherwise
+//
+//=============================================================================
+Character* DialogList::GetStinkySkinPointer( tUID charUID )
+{
+ int skinType;
+ unsigned int i;
+ Character* charPtr;
+
+ for( skinType = 0; skinType < SKIN_NUM_TYPES; skinType++ )
+ {
+ if( skinDialogGroupTable[skinType].charUID == charUID )
+ {
+ break;
+ }
+ }
+
+ if( skinType == SKIN_NUM_TYPES )
+ {
+ //
+ // No skin exists for given character
+ //
+ return( NULL );
+ }
+
+ //
+ // At this point, the character has skins. Look for a match.
+ //
+ for( i = 0; i < skinTableLength; i++ )
+ {
+ if( skinNameTable[i].dialogGroup == skinType )
+ {
+ charPtr = GetCharacterManager()->GetCharacterByName( skinNameTable[i].skinUID );
+ if( charPtr != NULL )
+ {
+ return( charPtr );
+ }
+ }
+ }
+
+ //
+ // No skins found
+ //
+ return( NULL );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogList::hasOneLinerPrefix
+//=============================================================================
+// Description: Determines if resource name belongs to one-liner dialog. This
+// is deemed to be true if it starts with a valid role abbreviation.
+//
+// Parameters: name - name of resource
+//
+// Return: true if role field found, false otherwise
+//
+//=============================================================================
+bool DialogList::hasOneLinerPrefix( const char* name )
+{
+ return( ( name[1] == '_' )
+ && ( ( name[0] == 'W' )
+ || ( name[0] == 'D' )
+ || ( name[0] == 'P' )
+ || ( name[0] == 'V' ) ) );
+}
+
+//=============================================================================
+// DialogList::isIndividualLine
+//=============================================================================
+// Description: Test for whether given resource is a dialog one-liner
+//
+// Parameters: resource - sound resource to test
+//
+// Return: true if one-liner, false otherwise
+//
+//=============================================================================
+bool DialogList::isIndividualLine( IDaSoundResource* resource )
+{
+ char tempBuffer[FILENAME_BUFFER_LEN];
+ char buffer[FILENAME_BUFFER_LEN];
+
+ //
+ // Get the first filename belonging to the resource. Don't bother checking
+ // for >1 file---if they exist, then the names had better be interchangable.
+ //
+ tempBuffer[0] = '\0';
+ resource->GetFileNameAt( 0, tempBuffer, FILENAME_BUFFER_LEN );
+ rAssert( strlen( tempBuffer ) > 0 );
+
+ DialogLine::StripDirectoryCrud( tempBuffer, buffer, FILENAME_BUFFER_LEN );
+
+ //
+ // Simple test: we'll call it a line if it has at least two underscores
+ // and no "C_" prefix
+ //
+ return( ( !hasConversationPrefix( buffer ) )
+ && ( hasOneLinerPrefix( buffer ) )
+ && ( underscoreCount( buffer ) > 1 ) );
+}
+
+//=============================================================================
+// DialogList::isConversationLine
+//=============================================================================
+// Description: Test for whether given resource is part of a dialog
+// conversation
+//
+// Parameters: resource - sound resource to test
+//
+// Return: true if conversation line, false otherwise
+//
+//=============================================================================
+bool DialogList::isConversationLine( IDaSoundResource* resource )
+{
+ char tempBuffer[FILENAME_BUFFER_LEN];
+ char buffer[FILENAME_BUFFER_LEN];
+
+ //
+ // Get the first filename belonging to the resource. Don't bother checking
+ // for >1 file---if they exist, then the names had better be interchangable.
+ //
+ tempBuffer[0] = '\0';
+ resource->GetFileNameAt( 0, tempBuffer, FILENAME_BUFFER_LEN );
+ rAssert( strlen( tempBuffer ) > 0 );
+
+ DialogLine::StripDirectoryCrud( tempBuffer, buffer, FILENAME_BUFFER_LEN );
+
+ //
+ // Test: line belongs to conversation if it has at least three underscores
+ // and a "C_" prefix
+ //
+ return( hasConversationPrefix( buffer ) &&
+ ( underscoreCount( buffer ) > 3 ) );
+}
+
+//=============================================================================
+// DialogList::underscoreCount
+//=============================================================================
+// Description: Return number of underscores in the given string
+//
+// Parameters: name - string to count in
+//
+// Return: number of underscores found
+//
+//=============================================================================
+unsigned int DialogList::underscoreCount( const char* name )
+{
+ unsigned int i = 0;
+ unsigned int count = 0;
+
+
+ while( name[i] != '\0' )
+ {
+ if( name[i] == '_' )
+ {
+ ++count;
+ }
+
+ i++;
+ }
+
+ return( count );
+}
+
+//=============================================================================
+// DialogList::searchDialogList
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( EventEnum id, tUID characterUID1, tUID characterUID2, SelectableDialog* list )
+//
+// Return: SelectableDialog
+//
+//=============================================================================
+SelectableDialog* DialogList::searchDialogList( EventEnum id, Character* character1,
+ Character* character2, SelectableDialogList& list,
+ radKey32 convName, bool isVillain )
+{
+ tUID UID1 = 0;
+ tUID UID2 = 0;
+
+ if( character1 == NULL )
+ {
+ UID1 = 0;
+ }
+ else
+ {
+ //
+ // Can't just get the character UID, since they're not guaranteed to be consistent
+ // with the model you see on the screen. Need the skeleton UID, it appears
+ //
+ UID1 = getPuppetUID( character1 );
+ }
+
+ if( character2 == NULL )
+ {
+ UID2 = 0;
+ }
+ else
+ {
+ UID2 = getPuppetUID( character2 );
+ }
+
+ return( searchDialogList( id, UID1, UID2, list, convName, isVillain, true ) );
+}
+
+//=============================================================================
+// DialogList::searchDialogList
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( EventEnum id, tUID driverUID, SelectableDialogList& list )
+//
+// Return: SelectableDialog
+//
+//=============================================================================
+SelectableDialog* DialogList::searchDialogList( EventEnum id, tUID characterUID1,
+ tUID characterUID2,
+ SelectableDialogList& list,
+ radKey32 convName,
+ bool isVillain )
+{
+ return( searchDialogList( id, characterUID1, characterUID2, list, convName, isVillain, true ) );
+}
+
+//=============================================================================
+// DialogList::searchDialogList
+//=============================================================================
+// Description: Search the given list for a SelectableDialog object with the
+// given event ID.
+//
+// Parameters: id - event ID to find a match for
+// list - list to search
+//
+// Return: pointer to SelectableDialog object matching the event ID if
+// it exists, NULL otherwise
+//
+//=============================================================================
+SelectableDialog* DialogList::searchDialogList( EventEnum id, tUID characterUID1,
+ tUID characterUID2, SelectableDialogList& list,
+ radKey32 convName, bool isVillain, bool fuzzyPedMatch )
+{
+ char eventName[30];
+ char char1Name[30];
+ char char2Name[30];
+ char convBuffer[30];
+ char villain[3];
+ SelectableDialog* currentDialog;
+ SelectableDialogList::const_iterator iter = list.begin();
+ SelectableDialog* returnValue = NULL;
+
+ if( s_showDialogSpew )
+ {
+ //
+ // Print a message for the stuff we're trying to match with
+ //
+ DialogLine::FillEventName( eventName, 30, id );
+ DialogLine::FillCharacterName( char1Name, 30, characterUID1 );
+ DialogLine::FillCharacterName( char2Name, 30, characterUID2 );
+ if( convName != 0 )
+ {
+ sprintf( convBuffer, ", conv %d", convName );
+ }
+ else
+ {
+ convBuffer[0] = '\0';
+ }
+ if( isVillain )
+ {
+ villain[0] = 'V';
+ }
+ else
+ {
+ villain[0] = 'W';
+ }
+ villain[1] = '\0';
+ rTunePrintf( "Dialog: Looking for event %s, char1 %s, char2 %s %s %s\n",
+ eventName, char1Name, char2Name, villain, convBuffer );
+ }
+
+ for( ; iter != list.end(); ++iter )
+ {
+ currentDialog = *iter;
+
+ if( s_showDialogSpew )
+ {
+ //
+ // Print a message for the stuff we're currently looking at
+ //
+ DialogLine::FillEventName( eventName, 30, currentDialog->GetEvent() );
+ DialogLine::FillCharacterName( char1Name, 30, currentDialog->GetDialogLineCharacterUID( 1 ) );
+
+ if( currentDialog->GetNumDialogLines() > 1 )
+ {
+ DialogLine::FillCharacterName( char2Name, 30, currentDialog->GetDialogLineCharacterUID( 2 ) );
+ }
+ else
+ {
+ char2Name[0] = '-';
+ char2Name[1] = '\0';
+ }
+
+ if( convName != 0 )
+ {
+ sprintf( convBuffer, ", conv %d", currentDialog->GetConversationName() );
+ }
+ else
+ {
+ convBuffer[0] = '\0';
+ }
+
+ if( currentDialog->IsVillainLine() )
+ {
+ villain[0] = 'V';
+ }
+ else
+ {
+ villain[0] = 'W';
+ }
+ villain[1] = '\0';
+
+ rTunePrintf( "Dialog: Matching against event %s, char1 %s, char2 %s %s %s\n",
+ eventName, char1Name, char2Name, villain, convBuffer );
+ }
+
+ if( ( currentDialog->GetEvent() == id )
+ && ( currentDialog->IsVillainLine() == isVillain )
+ // If a conversation name is supplied, that has to match
+ && ( ( convName == 0 )
+ || ( currentDialog->GetConversationName() == convName ) ) )
+ {
+ if( currentDialog->GetNumDialogLines() == 1 )
+ {
+ //
+ // Match either character
+ //
+ if( characterMatches( characterUID1, currentDialog, fuzzyPedMatch )
+ || characterMatches( characterUID2, currentDialog, fuzzyPedMatch ) )
+ {
+ returnValue = currentDialog;
+ }
+ }
+ else
+ {
+ //
+ // Multi-line dialog. Match both.
+ //
+ if( characterMatches( characterUID1, currentDialog, fuzzyPedMatch )
+ && characterMatches( characterUID2, currentDialog, fuzzyPedMatch ) )
+ {
+ returnValue = currentDialog;
+ }
+ }
+
+ if( returnValue != NULL )
+ {
+ if( s_showDialogSpew )
+ {
+ rTunePrintf( "Dialog: Match found\n" );
+ }
+
+ //
+ // We're done
+ //
+ break;
+ }
+ }
+ }
+
+ return( returnValue );
+}
+
+//=============================================================================
+// DialogList::characterMatches
+//=============================================================================
+// Description: Determine whether the given dialog matches the character
+// given. UID of zero always matches.
+//
+// Parameters: characterObj - character to match
+// dialog - dialog to match to
+// fuzzyPedMatch - true if we want to fudge UIDs to group
+// pedestrians, false otherwise
+//
+// Return: true if match, false otherwise
+//
+//=============================================================================
+bool DialogList::characterMatches( tUID characterUID, SelectableDialog* dialog,
+ bool fuzzyPedMatch )
+{
+ unsigned int i;
+ tUID effectiveUID; // Unix humour. Nyuck!
+ pedDialogType dialogType;
+ bool switchMade = false;
+
+ if( characterUID == static_cast< tUID >( 0 ) )
+ {
+ return( false );
+ }
+
+ //
+ // Argh!! We have a whole bunch of pedestrian UIDs which need to be mapped
+ // to eight dialog characters. If this actually shows in a profiler, we'll
+ // need to mark the peds in the Character objects when they're spawned somehow
+ // to avoid this search
+ //
+
+ //
+ // Double argh!! Now we've got a bunch of character skins that are breaking
+ // the dialog system. We have to search for those as well.
+ //
+ effectiveUID = characterUID;
+
+ if( fuzzyPedMatch )
+ {
+ for( i = 0; i < pedestrianTableLength; i++ )
+ {
+ if( effectiveUID == static_cast< tUID >( pedestrianNameTable[i].pedUID ) )
+ {
+ //
+ // Is ped, map new UID
+ //
+
+ //
+ // Another hack: zombie1/2 and zombie3/4 should be randomly chosen.
+ // TODO: leave zombie3 as zombie3 for E3.
+ //
+ dialogType = pedestrianNameTable[i].dialogGroup;
+ if( ( dialogType == PED_ZOMBIE1 )
+ && ( dialog->GetEvent() != EVENT_CONVERSATION_INIT_DIALOG )
+ && ( dialog->GetEvent() != EVENT_IN_GAMEPLAY_CONVERSATION ) )
+ {
+ if( ( rand() % 2 ) == 0 )
+ {
+ dialogType = PED_ZOMBIE2;
+ }
+ }
+
+ effectiveUID = dialogGroupTable[dialogType].pedUID;
+ switchMade = true;
+ break;
+ }
+ }
+
+ if( !switchMade )
+ {
+ //
+ // Not a ped, check for skins
+ //
+ for( i = 0; i < skinTableLength; i++ )
+ {
+ if( effectiveUID == static_cast< tUID >( skinNameTable[i].skinUID ) )
+ {
+ //
+ // Is skin, map new UID
+ //
+ effectiveUID = skinDialogGroupTable[skinNameTable[i].dialogGroup].charUID;
+ break;
+ }
+ }
+ }
+ }
+
+ return( dialog->UsesCharacter( effectiveUID ) );
+}
+
+//=============================================================================
+// DialogList::getPuppetUID
+//=============================================================================
+// Description: Get UID for Choreo puppet for character
+//
+// Parameters: ( Character* characterPtr )
+//
+// Return: tUID if skeleton found, 0 otherwise
+//
+//=============================================================================
+tUID DialogList::getPuppetUID( Character* characterPtr )
+{
+ const char* modelName;
+ rAssert( characterPtr != NULL );
+
+ modelName = GetCharacterManager()->GetModelName( characterPtr );
+ if( modelName != NULL )
+ {
+ return( tEntity::MakeUID( modelName ) );
+ }
+ else
+ {
+ return( 0 );
+ }
+}
+
+void DialogList::dumpDialogCoverage( void* userData )
+{
+#ifndef RAD_RELEASE
+ SelectableDialogList::const_iterator iter;
+ int i, j;
+ SelectableDialog* currentDialog;
+ char eventName[30];
+ char char1Name[30];
+ char char2Name[30];
+ char convBuffer[30];
+ DialogList* listObj = static_cast<DialogList*>(userData);
+
+ for( i = 0; i < GameplayManager::MAX_LEVELS; i++ )
+ {
+ for( j = 0; j < GameplayManager::MAX_MISSIONS+1; j++ )
+ {
+ rTunePrintf( "\nDialogue for level %d mission %d list\n", i, j );
+
+ iter = listObj->m_missionLists[i][j].begin();
+ for( ; iter != listObj->m_missionLists[i][j].end(); ++iter )
+ {
+ currentDialog = *iter;
+ if( currentDialog != NULL )
+ {
+ DialogLine::FillEventName( eventName, 30, currentDialog->GetEvent() );
+ DialogLine::FillCharacterName( char1Name, 30, currentDialog->GetDialogLineCharacterUID( 1 ) );
+
+ if( currentDialog->GetNumDialogLines() > 1 )
+ {
+ DialogLine::FillCharacterName( char2Name, 30, currentDialog->GetDialogLineCharacterUID( 2 ) );
+ }
+ else
+ {
+ char2Name[0] = '-';
+ char2Name[1] = '\0';
+ }
+
+ sprintf( convBuffer, ", conv %d", currentDialog->GetConversationName() );
+
+ rTunePrintf( "Dialog: Event %s, char1 %s, char2 %s%s : ",
+ eventName, char1Name, char2Name, convBuffer );
+ currentDialog->PrintPlayedStatus();
+ }
+ }
+ }
+ }
+
+ rTuneString( "\nGeneric dialogue list:\n" );
+
+ iter = listObj->m_genericDialogList.begin();
+ for( ; iter != listObj->m_genericDialogList.end(); ++iter )
+ {
+ currentDialog = *iter;
+ if( currentDialog != NULL )
+ {
+ DialogLine::FillEventName( eventName, 30, currentDialog->GetEvent() );
+ DialogLine::FillCharacterName( char1Name, 30, currentDialog->GetDialogLineCharacterUID( 1 ) );
+
+ if( currentDialog->GetNumDialogLines() > 1 )
+ {
+ DialogLine::FillCharacterName( char2Name, 30, currentDialog->GetDialogLineCharacterUID( 2 ) );
+ }
+ else
+ {
+ char2Name[0] = '-';
+ char2Name[1] = '\0';
+ }
+
+ sprintf( convBuffer, ", conv %d", currentDialog->GetConversationName() );
+
+ rTunePrintf( "Dialog: Event %s, char1 %s, char2 %s%s : ",
+ eventName, char1Name, char2Name, convBuffer );
+ currentDialog->PrintPlayedStatus();
+ }
+ }
+
+#endif
+} \ No newline at end of file
diff --git a/game/code/sound/dialog/dialoglist.h b/game/code/sound/dialog/dialoglist.h
new file mode 100644
index 0000000..54692b0
--- /dev/null
+++ b/game/code/sound/dialog/dialoglist.h
@@ -0,0 +1,109 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialoglist.h
+//
+// Description: Loads and maintains the list of dialog lines and conversations
+// (which group multiple dialog lines, and potentially link
+// conversations to other conversations that occur later).
+//
+// History: 01/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGLIST_H
+#define DIALOGLIST_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <mission/gameplaymanager.h>
+#include <events/eventenum.h>
+#include <sound/dialog/selectabledialoglist.h>
+
+//========================================
+// Forward References
+//========================================
+struct IRadNameSpace;
+struct IDaSoundResource;
+class SelectableDialog;
+class Character;
+
+//=============================================================================
+//
+// Synopsis: DialogList
+//
+//=============================================================================
+
+class DialogList
+{
+ public:
+ DialogList();
+ virtual ~DialogList();
+
+ void OrganizeDialog( IRadNameSpace* namespaceObj );
+
+ SelectableDialog* FindDialogForEvent( EventEnum id, Character* character1, Character* character2,
+ tUID charUID1, tUID charUID2, radKey32 convKey, bool isVillain );
+
+ static Character* GetStinkySkinPointer( tUID charUID );
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogList( const DialogList& original );
+ DialogList& operator=( const DialogList& rhs );
+
+ //
+ // Sound file naming convention tests
+ //
+ bool isIndividualLine( IDaSoundResource* resource );
+ bool isConversationLine( IDaSoundResource* resource );
+
+ bool hasConversationPrefix( const char* name )
+ { return( ( name[0] == 'C' ) && ( name[1] == '_' ) ); }
+ bool hasOneLinerPrefix( const char* name );
+ unsigned int underscoreCount( const char* name );
+
+ SelectableDialog* searchDialogList( EventEnum id, tUID characterUID1, tUID characterUID2,
+ SelectableDialogList& list, radKey32 convName, bool isVillain,
+ bool fuzzyPedMatch );
+
+ SelectableDialog* searchDialogList( EventEnum id, tUID characterUID1, tUID characterUID2,
+ SelectableDialogList& list, radKey32 convName, bool isVillain );
+
+ SelectableDialog* searchDialogList( EventEnum id, Character* character1,
+ Character* character2, SelectableDialogList& list,
+ radKey32 convName, bool isVillain );
+
+ bool characterMatches( tUID characterUID, SelectableDialog* dialog, bool fuzzyPedMatch );
+
+ tUID getPuppetUID( Character* characterPtr );
+
+ static void dumpDialogCoverage( void* userData );
+
+ //
+ // List of level/mission dialogs
+ //
+ SelectableDialogList m_missionLists[GameplayManager::MAX_LEVELS][GameplayManager::MAX_MISSIONS+1];
+
+ //
+ // Generic dialog list
+ //
+ SelectableDialogList m_genericDialogList;
+
+ static radKey32 s_introKey;
+ static radKey32 s_aztecKey;
+ static tUID s_milhouseKey;
+ static tUID s_nelsonKey;
+ static tUID s_raceZombie1;
+ static tUID s_raceZombie2;
+
+ //
+ // Debug flag
+ //
+ static bool s_showDialogSpew;
+};
+
+
+#endif // DIALOGLIST_H
+
diff --git a/game/code/sound/dialog/dialogpriorityqueue.cpp b/game/code/sound/dialog/dialogpriorityqueue.cpp
new file mode 100644
index 0000000..5a57510
--- /dev/null
+++ b/game/code/sound/dialog/dialogpriorityqueue.cpp
@@ -0,0 +1,536 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogpriorityqueue.cpp
+//
+// Description: Responsible for managing the outstanding dialog playback requests.
+// When the DialogCoordinator needs to play dialog, it hands the
+// PlayableDialog object off, and the DialogPriorityQueue determines
+// if it can be played, or if it should wait until some other dialog
+// completes. When a PlayableDialog is ready for playback, it gets
+// handed to the SimpsonsSoundPlayer.
+//
+// History: 04/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radtime.hpp>
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogpriorityqueue.h>
+
+#include <sound/dialog/dialogqueueelement.h>
+#include <sound/dialog/selectabledialog.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundmanager.h>
+
+#include <memory/srrmemory.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Probability of optional play success as chance in 256
+//
+static const unsigned int OPL_PROB = 64;
+
+//#define DEBUG_QUEUE_REFCOUNT
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogPriorityQueue::DialogPriorityQueue
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogPriorityQueue::DialogPriorityQueue() :
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ m_debugPage( 3, GetSoundManager()->GetDebugDisplay() ),
+#endif
+ m_nowPlaying( NULL ),
+ m_permitQueueAdvance( true )
+{
+}
+
+//==============================================================================
+// DialogPriorityQueue::~DialogPriorityQueue
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogPriorityQueue::~DialogPriorityQueue()
+{
+}
+
+//=============================================================================
+// DialogPriorityQueue::AddDialogToQueue
+//=============================================================================
+// Description: Place dialog on queue and play if possible
+//
+// Parameters: dialog - dialog to add to queue
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::AddDialogToQueue( SelectableDialog& dialog, rmt::Vector* posn )
+{
+ DialogPriority priority;
+ DialogQueueElement* queueElement;
+ unsigned int diceRoll;
+
+ //
+ // Check the priority on the dialog, and use it to find the appropriate
+ // spot in the queue.
+ //
+ priority = DialogQueueElement::CalculateDialogPriority( dialog );
+
+ if( priority == OccasionalPlayLine )
+ {
+ //
+ // Random play
+ //
+ diceRoll = ( rand() % 100 );
+ if( diceRoll >= DialogQueueElement::CalculateDialogProbability( dialog ) )
+ {
+ return;
+ }
+ }
+
+ //
+ // Ducking for dialog
+ //
+ if( m_nowPlaying == NULL )
+ {
+ Sound::daSoundRenderingManager::GetInstance()->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_DIALOG, NULL, false );
+ GetSoundManager()->MuteNISPlayers();
+ }
+
+ //
+ // Don't bother playing dialog if we're already playing the same thing.
+ // This can happen with collision events that get triggered zillions of
+ // times
+ //
+ if( ( m_nowPlaying == NULL )
+ || !( m_nowPlaying->DialogMatches( &dialog ) ) )
+ {
+ queueElement = new ( GMA_TEMP ) DialogQueueElement( &dialog );
+
+ if( priority == MustPlayImmediately )
+ {
+ //
+ // Special case. Place this guy at the head of the queue and kill
+ // whatever's playing right now.
+ //
+ if( m_nowPlaying )
+ {
+ //
+ // If we don't halt the dialog queue, the stop callback will advance
+ // it on us and we get two dialog lines
+ //
+ m_permitQueueAdvance = false;
+
+ m_nowPlaying->StopDialog();
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "AddDialogToQueue %x: Count %d\n", m_nowPlaying, m_nowPlaying->GetRefCount() );
+#endif
+ //
+ // One more check. The StopDialog() above may already have made m_nowPlaying
+ // go away
+ //
+ if( m_nowPlaying != NULL )
+ {
+ m_nowPlaying->Release();
+ }
+
+ m_permitQueueAdvance = true;
+ }
+
+ m_nowPlaying = queueElement;
+ playDialog( posn );
+ }
+ else
+ {
+ //
+ // Stick it in the list
+ //
+ queueElement->AddToQueue( &m_dialogQueue, posn );
+ }
+ }
+
+#ifndef RAD_RELEASE
+ //
+ // Mark dialog as played for coverage testing purposes
+ //
+ dialog.MarkAsPlayed();
+#endif
+}
+
+//=============================================================================
+// DialogPriorityQueue::StopCurrentDialog
+//=============================================================================
+// Description: If we have something playing, stop it and yank it off the
+// queue
+//
+// Parameters: None
+//
+// Return: true if there was dialog to stop, false otherwise
+//
+//=============================================================================
+bool DialogPriorityQueue::StopCurrentDialog()
+{
+ bool dialogStopped = false;
+
+ if( m_nowPlaying )
+ {
+ //
+ // Stop it and let the callback do the rest
+ //
+ m_nowPlaying->StopDialog();
+ dialogStopped = true;
+ }
+
+ return( dialogStopped );
+}
+
+//=============================================================================
+// DialogPriorityQueue::StopAllDialog
+//=============================================================================
+// Description: Kill the queue. This'll most likely be done when gameplay
+// ends.
+//
+// Parameters: None
+//
+// Return: true if there was dialog to stop, false otherwise
+//
+//=============================================================================
+bool DialogPriorityQueue::StopAllDialog()
+{
+ DialogQueueElement* current;
+ bool dialogStopped = false;
+
+ //
+ // Just in case we're still in a paused state. Stopping paused dialogue doesn't
+ // seem to give us our stop callbacks
+ //
+ UnpauseDialog();
+
+ m_permitQueueAdvance = false;
+
+ while( !m_dialogQueue.empty() )
+ {
+ current = m_dialogQueue.front();
+ current->RemoveSelfFromList();
+ current->Release();
+ }
+
+ if( m_nowPlaying != NULL )
+ {
+ m_nowPlaying->StopDialog();
+
+ //
+ // Check again to make sure that the dialog didn't remove itself.
+ // Since the queue was emptied first, nothing else should replace
+ // the currently playing dialog afterward.
+ //
+ if( m_nowPlaying != NULL )
+ {
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "StopAllDialog %x: Count %d\n", m_nowPlaying, m_nowPlaying->GetRefCount() );
+#endif
+ m_nowPlaying->Release();
+ m_nowPlaying = NULL;
+
+ Sound::daSoundRenderingManager::GetInstance()->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_DIALOG, NULL, true );
+ GetSoundManager()->UnmuteNISPlayers();
+ }
+
+ dialogStopped = true;
+ }
+
+ m_permitQueueAdvance = true;
+
+ //
+ // Since we don't seem to get the OnPlaybackComplete callback for the queue
+ // element, throw a couple of shutup events in case someone was mouth flapping
+ //
+ GetEventManager()->TriggerEvent( EVENT_PC_SHUTUP );
+ GetEventManager()->TriggerEvent( EVENT_NPC_SHUTUP );
+
+ return( dialogStopped );
+}
+
+//=============================================================================
+// DialogPriorityQueue::PauseDialog
+//=============================================================================
+// Description: Pause the dialog players
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::PauseDialog()
+{
+ m_player1.Pause();
+ m_player2.Pause();
+ m_positionalPlayer1.Pause();
+ m_positionalPlayer2.Pause();
+}
+
+//=============================================================================
+// DialogPriorityQueue::UnpauseDialog
+//=============================================================================
+// Description: Unpause the dialog players
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::UnpauseDialog()
+{
+ if( m_player1.IsPaused() )
+ {
+ m_player1.Continue();
+ }
+ if( m_player2.IsPaused() )
+ {
+ m_player2.Continue();
+ }
+ if( m_positionalPlayer1.IsPaused() )
+ {
+ m_positionalPlayer1.Continue();
+ }
+ if( m_positionalPlayer2.IsPaused() )
+ {
+ m_positionalPlayer2.Continue();
+ }
+}
+
+//=============================================================================
+// DialogPriorityQueue::OnDialogLineComplete
+//=============================================================================
+// Description: Called when a line of dialog in the currently playing
+// conversation is complete
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::OnDialogLineComplete()
+{
+ //
+ // TODO: Stop the mouth flapping and eye blinking
+ //
+}
+
+//=============================================================================
+// DialogPriorityQueue::OnDialogComplete
+//=============================================================================
+// Description: Called when the currently playing SelectableDialog is
+// complete
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::OnDialogComplete()
+{
+ //
+ // TODO: Stop the mouth flapping and eye blinking
+ //
+
+ //
+ // Get rid of the currently playing element
+ //
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "OnDialogComplete %x: Count %d\n", m_nowPlaying, m_nowPlaying->GetRefCount() );
+#endif
+ m_nowPlaying->Release();
+ if( !m_dialogQueue.empty() && m_permitQueueAdvance )
+ {
+ m_nowPlaying = m_dialogQueue.front();
+ m_nowPlaying->RemoveSelfFromList();
+ playDialog( m_nowPlaying->GetPosition() );
+ }
+ else
+ {
+ m_nowPlaying = NULL;
+
+ Sound::daSoundRenderingManager::GetInstance()->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_DIALOG, NULL, true );
+ GetSoundManager()->UnmuteNISPlayers();
+ }
+}
+
+//=============================================================================
+// DialogPriorityQueue::Service
+//=============================================================================
+// Description: Do servicing stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::ServiceOncePerFrame()
+{
+ DialogQueueElement::Service();
+
+ //
+ // Just to be safe, don't update the positional players here. The update
+ // function just does stuff for moving sounds and pausing out-of-range
+ // stuff, none of which applies here. It's theoretically safe to do the
+ // right thing and service these players, but we're way too close to final
+ // to change the status quo.
+ //
+ //m_positionalPlayer1.ServiceOncePerFrame();
+ //m_positionalPlayer2.ServiceOncePerFrame();
+
+ advanceQueue();
+
+ serviceDebugPage();
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogPriorityQueue::advanceQueue
+//=============================================================================
+// Description: Advance the queue if non-empty and nothing's playing.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::advanceQueue()
+{
+ if( ( m_nowPlaying == NULL ) && ( !m_dialogQueue.empty() ) && m_permitQueueAdvance )
+ {
+ m_nowPlaying = m_dialogQueue.front();
+ m_nowPlaying->RemoveSelfFromList();
+ playDialog( m_nowPlaying->GetPosition() );
+ }
+}
+
+//=============================================================================
+// DialogPriorityQueue::playDialog
+//=============================================================================
+// Description: Start a dialog line playing with the correct players
+//
+// Parameters: posn - position of speaker for positional dialogue. NULL
+// if non-positional
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::playDialog( rmt::Vector* posn )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+
+ if( posn != NULL )
+ {
+ //
+ // Before starting playback, set up the positional stuff
+ //
+ //
+ // Get the positionalSoundSettings object for the wasp sound
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( ::radMakeKey32( "posn_dialog_settings" ) );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+ m_positionalPlayer1.SetParameters( parameters );
+
+ m_positionalPlayer1.SetPosition( posn->x, posn->y, posn->z );
+
+ m_nowPlaying->PlayDialog( m_positionalPlayer1, m_positionalPlayer2, this, this );
+ }
+ else
+ {
+ rTuneAssertMsg( false, "No min/max for positional dialogue? Bad, call Esan." );
+
+ //
+ // Handle gracefully in release
+ //
+ m_nowPlaying->PlayDialog( m_player1, m_player2, this, this );
+ }
+ }
+ else
+ {
+ m_nowPlaying->PlayDialog( m_player1, m_player2, this, this );
+ }
+}
+
+//=============================================================================
+// DialogPriorityQueue::serviceDebugPage
+//=============================================================================
+// Description: Update the SoundInfo data available in Watcher
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogPriorityQueue::serviceDebugPage()
+{
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ int i;
+ int queueLength;
+ DialogQueueType::const_iterator iter;
+
+ if( m_nowPlaying != NULL )
+ {
+ //
+ // For the debug page, nowPlaying is part of the queue
+ //
+ queueLength = m_dialogQueue.size() + 1;
+ m_debugPage.SetQueueLength( queueLength );
+
+ m_nowPlaying->FillDebugInfo( m_debugPage, 0 );
+ i = 1;
+ for( iter = m_dialogQueue.begin(); iter != m_dialogQueue.end(); ++iter )
+ {
+ (*iter)->FillDebugInfo( m_debugPage, i++ );
+ }
+ }
+ else
+ {
+ m_debugPage.SetQueueLength( 0 );
+ }
+#endif
+}
diff --git a/game/code/sound/dialog/dialogpriorityqueue.h b/game/code/sound/dialog/dialogpriorityqueue.h
new file mode 100644
index 0000000..7ef5cfe
--- /dev/null
+++ b/game/code/sound/dialog/dialogpriorityqueue.h
@@ -0,0 +1,99 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogpriorityqueue.h
+//
+// Description: Responsible for managing the outstanding dialog playback requests.
+// When the DialogCoordinator needs to play dialog, it hands the
+// PlayableDialog object off, and the DialogPriorityQueue determines
+// if it can be played, or if it should wait until some other dialog
+// completes. When a PlayableDialog is ready for playback, it gets
+// handed to the SimpsonsSoundPlayer.
+//
+// History: 04/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGPRIORITYQUEUE_H
+#define DIALOGPRIORITYQUEUE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/simpsonssoundplayer.h>
+#include <sound/positionalsoundplayer.h>
+#include <sound/dialog/dialogqueueelement.h>
+#include <sound/dialog/dialogqueuetype.h>
+#include <sound/dialog/dialogsounddebugpage.h>
+
+//========================================
+// Forward References
+//========================================
+class SelectableDialog;
+
+//=============================================================================
+//
+// Synopsis: DialogPriorityQueue
+//
+//=============================================================================
+
+class DialogPriorityQueue : public DialogLineCompleteCallback,
+ public DialogCompleteCallback
+{
+ public:
+ DialogPriorityQueue();
+ virtual ~DialogPriorityQueue();
+
+ void AddDialogToQueue( SelectableDialog& dialog, rmt::Vector* posn = NULL );
+
+ bool StopCurrentDialog();
+ bool StopAllDialog();
+
+ void PauseDialog();
+ void UnpauseDialog();
+
+ void OnDialogLineComplete();
+ void OnDialogComplete();
+
+ void ServiceOncePerFrame();
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogPriorityQueue( const DialogPriorityQueue& original );
+ DialogPriorityQueue& operator=( const DialogPriorityQueue& rhs );
+
+ void advanceQueue();
+ void serviceDebugPage();
+ void playDialog( rmt::Vector* posn );
+
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ DialogSoundDebugPage m_debugPage;
+#endif
+
+ //
+ // Dialog sound players. Two needed so that we can queue up a second
+ // line while the first is playing.
+ //
+ SimpsonsSoundPlayer m_player1;
+ SimpsonsSoundPlayer m_player2;
+
+ PositionalSoundPlayer m_positionalPlayer1;
+ PositionalSoundPlayer m_positionalPlayer2;
+
+ //
+ // Points to whatever's playing right this instant. Stored separately
+ // from the waiting queue objects.
+ //
+ DialogQueueElement* m_nowPlaying;
+
+ //
+ // The queue
+ //
+ DialogQueueType m_dialogQueue;
+
+ bool m_permitQueueAdvance;
+};
+
+
+#endif // DIALOGPRIORITYQUEUE_H
+
diff --git a/game/code/sound/dialog/dialogqueueelement.cpp b/game/code/sound/dialog/dialogqueueelement.cpp
new file mode 100644
index 0000000..047b626
--- /dev/null
+++ b/game/code/sound/dialog/dialogqueueelement.cpp
@@ -0,0 +1,951 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogqueueelement.cpp
+//
+// Description: Implement DialogQueueElement
+//
+// History: 04/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radtime.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogqueueelement.h>
+
+#include <sound/dialog/selectabledialog.h>
+#include <sound/dialog/dialogsounddebugpage.h>
+#include <sound/dialog/dialogline.h>
+#include <sound/dialog/dialoglist.h>
+
+#include <memory/srrmemory.h>
+#include <events/eventmanager.h>
+#include <worldsim/avatarmanager.h>
+#include <worldsim/character/charactermanager.h>
+
+//#define DEBUG_QUEUE_REFCOUNT
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+IRadTimerList* DialogQueueElement::s_timerList = NULL;
+bool DialogQueueElement::s_watcherInitialized = false;
+
+struct LinePriorityTableEntry
+{
+ EventEnum eventID;
+ DialogPriority priority;
+ unsigned int probability;
+#ifndef RAD_RELEASE
+ const char* eventName;
+#endif
+};
+
+LinePriorityTableEntry priorityTable[] =
+{
+ { EVENT_GETINTOVEHICLE_START, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "GIC"
+#endif
+ },
+ { EVENT_BURNOUT, OccasionalPlayLine, 15
+#ifndef RAD_RELEASE
+ , "Burn"
+#endif
+ },
+ { EVENT_DESTINATION_REACHED, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Arrive"
+#endif
+ },
+ { EVENT_BIG_AIR, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Air"
+#endif
+ },
+ { EVENT_BIG_CRASH, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Damage"
+#endif
+ },
+ { EVENT_GETOUTOFVEHICLE_START, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "GOC"
+#endif
+ },
+ { EVENT_RACE_PASSED_AI, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Pass"
+#endif
+ },
+ { EVENT_RACE_GOT_PASSED_BY_AI, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Passed"
+#endif
+ },
+ { EVENT_KICK_NPC_SOUND, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "HitByW"
+#endif
+ },
+ { EVENT_PLAYER_CAR_HIT_NPC, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "HitByC"
+#endif
+ },
+ { EVENT_PEDESTRIAN_DODGE, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "NHitByC"
+#endif
+ },
+ { EVENT_PLAYER_MAKES_LIGHT_OF_CAR_HITTING_NPC, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "HitP"
+#endif
+ },
+ { EVENT_PEDESTRIAN_SMACKDOWN, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Char"
+#endif
+ },
+ { EVENT_MINOR_VEHICLE_CRASH, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Mcrash"
+#endif
+ },
+ { EVENT_TRAFFIC_IMPEDED, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "CarWay"
+#endif
+ },
+ { EVENT_HIT_BREAKABLE, OccasionalPlayLine, 20
+#ifndef RAD_RELEASE
+ , "Break"
+#endif
+ },
+ { EVENT_COLLECT_OBJECT, OccasionalPlayLine, 50
+#ifndef RAD_RELEASE
+ , "ObjectW"
+#endif
+ },
+ { EVENT_BIG_BOOM_SOUND, ShouldPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Dcar"
+#endif
+ },
+ { EVENT_MISSION_FAILURE, ShouldPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Mfail"
+#endif
+ },
+ { EVENT_TAIL_LOST_DIALOG, ShouldPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Tail"
+#endif
+ },
+ { EVENT_MISSION_SUCCESS_DIALOG, ShouldPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Mvic"
+#endif
+ },
+ { EVENT_CARD_COLLECTED, MustPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Card"
+#endif
+ },
+ { EVENT_PHONE_BOOTH_RIDE_REQUEST, MustPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Askride"
+#endif
+ },
+ { EVENT_PHONE_BOOTH_NEW_VEHICLE_SELECTED, MustPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Ridereply"
+#endif
+ },
+ { EVENT_PHONE_BOOTH_OLD_VEHICLE_RESELECTED, MustPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Answer"
+#endif
+ },
+ { EVENT_MISSION_BRIEFING_ACCEPTED, MustPlayLine, 100
+#ifndef RAD_RELEASE
+ , "Mstart"
+#endif
+ },
+ { EVENT_CONVERSATION_INIT_DIALOG, MustPlayImmediately, 100
+#ifndef RAD_RELEASE
+ , "EVENT_CONVERSATION_INIT_DIALOG"
+#endif
+ },
+ { EVENT_IN_GAMEPLAY_CONVERSATION, MustPlayImmediately, 100
+#ifndef RAD_RELEASE
+ , "EVENT_IN_GAMEPLAY_CONVERSATION"
+#endif
+ },
+ { EVENT_TUTORIAL_DIALOG_PLAY, MustPlayImmediately, 100
+#ifndef RAD_RELEASE
+ , "EVENT_TUTORIAL_DIALOG_PLAY"
+#endif
+ },
+ { EVENT_DING_DONG, MustPlayImmediately, 100
+#ifndef RAD_RELEASE
+ , "EVENT_DING_DONG"
+#endif
+ }
+};
+
+static unsigned int priorityTableLength = sizeof( priorityTable ) / sizeof( LinePriorityTableEntry );
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogQueueElement::DialogQueueElement
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogQueueElement::DialogQueueElement( SelectableDialog* dialog ) :
+ m_dialog( dialog ),
+ m_player1( NULL ),
+ m_player2( NULL ),
+ m_lineDoneCallback( NULL ),
+ m_dialogDoneCallback( NULL ),
+ m_linesPlayed( 0 ),
+ m_queue( NULL ),
+ m_hasPosition( false )
+{
+ unsigned int lifeInMsecs;
+
+ rAssert( m_dialog != NULL );
+
+ if( s_timerList == NULL )
+ {
+ //
+ // We need enough timers for each element in the queue, plus one for
+ // currently playing dialog and one to create before we test for the
+ // queue being full. Actually, we don't really need one for current
+ // dialog, but we'll call that safety margin.
+ //
+ ::radTimeCreateList( &s_timerList, MAX_QUEUE_ELEMENTS + 2, GMA_AUDIO_PERSISTENT );
+ }
+
+ m_timer = NULL;
+
+ lifeInMsecs = DialogLine::GetLifeInMsecsForEvent( dialog->GetEvent() );
+
+ if( lifeInMsecs > 0 )
+ {
+ s_timerList->CreateTimer( &m_timer,
+ lifeInMsecs,
+ this,
+ NULL,
+ true,
+ IRadTimer::ResetModeOneShot );
+ rAssert( m_timer != NULL );
+ }
+}
+
+//==============================================================================
+// DialogQueueElement::~DialogQueueElement
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogQueueElement::~DialogQueueElement()
+{
+ if( m_timer )
+ {
+ m_timer->UnregisterCallback( this );
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "~DialogQueueElement Timer: %d\n", m_timer->GetRefCount() );
+#endif
+ m_timer->Release();
+ }
+}
+
+//=============================================================================
+// DialogQueueElement::OnTimerDone
+//=============================================================================
+// Description: If the timer goes off and calls this function, then the
+// lifetime for the dialog has expired and we need to excuse
+// ourselves from the queue.
+//
+// Parameters: elapsedTime - ignored
+// pUserData - ignored
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::OnTimerDone( unsigned int elapsedTime, void * pUserData )
+{
+ RemoveSelfFromList();
+
+ //
+ // We're now expendable. Delete self.
+ //
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "OnTimerDone %x: Count %d\n", this, GetRefCount() );
+#endif
+ Release();
+}
+
+//=============================================================================
+// DialogQueueElement::AddToQueue
+//=============================================================================
+// Description: Add self to the given dialog queue
+//
+// Parameters: queue - queue to add self to
+// posn - position of dialog speaker, NULL if non-positional
+//
+// Return: none
+//
+//=============================================================================
+void DialogQueueElement::AddToQueue( DialogQueueType* queue, rmt::Vector* posn )
+{
+ DialogQueueElement* lowerPriorityElement;
+ bool duplicateFound = false;
+ DialogPriority priority = CalculateDialogPriority( *m_dialog );
+
+ rAssert( queue != NULL );
+ m_queue = queue;
+
+ if( posn != NULL )
+ {
+ m_hasPosition = true;
+ m_position = *posn;
+ }
+ else
+ {
+ m_hasPosition = false;
+ }
+
+ if( m_queue->empty() )
+ {
+ m_queue->push_front( this );
+ }
+ else
+ {
+ DialogQueueType::iterator iter = m_queue->begin();
+
+ //
+ // Search the rest of the list to see if we've already got this
+ // dialog in it. It couldn't have been passed over yet because
+ // all the earlier stuff has a higher priority
+ //
+ for( ; iter != m_queue->end(); ++iter )
+ {
+ if( (*iter)->DialogMatches( m_dialog ) )
+ {
+ duplicateFound = true;
+ break;
+ }
+ }
+
+ if( !duplicateFound )
+ {
+ if( m_queue->size() >= MAX_QUEUE_ELEMENTS )
+ {
+ //
+ // Dialog full, something has to go. Ditch the lowest priority
+ // one. If that's the one we're inserting, don't do it. If there's
+ // a lower-priority one in the queue, ditch that one instead.
+ //
+ if( iter == m_queue->end() )
+ {
+ //
+ // Nothing lower
+ //
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "AddToQueue %x: Count %d\n", this, GetRefCount() );
+#endif
+ Release();
+ }
+ else
+ {
+ lowerPriorityElement = *iter;
+ m_queue->insert( iter, this );
+ m_queue->remove( lowerPriorityElement );
+ lowerPriorityElement->Release();
+ }
+ }
+ else
+ {
+ //
+ // Find spot to insert based on priority
+ //
+ iter = m_queue->begin();
+ while( ( iter != m_queue->end() )
+ && ( (*iter)->GetPriority() >= priority ) )
+ {
+ ++iter;
+ }
+
+ m_queue->insert( iter, this );
+ }
+ }
+ else
+ {
+ //
+ // No need to add this to the queue, and the caller is now relying
+ // on this object for self-management, so delete self
+ //
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "AddToQueue %x: Count %d\n", this, GetRefCount() );
+#endif
+ Release();
+ }
+ }
+}
+
+//=============================================================================
+// DialogQueueElement::RemoveSelfFromList
+//=============================================================================
+// Description: Pull ourself from the queue element list
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::RemoveSelfFromList()
+{
+ rAssert( m_queue != NULL );
+
+ m_queue->remove( this );
+}
+
+//=============================================================================
+// DialogQueueElement::GetDialogPriority
+//=============================================================================
+// Description: Searches the priority table for a priority matching the event
+// ID for this bit of dialog.
+//
+// Parameters: dialog - dialog to find priority for
+//
+// Return: DialogPriority value for dialog if found in table,
+// UnknownPriority otherwise.
+//
+//=============================================================================
+DialogPriority DialogQueueElement::CalculateDialogPriority( const SelectableDialog& dialog )
+{
+ EventEnum eventID;
+ unsigned int i;
+ DialogPriority priority = UnknownPriority;
+
+ eventID = dialog.GetEvent();
+ for( i = 0; i < priorityTableLength; i++ )
+ {
+ if( priorityTable[i].eventID == eventID )
+ {
+ priority = priorityTable[i].priority;
+ break;
+ }
+ }
+
+ return( priority );
+}
+
+//=============================================================================
+// DialogQueueElement::CalculateDialogProbability
+//=============================================================================
+// Description: Searches the priority table for a probability matching the event
+// ID for this bit of dialog.
+//
+// Parameters: dialog - dialog to find priority for
+//
+// Return: Probability as % for dialog if found in table,
+// 100 otherwise.
+//
+//=============================================================================
+unsigned int DialogQueueElement::CalculateDialogProbability( const SelectableDialog& dialog )
+{
+ EventEnum eventID;
+ unsigned int i;
+ unsigned int probability = 100;
+
+ eventID = dialog.GetEvent();
+ for( i = 0; i < priorityTableLength; i++ )
+ {
+ if( ( priorityTable[i].priority == OccasionalPlayLine )
+ && ( priorityTable[i].eventID == eventID ) )
+ {
+ probability = priorityTable[i].probability;
+ break;
+ }
+ }
+
+ return( probability );
+}
+
+//=============================================================================
+// DialogQueueElement::OnPlaybackComplete
+//=============================================================================
+// Description: Callback function, triggered when currently playing dialog
+// is finished
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::OnPlaybackComplete()
+{
+ unsigned int numDialogLines = m_dialog->GetNumDialogLines();
+ SimpsonsSoundPlayer* player;
+ SimpsonsSoundPlayer* queuer; // I think I made up a word
+ Character* npcPtr;
+
+ //
+ // Reference self in case one of the callbacks we trigger
+ // here tries to delete this object
+ //
+ AddRef();
+
+ if( ++m_linesPlayed >= numDialogLines )
+ {
+ if( m_dialogDoneCallback )
+ {
+ if( isMouthFlappingEvent( m_dialog->GetEvent() ) )
+ {
+ //
+ // Coordinate the mouth flapping. Find out whether the PC
+ // or the NPC just finished talking, and send out the appropriate
+ // talk/shutup events.
+ //
+ if( dialogLineIsWalker( m_linesPlayed ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_PC_SHUTUP );
+ }
+ else
+ {
+ GetEventManager()->TriggerEvent( EVENT_NPC_SHUTUP );
+ }
+ }
+
+ //
+ // Tell the rest of the world that we're done
+ //
+ if( m_dialog->GetEvent() == EVENT_CONVERSATION_INIT_DIALOG )
+ {
+/*
+ if( m_dialog->GetMission() == static_cast<unsigned int>( DialogLine::TUTORIAL_MISSION_NUMBER ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_TUTORIAL_DIALOG_DONE );
+ }
+ else
+*/
+ {
+ GetEventManager()->TriggerEvent( EVENT_CONVERSATION_DONE );
+ }
+ }
+ else if( m_dialog->GetEvent() == EVENT_TUTORIAL_DIALOG_PLAY )
+ {
+ GetEventManager()->TriggerEvent( EVENT_TUTORIAL_DIALOG_DONE );
+ }
+
+ m_dialogDoneCallback->OnDialogComplete();
+ }
+ }
+ else
+ {
+ if( m_lineDoneCallback )
+ {
+ m_lineDoneCallback->OnDialogLineComplete();
+ }
+
+ if( isMouthFlappingEvent( m_dialog->GetEvent() ) )
+ {
+ //
+ // Coordinate the mouth flapping. Find out whether the PC
+ // or the NPC just finished talking, and send out the appropriate
+ // talk/shutup events.
+ //
+ if( dialogLineIsWalker( m_linesPlayed ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_PC_SHUTUP );
+ }
+ else
+ {
+ GetEventManager()->TriggerEvent( EVENT_NPC_SHUTUP );
+ }
+
+ //
+ // Start up the next line
+ //
+ if( dialogLineIsWalker( m_linesPlayed + 1 ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_PC_TALK );
+ }
+ else
+ {
+ npcPtr = dialogLineIsNPC( m_linesPlayed + 1 );
+ if( npcPtr != NULL )
+ {
+ GetEventManager()->TriggerEvent( EVENT_NPC_TALK, npcPtr );
+ }
+ }
+ }
+
+ //
+ // Even line numbers on player 1, odd on player 2
+ //
+ if( m_linesPlayed % 2 == 0 )
+ {
+ player = m_player1;
+ queuer = m_player2;
+ }
+ else
+ {
+ player = m_player2;
+ queuer = m_player1;
+ }
+ m_dialog->PlayQueuedLine( *player, this );
+
+ //
+ // Queue dialog if necessary
+ //
+ if( numDialogLines > m_linesPlayed + 1 )
+ {
+ m_dialog->QueueLine( m_linesPlayed + 1, *queuer );
+ }
+ }
+
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "OnPlaybackComplete %x: Count %d\n", this, GetRefCount() );
+#endif
+ Release();
+}
+
+//=============================================================================
+// DialogQueueElement::OnSoundReady
+//=============================================================================
+// Description: Unused, required for SimpsonsSoundPlayerCallback interface
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::OnSoundReady()
+{
+}
+
+//=============================================================================
+// DialogQueueElement::PlayDialog
+//=============================================================================
+// Description: Comment
+//
+// Parameters: player - SimpsonsSoundPlayer to use for playback
+// lineCallback - callback for when an individual line of
+// dialog is done, but not the entire dialog
+// dialogCallback - callback for when the entire dialog is done
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::PlayDialog( SimpsonsSoundPlayer& player1,
+ SimpsonsSoundPlayer& player2,
+ DialogLineCompleteCallback* lineCallback,
+ DialogCompleteCallback* dialogCallback )
+{
+ Character* npcPtr;
+
+ m_lineDoneCallback = lineCallback;
+ m_dialogDoneCallback = dialogCallback;
+
+ m_player1 = &player1;
+ m_player2 = &player2;
+ m_dialog->PlayLine( m_linesPlayed, *m_player1, this );
+ if( m_dialog->GetNumDialogLines() >= 2 )
+ {
+ //
+ // Queue up the next line
+ //
+ m_dialog->QueueLine( m_linesPlayed + 1, *m_player2 );
+ }
+
+ if( isMouthFlappingEvent( m_dialog->GetEvent() ) )
+ {
+ //
+ // Start the mouth flapping
+ //
+ if( dialogLineIsWalker( 1 ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_PC_TALK );
+ }
+ else
+ {
+ npcPtr = dialogLineIsNPC( 1 );
+ if( npcPtr != NULL )
+ {
+ GetEventManager()->TriggerEvent( EVENT_NPC_TALK, npcPtr );
+ }
+ }
+ }
+
+ if( m_timer )
+ {
+ m_timer->UnregisterCallback( this );
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "PlayDialog Timer: %d\n", m_timer->GetRefCount() );
+#endif
+ m_timer->Release();
+ m_timer = NULL;
+ }
+}
+
+//=============================================================================
+// DialogQueueElement::StopDialog
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::StopDialog()
+{
+ //
+ // Just in case of nasty callback action on the Stop() calls below
+ //
+ AddRef();
+
+ //
+ // Skip to the end of the dialog before triggering any stop callbacks
+ //
+ m_linesPlayed = m_dialog->GetNumDialogLines();
+
+ m_player1->Stop();
+ m_player2->Stop();
+
+ if( m_dialog != NULL )
+ {
+ if( isMouthFlappingEvent( m_dialog->GetEvent() ) )
+ {
+ GetEventManager()->TriggerEvent( EVENT_PC_SHUTUP );
+ GetEventManager()->TriggerEvent( EVENT_NPC_SHUTUP );
+ }
+ }
+
+#ifdef DEBUG_QUEUE_REFCOUNT
+ rTunePrintf( "StopDialog %x: Count %d\n", this, GetRefCount() );
+#endif
+ Release();
+}
+
+//=============================================================================
+// DialogQueueElement::Service
+//=============================================================================
+// Description: Service the timer list
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogQueueElement::Service()
+{
+ if( s_timerList != NULL )
+ {
+ s_timerList->Service();
+ }
+
+#ifndef RAD_RELEASE
+ if( !s_watcherInitialized )
+ {
+ //
+ // Register probability table in Watcher
+ //
+ unsigned int i;
+
+ for( i = 0; i < priorityTableLength; i++ )
+ {
+ if( priorityTable[i].priority == OccasionalPlayLine )
+ {
+ radDbgWatchAddUnsignedInt( &(priorityTable[i].probability),
+ priorityTable[i].eventName,
+ "Dialogue Tuning",
+ NULL,
+ NULL,
+ 0,
+ 100 );
+ }
+ }
+
+ s_watcherInitialized = true;
+ }
+#endif
+}
+
+//=============================================================================
+// DialogQueueElement::GetPosition
+//=============================================================================
+// Description: If this is a positional dialog, return a position
+//
+// Parameters: None
+//
+// Return: pointer to rmt::Vector with position if positional, NULL otherwise
+//
+//=============================================================================
+rmt::Vector* DialogQueueElement::GetPosition()
+{
+ rmt::Vector* retVal;
+
+ if( m_hasPosition )
+ {
+ retVal = &m_position;
+ }
+ else
+ {
+ retVal = NULL;
+ }
+
+ return( retVal );
+}
+
+void DialogQueueElement::FillDebugInfo( DialogSoundDebugPage& debugInfo, unsigned int lineNum )
+{
+ unsigned int msecs;
+
+ if( m_timer != NULL )
+ {
+ msecs = m_timer->GetTimeout();
+ }
+ else
+ {
+ msecs = 0;
+ }
+
+ debugInfo.SetQueueEntry( lineNum,
+ m_dialog->GetEvent(),
+ m_dialog->GetMission(),
+ m_dialog->GetLevel(),
+ m_dialog->GetDialogLineCharacterUID( 1 ),
+ CalculateDialogPriority( *m_dialog ),
+ msecs );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogQueueElement::dialogLineIsWalker
+//=============================================================================
+// Description: Indicates whether the dialog line with the given number
+// belongs to the player character
+//
+// Parameters: lineNum - line number to check
+//
+// Return: true if player character, false otherwise
+//
+//=============================================================================
+bool DialogQueueElement::dialogLineIsWalker( unsigned int lineNum )
+{
+ tUID characterUID;
+ Character* walker;
+ tUID walkerUID;
+
+ characterUID = m_dialog->GetDialogLineCharacterUID( lineNum );
+ walker = GetAvatarManager()->GetAvatarForPlayer( 0 )->GetCharacter();
+ rAssert( walker != NULL );
+ walkerUID = walker->GetUID();
+
+ return( characterUID == walkerUID );
+}
+
+//=============================================================================
+// DialogQueueElement::dialogLineIsNPC
+//=============================================================================
+// Description: Indicates whether the dialog line with the given number
+// belongs to an NPC
+//
+// Parameters: lineNum - line number to check
+//
+// Return: pointer to character object if found, NULL otherwise
+//
+//=============================================================================
+Character* DialogQueueElement::dialogLineIsNPC( unsigned int lineNum )
+{
+ tUID speakerUID;
+ Character* npc;
+
+ speakerUID = m_dialog->GetDialogLineCharacterUID( lineNum );
+ npc = GetCharacterManager()->GetCharacterByName( speakerUID );
+
+ //
+ // If the character is an NPC, we'll get a pointer. If it's some
+ // character that doesn't exist in the world (e.g. Brockman in L7M1),
+ // then we get NULL.
+ //
+ if( npc != NULL )
+ {
+ return( npc );
+ }
+
+ //
+ // P.S. Not only do we have to check the speaker's UID, we have to
+ // check for stinky skins as well
+ //
+ return( DialogList::GetStinkySkinPointer( speakerUID ) );
+}
+
+//=============================================================================
+// DialogQueueElement::isMouthFlappingEvent
+//=============================================================================
+// Description: Indicate whether given dialogue event should trigger mouth
+// flapping
+//
+// Parameters: theEvent - event to scrutinize
+//
+// Return: true if mouth flapping event, false otherwise
+//
+//=============================================================================
+bool DialogQueueElement::isMouthFlappingEvent( EventEnum theEvent )
+{
+ bool retVal = false;
+
+ switch( theEvent )
+ {
+ case EVENT_CONVERSATION_INIT_DIALOG:
+ case EVENT_AMBIENT_ASKFOOD:
+ case EVENT_AMBIENT_FOODREPLY:
+ case EVENT_AMBIENT_GREETING:
+ case EVENT_AMBIENT_RESPONSE:
+ case EVENT_PEDESTRIAN_SMACKDOWN:
+ case EVENT_CHARACTER_TIRED_NOW:
+ retVal = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return( retVal );
+} \ No newline at end of file
diff --git a/game/code/sound/dialog/dialogqueueelement.h b/game/code/sound/dialog/dialogqueueelement.h
new file mode 100644
index 0000000..54074b1
--- /dev/null
+++ b/game/code/sound/dialog/dialogqueueelement.h
@@ -0,0 +1,158 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogqueueelement.h
+//
+// Description: Wrapper for SelectableDialog objects in the dialog queue,
+// to associate them with a timer and to allow reception of
+// playback completion callbacks without having to bother
+// the queue class with partially-complete conversations.
+//
+// History: 04/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGQUEUEELEMENT_H
+#define DIALOGQUEUEELEMENT_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radtime.hpp>
+
+#include <sound/simpsonssoundplayer.h>
+#include <sound/dialog/dialogqueuetype.h>
+#include <events/eventenum.h>
+
+//========================================
+// Forward References
+//========================================
+class SelectableDialog;
+class SimpsonsSoundPlayer;
+class DialogSoundDebugPage;
+class Character;
+
+//
+// Four levels of playback priority
+//
+enum DialogPriority
+{
+ UnknownPriority,
+
+ OccasionalPlayLine,
+ ShouldPlayLine,
+ MustPlayLine,
+ MustPlayImmediately
+};
+
+//=============================================================================
+//
+// Synopsis: DialogLineCompleteCallback - callback interface, triggered
+// when a line of dialog is finished playing, but more
+// dialog remains to be played
+//
+//=============================================================================
+
+class DialogLineCompleteCallback
+{
+ public:
+ virtual void OnDialogLineComplete() = 0;
+};
+
+//=============================================================================
+//
+// Synopsis: DialogCompleteCallback - callback interface, triggered
+// when all of the dialog has been played
+//
+//=============================================================================
+
+class DialogCompleteCallback
+{
+ public:
+ virtual void OnDialogComplete() = 0;
+};
+
+//=============================================================================
+//
+// Synopsis: DialogQueueElement
+//
+//=============================================================================
+
+class DialogQueueElement : public IRadTimerCallback,
+ public SimpsonsSoundPlayerCallback,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "DialogQueueElement" );
+
+ DialogQueueElement( SelectableDialog* dialog );
+ virtual ~DialogQueueElement();
+
+ static void CreateTimerList();
+
+ void OnTimerDone( unsigned int elapsedTime, void * pUserData );
+
+ void AddToQueue( DialogQueueType* queue, rmt::Vector* posn );
+ void RemoveSelfFromList();
+
+ void PlayDialog( SimpsonsSoundPlayer& player1,
+ SimpsonsSoundPlayer& player2,
+ DialogLineCompleteCallback* lineCallback,
+ DialogCompleteCallback* dialogCallback );
+ void StopDialog();
+
+ DialogPriority GetPriority() { return( CalculateDialogPriority( *m_dialog ) ); }
+
+ bool DialogMatches( SelectableDialog* dialog ) { return( dialog == m_dialog ); }
+
+ rmt::Vector* GetPosition();
+
+ void FillDebugInfo( DialogSoundDebugPage& debugInfo, unsigned int lineNum );
+
+ //
+ // SimpsonsSoundPlayer callbacks
+ //
+ void OnPlaybackComplete();
+ void OnSoundReady();
+
+ static DialogPriority CalculateDialogPriority( const SelectableDialog& dialog );
+ static unsigned int CalculateDialogProbability( const SelectableDialog& dialog );
+ static void Service();
+
+ static const unsigned int MAX_QUEUE_ELEMENTS = 16;
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogQueueElement();
+ DialogQueueElement( const DialogQueueElement& original );
+ DialogQueueElement& operator=( const DialogQueueElement& rhs );
+
+ bool dialogLineIsWalker( unsigned int lineNum );
+ Character* dialogLineIsNPC( unsigned int lineNum );
+
+ bool isMouthFlappingEvent( EventEnum theEvent );
+
+ static IRadTimerList* s_timerList;
+
+ static bool s_watcherInitialized;
+
+ SelectableDialog* m_dialog;
+ IRadTimer* m_timer;
+
+ SimpsonsSoundPlayer* m_player1;
+ SimpsonsSoundPlayer* m_player2;
+
+ DialogLineCompleteCallback* m_lineDoneCallback;
+ DialogCompleteCallback* m_dialogDoneCallback;
+
+ unsigned int m_linesPlayed;
+
+ DialogQueueType* m_queue;
+
+ rmt::Vector m_position;
+ bool m_hasPosition;
+};
+
+
+#endif // DIALOGQUEUEELEMENT_H
+
diff --git a/game/code/sound/dialog/dialogqueuetype.h b/game/code/sound/dialog/dialogqueuetype.h
new file mode 100644
index 0000000..178396d
--- /dev/null
+++ b/game/code/sound/dialog/dialogqueuetype.h
@@ -0,0 +1,24 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogqueuetype.h
+//
+// Description: Typedef for STL list of dialog queue elements. Removed from
+// DialogPriorityQueue to avoid unnecessary dependency.
+//
+// History: 9/25/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGQUEUETYPE_H
+#define DIALOGQUEUETYPE_H
+
+class DialogQueueElement;
+
+#include <list>
+#include <memory/stlallocators.h>
+
+typedef std::list< DialogQueueElement*, s2alloc<DialogQueueElement*> > DialogQueueType;
+
+#endif // DIALOGQUEUETYPE_H
+
diff --git a/game/code/sound/dialog/dialogselectiongroup.cpp b/game/code/sound/dialog/dialogselectiongroup.cpp
new file mode 100644
index 0000000..3b3b0f0
--- /dev/null
+++ b/game/code/sound/dialog/dialogselectiongroup.cpp
@@ -0,0 +1,376 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogselectiongroup.cpp
+//
+// Description: Represents a set of dialog lines or conversations that can
+// be randomly selected without affecting gameplay. For example,
+// if Homer had three generic lines for playback whenever he is
+// hit by a car, and all three can be substituted for each other
+// freely, then those lines would be grouped by a DialogSelectionGroup
+// object.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+#define DONTCHECKVECTORRESIZING
+//========================================
+// System Includes
+//========================================
+#include <radtime.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogselectiongroup.h>
+
+#include <sound/simpsonssoundplayer.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Typical max number of elements in the vector, so as to not waste space
+//
+static const int TYPICAL_VECTOR_SIZE = 4;
+
+//
+// Value for in-use dialog index when nothing being played
+//
+static const short DIALOG_NOT_IN_USE = -1;
+
+static const short DIALOG_NOT_YET_USED = -1;
+
+
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// DialogSelectionGroup::DialogSelectionGroup
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogSelectionGroup::DialogSelectionGroup( SelectableDialog& dialog1,
+ SelectableDialog& dialog2 ) :
+ m_currentlyPlayingDialog( DIALOG_NOT_IN_USE ),
+ m_lastSelection( DIALOG_NOT_YET_USED )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_dialogVector.reserve( TYPICAL_VECTOR_SIZE );
+
+ m_dialogVector.push_back( &dialog1 );
+ m_dialogVector.push_back( &dialog2 );
+
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//==============================================================================
+// DialogSelectionGroup::~DialogSelectionGroup
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+DialogSelectionGroup::~DialogSelectionGroup()
+{
+}
+
+//==============================================================================
+// DialogSelectionGroup::PlayLine
+//==============================================================================
+// Description: Select a dialog if we haven't done it yet and play it.
+//
+// Parameters: lineIndex - index of dialog line to play
+// player - sound player
+// callback - callback for when the dialog line is complete
+//
+// Return: N/A.
+//
+//==============================================================================
+void DialogSelectionGroup::PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ if( lineIndex == 0 )
+ {
+ makeRandomSelection();
+ }
+ else
+ {
+ rAssert( m_currentlyPlayingDialog != DIALOG_NOT_IN_USE );
+ }
+
+ m_dialogVector[m_currentlyPlayingDialog]->PlayLine( lineIndex, player, callback );
+}
+
+//=============================================================================
+// DialogSelectionGroup::QueueLine
+//=============================================================================
+// Description: Select a dialog if we haven't done it yet and queue it for
+// playback
+//
+// Parameters: lineIndex - index of dialog line to play
+// player - sound player
+//
+// Return: void
+//
+//=============================================================================
+void DialogSelectionGroup::QueueLine( unsigned int lineIndex, SimpsonsSoundPlayer& player )
+{
+ if( lineIndex == 0 )
+ {
+ makeRandomSelection();
+ }
+ else
+ {
+ rAssert( m_currentlyPlayingDialog != DIALOG_NOT_IN_USE );
+ }
+
+ m_dialogVector[m_currentlyPlayingDialog]->QueueLine( lineIndex, player );
+}
+
+//=============================================================================
+// DialogSelectionGroup::PlayQueuedLine
+//=============================================================================
+// Description: Play line of dialog that we queued earlier
+//
+// Parameters: player - sound player
+// callback - callback for when the dialog line is complete
+//
+// Return: void
+//
+//=============================================================================
+void DialogSelectionGroup::PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ m_dialogVector[m_currentlyPlayingDialog]->PlayQueuedLine( player, callback );
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetNumDialogLines
+//=============================================================================
+// Description: Return the number of dialog lines in the currently selected
+// SelectableDialog object
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+unsigned int DialogSelectionGroup::GetNumDialogLines() const
+{
+ if( m_currentlyPlayingDialog == DIALOG_NOT_IN_USE )
+ {
+ //
+ // Assume shortest case
+ //
+ return( 1 );
+ }
+ else
+ {
+ return( m_dialogVector[m_currentlyPlayingDialog]->GetNumDialogLines() );
+ }
+}
+
+//=============================================================================
+// DialogSelectionGroup::UsesCharacter
+//=============================================================================
+// Description: Indicate if any of the dialogs use the given character
+//
+// Parameters: characterObj - character to match
+//
+// Return: true if character used, false otherwise
+//
+//=============================================================================
+bool DialogSelectionGroup::UsesCharacter( tUID characterUID )
+{
+ if( m_dialogVector.empty() )
+ {
+ return( false );
+ }
+ else
+ {
+ return( m_dialogVector[0]->UsesCharacter( characterUID ) );
+ }
+}
+
+//=============================================================================
+// DialogSelectionGroup::IsVillainLine
+//=============================================================================
+// Description: Indicate if the dialogs are villain
+//
+// Parameters: None
+//
+// Return: true if villain, false otherwise
+//
+//=============================================================================
+bool DialogSelectionGroup::IsVillainLine()
+{
+ if( m_dialogVector.empty() )
+ {
+ return( false );
+ }
+ else
+ {
+ return( m_dialogVector[0]->IsVillainLine() );
+ }
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetDialogLineCharacterUID
+//=============================================================================
+// Description: Indicate which character is speaking with the given line
+//
+// Parameters: lineNum - indicates which dialog line we want the UID for
+//
+// Return: tUID of character associated with dialog line, zero if we
+// haven't selected a character
+//
+//=============================================================================
+tUID DialogSelectionGroup::GetDialogLineCharacterUID( unsigned int lineNum )
+{
+ if( m_currentlyPlayingDialog == DIALOG_NOT_IN_USE )
+ {
+ return( m_dialogVector[0]->GetDialogLineCharacterUID( lineNum ) );
+ }
+ else
+ {
+ return( m_dialogVector[m_currentlyPlayingDialog]->GetDialogLineCharacterUID( lineNum ) );
+ }
+}
+
+//=============================================================================
+// DialogSelectionGroup::AddMatchingDialog
+//=============================================================================
+// Description: Push given dialog onto list
+//
+// Parameters: newDialog - dialog to add
+//
+// Return: void
+//
+//=============================================================================
+void DialogSelectionGroup::AddMatchingDialog( SelectableDialog& newDialog,
+ SelectableDialogList& list )
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+ m_dialogVector.push_back( &newDialog );
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetEvent
+//=============================================================================
+// Description: Returns event associated with this group, which we'll get
+// from a dialog in the list.
+//
+// Parameters: None
+//
+// Return: EventEnum representing event
+//
+//=============================================================================
+EventEnum DialogSelectionGroup::GetEvent() const
+{
+ rAssert( m_dialogVector.size() > 0 );
+
+ return( m_dialogVector[0]->GetEvent() );
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetLevel
+//=============================================================================
+// Description: Returns level associated with this group, which we'll get
+// from a dialog in the list.
+//
+// Parameters: None
+//
+// Return: index of level if one exists, NO_LEVEL otherwise
+//
+//=============================================================================
+unsigned int DialogSelectionGroup::GetLevel() const
+{
+ rAssert( m_dialogVector.size() > 0 );
+
+ return( m_dialogVector[0]->GetLevel() );
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetMission
+//=============================================================================
+// Description: Returns event associated with this group, which we'll get
+// from a dialog in the list.
+//
+// Parameters: None
+//
+// Return: index of mission if one exists, NO_MISSION otherwise
+//
+//=============================================================================
+unsigned int DialogSelectionGroup::GetMission() const
+{
+ rAssert( m_dialogVector.size() > 0 );
+
+ return( m_dialogVector[0]->GetMission() );
+}
+
+//=============================================================================
+// DialogSelectionGroup::GetConversationName
+//=============================================================================
+// Description: Not relevant in this class.
+//
+// Parameters: None
+//
+// Return: Zero, indicating we aren't a conversation
+//
+//=============================================================================
+radKey32 DialogSelectionGroup::GetConversationName()
+{
+ return( 0 );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// DialogSelectionGroup::makeRandomSelection
+//=============================================================================
+// Description: Select dialog to play
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void DialogSelectionGroup::makeRandomSelection()
+{
+ if( m_lastSelection == DIALOG_NOT_YET_USED )
+ {
+ //
+ // No real need to bother with true pseudo-randomization, just
+ // use the clock
+ //
+ m_lastSelection = static_cast<short>( radTimeGetMilliseconds() % m_dialogVector.size() );
+ }
+
+ m_currentlyPlayingDialog = m_lastSelection;
+ m_lastSelection = ( m_lastSelection + 1 ) % m_dialogVector.size();
+}
+
+#undef DONTCHECKVECTORRESIZING \ No newline at end of file
diff --git a/game/code/sound/dialog/dialogselectiongroup.h b/game/code/sound/dialog/dialogselectiongroup.h
new file mode 100644
index 0000000..6da0d17
--- /dev/null
+++ b/game/code/sound/dialog/dialogselectiongroup.h
@@ -0,0 +1,91 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogselectiongroup.h
+//
+// Description: Represents a set of dialog lines or conversations that can
+// be randomly selected without affecting gameplay. For example,
+// if Homer had three generic lines for playback whenever he is
+// hit by a car, and all three can be substituted for each other
+// freely, then those lines would be grouped by a DialogSelectionGroup
+// object.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGSELECTIONGROUP_H
+#define DIALOGSELECTIONGROUP_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <vector>
+
+#include <sound/dialog/selectabledialog.h>
+
+//========================================
+// Forward References
+//========================================
+class SimpsonsSoundPlayer;
+struct SimpsonsSoundPlayerCallback;
+
+//=============================================================================
+//
+// Synopsis: DialogSelectionGroup
+//
+//=============================================================================
+
+class DialogSelectionGroup : public SelectableDialog
+{
+ public:
+ DialogSelectionGroup( SelectableDialog& dialog1, SelectableDialog& dialog2 );
+ virtual ~DialogSelectionGroup();
+
+ void PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+ void QueueLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player );
+ void PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback );
+
+ unsigned int GetNumDialogLines() const;
+
+ bool UsesCharacter( tUID characterUID );
+ tUID GetDialogLineCharacterUID( unsigned int lineNum );
+ radKey32 GetConversationName();
+ bool IsVillainLine();
+
+ void AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list );
+
+ //
+ // Overriding SelectableDialog methods
+ //
+ unsigned int GetMission() const;
+ unsigned int GetLevel() const;
+ EventEnum GetEvent() const;
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogSelectionGroup();
+ DialogSelectionGroup( const DialogSelectionGroup& original );
+ DialogSelectionGroup& operator=( const DialogSelectionGroup& rhs );
+
+ void makeRandomSelection();
+
+ //
+ // List of SelectableDialog objects to choose from. Use std::vector
+ // for space conservation
+ //
+ typedef std::vector< SelectableDialog*, s2alloc<SelectableDialog*> > DialogVector;
+
+ DialogVector m_dialogVector;
+
+ short m_currentlyPlayingDialog;
+ short m_lastSelection;
+};
+
+
+#endif // DIALOGSELECTIONGROUP_H
+
diff --git a/game/code/sound/dialog/dialogsounddebugpage.cpp b/game/code/sound/dialog/dialogsounddebugpage.cpp
new file mode 100644
index 0000000..1823422
--- /dev/null
+++ b/game/code/sound/dialog/dialogsounddebugpage.cpp
@@ -0,0 +1,243 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogsounddebugpage.cpp
+//
+// Description: Implements a class for displaying dialog-related debug info
+// on the screen, triggered using Watcher
+//
+// History: 1/20/2003 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/dialogsounddebugpage.h>
+
+#include <sound/dialog/dialogline.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// DialogSoundDebugPage::DialogSoundDebugPage
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+DialogSoundDebugPage::DialogSoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master ) :
+ SoundDebugPage( pageNum, master )
+{
+ unsigned int i;
+
+ //
+ // Mark queue entries as empty by setting event ID to NUM_EVENTS
+ //
+ for( i = 0; i < MAX_QUEUE_SIZE; i++ )
+ {
+ m_queueData[i].eventID = NUM_EVENTS;
+ }
+}
+
+//=============================================================================
+// DialogSoundDebugPage::~DialogSoundDebugPage
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+DialogSoundDebugPage::~DialogSoundDebugPage()
+{
+}
+
+//=============================================================================
+// DialogSoundDebugPage::SetQueueLength
+//=============================================================================
+// Description: Given queue length, clear out entries that are no longer in
+// the queue
+//
+// Parameters: size - current size of queue
+//
+// Return: void
+//
+//=============================================================================
+void DialogSoundDebugPage::SetQueueLength( unsigned int size )
+{
+ unsigned int i;
+
+ for( i = size; i < MAX_QUEUE_SIZE; i++ )
+ {
+ m_queueData[i].eventID = NUM_EVENTS;
+ }
+}
+
+//=============================================================================
+// DialogSoundDebugPage::SetQueueEntry
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int position, EventEnum event, unsigned int mission, unsigned int level, tUID theCharacter, DialogPriority priority, unsigned int msecsRemaining )
+//
+// Return: void
+//
+//=============================================================================
+void DialogSoundDebugPage::SetQueueEntry( unsigned int position,
+ EventEnum event,
+ unsigned int mission,
+ unsigned int level,
+ tUID theCharacter,
+ DialogPriority priority,
+ unsigned int msecsRemaining )
+{
+ QueueInfo* data;
+
+ if( position >= MAX_QUEUE_SIZE )
+ {
+ //
+ // Don't bother displaying too much stuff
+ //
+ return;
+ }
+
+ data = &m_queueData[position];
+ data->eventID = event;
+ data->level = level;
+ data->mission = mission;
+ data->theCharacter = theCharacter;
+ data->priority = priority;
+ data->msecsRemaining = msecsRemaining;
+}
+
+//*****************************************************************************
+//
+// Protected Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// DialogSoundDebugPage::fillLineBuffer
+//=============================================================================
+// Description: Fill the given buffer with text to display on the screen
+// at the given line
+//
+// Parameters: lineNum - line number on screen where buffer will be displayed
+// buffer - to be filled in with text to display
+//
+// Return: void
+//
+//=============================================================================
+void DialogSoundDebugPage::fillLineBuffer( int lineNum, char* buffer )
+{
+ switch( lineNum )
+ {
+ case 0:
+ strcpy( buffer, "Now playing:" );
+ break;
+
+ case 1:
+ fillQueueText( buffer, 0 );
+ break;
+
+ case 3:
+ strcpy( buffer, "Queued:" );
+ break;
+
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ fillQueueText( buffer, lineNum - 3 );
+ break;
+
+ default:
+ buffer[0] = '\0';
+ break;
+ }
+}
+
+//=============================================================================
+// DialogSoundDebugPage::getNumLines
+//=============================================================================
+// Description: Returns number of lines that we'll display on screen
+//
+// Parameters: None
+//
+// Return: Line count
+//
+//=============================================================================
+int DialogSoundDebugPage::getNumLines()
+{
+ return( 13 );
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// DialogSoundDebugPage::fillQueueText
+//=============================================================================
+// Description: Fill the text buffer with information about one particular
+// dialog queue entry
+//
+// Parameters: buffer - text buffer to fill
+// index - index of m_queueData entry to fill out with
+//
+// Return: void
+//
+//=============================================================================
+void DialogSoundDebugPage::fillQueueText( char* buffer, unsigned int index )
+{
+ QueueInfo* info;
+ char eventName[30];
+ char characterName[10];
+
+ rAssert( index >= 0 );
+ rAssert( index <= MAX_QUEUE_SIZE );
+ rAssert( buffer != NULL );
+
+ info = &m_queueData[index];
+ if( info->eventID != NUM_EVENTS )
+ {
+ DialogLine::FillEventName( eventName, 30, info->eventID );
+ DialogLine::FillCharacterName( characterName, 10, info->theCharacter );
+ sprintf( buffer, "Event: %s Char: %s Pri: %d L%dM%d",
+ eventName,
+ characterName,
+ info->priority,
+ info->level,
+ info->mission );
+ }
+ else
+ {
+ buffer[0] = '\0';
+ }
+}
diff --git a/game/code/sound/dialog/dialogsounddebugpage.h b/game/code/sound/dialog/dialogsounddebugpage.h
new file mode 100644
index 0000000..9fb0652
--- /dev/null
+++ b/game/code/sound/dialog/dialogsounddebugpage.h
@@ -0,0 +1,89 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dialogsounddebugpage.h
+//
+// Description: Declares a class for displaying dialog-related debug info
+// on the screen, triggered using Watcher
+//
+// History: 1/20/2003 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef DIALOGSOUNDDEBUGPAGE_H
+#define DIALOGSOUNDDEBUGPAGE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/sounddebug/sounddebugpage.h>
+
+#include <events/eventenum.h>
+#include <sound/dialog/dialogqueueelement.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: DialogSoundDebugPage
+//
+//=============================================================================
+
+class DialogSoundDebugPage : public SoundDebugPage
+{
+ public:
+ DialogSoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master );
+ virtual ~DialogSoundDebugPage();
+
+ void SetQueueLength( unsigned int size );
+
+ void SetQueueEntry( unsigned int position,
+ EventEnum event,
+ unsigned int mission,
+ unsigned int level,
+ tUID theCharacter,
+ DialogPriority priority,
+ unsigned int msecsRemaining );
+
+ protected:
+ //
+ // Pure virtual functions from SoundDebugPage
+ //
+ void fillLineBuffer( int lineNum, char* buffer );
+ int getNumLines();
+
+ private:
+ //Prevent wasteful constructor creation.
+ DialogSoundDebugPage();
+ DialogSoundDebugPage( const DialogSoundDebugPage& dialogsounddebugpage );
+ DialogSoundDebugPage& operator=( const DialogSoundDebugPage& dialogsounddebugpage );
+
+ void fillQueueText( char* buffer, unsigned int index );
+
+ //
+ // Structure for holding queue information
+ //
+ struct QueueInfo
+ {
+ EventEnum eventID;
+ unsigned int mission;
+ unsigned int level;
+ tUID theCharacter;
+ DialogPriority priority;
+ unsigned int msecsRemaining;
+ };
+
+ static const unsigned int MAX_QUEUE_SIZE = 10;
+
+ QueueInfo m_queueData[MAX_QUEUE_SIZE];
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //DIALOGSOUNDDEBUGPAGE_H
diff --git a/game/code/sound/dialog/playabledialog.cpp b/game/code/sound/dialog/playabledialog.cpp
new file mode 100644
index 0000000..c251354
--- /dev/null
+++ b/game/code/sound/dialog/playabledialog.cpp
@@ -0,0 +1,87 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: playabledialog.cpp
+//
+// Description: Abstract base class for the basic unit of dialog playback.
+// A PlayableDialog object represents a piece of dialog which
+// is to be played without interruption (unless it gets booted
+// by a higher-priority PlayableDialog).
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/playabledialog.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// PlayableDialog::PlayableDialog
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+PlayableDialog::PlayableDialog()
+{
+}
+
+//==============================================================================
+// PlayableDialog::PlayableDialog
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: mission - mission number for dialog
+// level - level number
+// event - event that this dialog is played in response to
+//
+// Return: N/A.
+//
+//==============================================================================
+PlayableDialog::PlayableDialog( unsigned int level, unsigned int mission, EventEnum event ) :
+ SelectableDialog( level, mission, event )
+{
+}
+
+//==============================================================================
+// PlayableDialog::~PlayableDialog
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+PlayableDialog::~PlayableDialog()
+{
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/dialog/playabledialog.h b/game/code/sound/dialog/playabledialog.h
new file mode 100644
index 0000000..5c7f16b
--- /dev/null
+++ b/game/code/sound/dialog/playabledialog.h
@@ -0,0 +1,48 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: playabledialog.h
+//
+// Description: Abstract base class for the basic unit of dialog playback.
+// A PlayableDialog object represents a piece of dialog which
+// is to be played without interruption (unless it gets booted
+// by a higher-priority PlayableDialog).
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef PLAYABLEDIALOG_H
+#define PLAYABLEDIALOG_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/dialog/selectabledialog.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: PlayableDialog
+//
+//=============================================================================
+
+class PlayableDialog : public SelectableDialog
+{
+ public:
+ PlayableDialog();
+ PlayableDialog( unsigned int level, unsigned int mission, EventEnum event );
+ virtual ~PlayableDialog();
+
+ private:
+ //Prevent wasteful constructor creation.
+ PlayableDialog( const PlayableDialog& original );
+ PlayableDialog& operator=( const PlayableDialog& rhs );
+};
+
+
+#endif // PLAYABLEDIALOG_H
+
diff --git a/game/code/sound/dialog/selectabledialog.cpp b/game/code/sound/dialog/selectabledialog.cpp
new file mode 100644
index 0000000..c71fe42
--- /dev/null
+++ b/game/code/sound/dialog/selectabledialog.cpp
@@ -0,0 +1,214 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: selectabledialog.cpp
+//
+// Description: Abstract base class for groups of one or more lines of dialog,
+// any of which can be selected randomly in response to a single
+// sound event.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <raddebug.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/dialog/selectabledialog.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SelectableDialog::SelectableDialog
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SelectableDialog::SelectableDialog() :
+ m_missionNum( NO_MISSION ),
+ m_levelNum( NO_LEVEL ),
+ m_event( NUM_EVENTS ),
+#ifndef RAD_RELEASE
+ m_hasBeenPlayed( false ),
+#endif
+ m_nextListObject( NULL )
+{
+}
+
+//==============================================================================
+// SelectableDialog::SelectableDialog
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: mission - mission number for dialog
+// level - level number
+// event - event that this dialog is played in response to
+//
+// Return: N/A.
+//
+//==============================================================================
+SelectableDialog::SelectableDialog( unsigned int level, unsigned int mission, EventEnum event ) :
+ m_missionNum( mission ),
+ m_levelNum( level ),
+ m_event( event ),
+#ifndef RAD_RELEASE
+ m_hasBeenPlayed( false ),
+#endif
+ m_nextListObject( NULL )
+{
+}
+
+//==============================================================================
+// SelectableDialog::~SelectableDialog
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SelectableDialog::~SelectableDialog()
+{
+}
+
+//=============================================================================
+// SelectableDialog::AddToDialogList
+//=============================================================================
+// Description: Place this object on the head of the list supplied
+//
+// Parameters: list - list to add to
+//
+// Return: void
+//
+//=============================================================================
+void SelectableDialog::AddToDialogList( SelectableDialog** list )
+{
+ m_nextListObject = *list;
+ *list = this;
+}
+
+//=============================================================================
+// SelectableDialog::AddToDialogList
+//=============================================================================
+// Description: Place this object in the list after the object supplied
+//
+// Parameters: listObj - object to add after
+//
+// Return: void
+//
+//=============================================================================
+void SelectableDialog::AddToDialogList( SelectableDialog* listObj )
+{
+ m_nextListObject = listObj->m_nextListObject;
+ listObj->m_nextListObject = this;
+}
+
+//=============================================================================
+// SelectableDialog::RemoveNextFromList
+//=============================================================================
+// Description: Pull out the object after this one in the list
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SelectableDialog::RemoveNextFromList()
+{
+ rAssert( m_nextListObject != NULL );
+ m_nextListObject = m_nextListObject->m_nextListObject;
+}
+
+//=============================================================================
+// SelectableDialog::GetMission
+//=============================================================================
+// Description: Returns mission number associated with this dialog
+//
+// Parameters: None
+//
+// Return: unsigned int with the mission number, NO_MISSION for no mission
+//
+//=============================================================================
+unsigned int SelectableDialog::GetMission() const
+{
+ return( m_missionNum );
+}
+
+//=============================================================================
+// SelectableDialog::GetLevel
+//=============================================================================
+// Description: Returns level number associated with this dialog
+//
+// Parameters: None
+//
+// Return: unsigned int with the level number, NO_LEVEL for no level
+//
+//=============================================================================
+unsigned int SelectableDialog::GetLevel() const
+{
+ return( m_levelNum );
+}
+
+//=============================================================================
+// SelectableDialog::GetEvent
+//=============================================================================
+// Description: Returns event associated with this dialog
+//
+// Parameters: None
+//
+// Return: EventEnum
+//
+//=============================================================================
+EventEnum SelectableDialog::GetEvent() const
+{
+ return( m_event );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+#ifndef RAD_RELEASE
+
+void SelectableDialog::MarkAsPlayed()
+{
+ m_hasBeenPlayed = true;
+}
+
+void SelectableDialog::PrintPlayedStatus()
+{
+ if( m_hasBeenPlayed )
+ {
+ rTuneString( "Played\n" );
+ }
+ else
+ {
+ rTuneString( "NOT PLAYED\n" );
+ }
+}
+
+#endif
diff --git a/game/code/sound/dialog/selectabledialog.h b/game/code/sound/dialog/selectabledialog.h
new file mode 100644
index 0000000..c26125c
--- /dev/null
+++ b/game/code/sound/dialog/selectabledialog.h
@@ -0,0 +1,118 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: selectabledialog.h
+//
+// Description: Abstract base class for groups of one or more lines of dialog,
+// any of which can be selected randomly in response to a single
+// sound event.
+//
+// History: 02/09/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SELECTABLEDIALOG_H
+#define SELECTABLEDIALOG_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <events/eventenum.h>
+#include <worldsim/character/character.h>
+#include <sound/dialog/selectabledialoglist.h>
+
+//========================================
+// Forward References
+//========================================
+class SimpsonsSoundPlayer;
+struct SimpsonsSoundPlayerCallback;
+
+//=============================================================================
+//
+// Synopsis: SelectableDialog
+//
+//=============================================================================
+
+class SelectableDialog
+{
+ public:
+ SelectableDialog();
+ SelectableDialog( unsigned int level, unsigned int mission, EventEnum event );
+ virtual ~SelectableDialog();
+
+ static const int NO_MISSION = 0;
+ static const int NO_LEVEL = 0;
+
+ bool IsLevelSpecific() { return( m_levelNum != NO_LEVEL ); }
+
+ virtual unsigned int GetMission() const;
+ virtual unsigned int GetLevel() const;
+ virtual EventEnum GetEvent() const;
+
+ virtual bool UsesCharacter( Character* characterObj )
+ { return( UsesCharacter( characterObj->GetUID() ) ); }
+ virtual bool UsesCharacter( tUID characterUID ) = 0;
+
+ virtual tUID GetDialogLineCharacterUID( unsigned int lineNum ) = 0;
+
+ virtual bool IsVillainLine() = 0;
+
+ void AddToDialogList( SelectableDialog** list );
+ void AddToDialogList( SelectableDialog* listObj );
+ SelectableDialog* GetNextInList() const { return( m_nextListObject ); }
+ void RemoveNextFromList();
+
+ virtual void AddMatchingDialog( SelectableDialog& newDialog, SelectableDialogList& list ) = 0;
+
+ virtual void PlayLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback ) = 0;
+ virtual void QueueLine( unsigned int lineIndex,
+ SimpsonsSoundPlayer& player ) = 0;
+ virtual void PlayQueuedLine( SimpsonsSoundPlayer& player,
+ SimpsonsSoundPlayerCallback* callback ) = 0;
+
+ virtual unsigned int GetNumDialogLines() const = 0;
+
+ virtual radKey32 GetConversationName() = 0;
+
+#ifndef RAD_RELEASE
+ void MarkAsPlayed();
+ void PrintPlayedStatus();
+#endif
+
+ protected:
+ //
+ // Level, mission, and event values. Since these aren't really used
+ // in DialogSelectionGroup and Conversation objects, they should
+ // probably be separated out of this object someday if we want to
+ // save a few bytes and clean up the design a bit.
+ //
+
+ //
+ // Level and mission number for this line. Set to NO_MISSION or
+ // NO_LEVEL if not applicable.
+ //
+ int m_missionNum;
+ int m_levelNum;
+
+ //
+ // Event that this dialog is played in response to
+ //
+ EventEnum m_event;
+
+ private:
+ //Prevent wasteful constructor creation.
+ SelectableDialog( const SelectableDialog& original );
+ SelectableDialog& operator=( const SelectableDialog& rhs );
+
+#ifndef RAD_RELEASE
+ bool m_hasBeenPlayed;
+#endif
+
+ SelectableDialog* m_nextListObject;
+};
+
+
+#endif // SELECTABLEDIALOG_H
+
diff --git a/game/code/sound/dialog/selectabledialoglist.h b/game/code/sound/dialog/selectabledialoglist.h
new file mode 100644
index 0000000..ddd5572
--- /dev/null
+++ b/game/code/sound/dialog/selectabledialoglist.h
@@ -0,0 +1,24 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: selectabledialoglist.h
+//
+// Description: Typedef for STL list of selectable dialogs. Removed from
+// DialogList to avoid unnecessary dependency.
+//
+// History: 9/25/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SELECTABLEDIALOGLIST_H
+#define SELECTABLEDIALOGLIST_H
+
+class SelectableDialog;
+
+#include <list>
+#include <memory/stlallocators.h>
+
+typedef std::list< SelectableDialog*, s2alloc<SelectableDialog*> > SelectableDialogList;
+
+#endif // SELECTABLEDIALOGLIST_H
+
diff --git a/game/code/sound/listener.cpp b/game/code/sound/listener.cpp
new file mode 100644
index 0000000..559cb11
--- /dev/null
+++ b/game/code/sound/listener.cpp
@@ -0,0 +1,236 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: listener.cpp
+//
+// Description: Implement Listener class, which tracks the camera and
+// updates the RadSound listener position/orientation to match
+//
+// History: 02/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radmath/radmath.hpp>
+#include <radsoundmath.hpp>
+#include <radsound_hal.hpp>
+#include <p3d/utility.hpp>
+#include <p3d/vectorcamera.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/listener.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <camera/supercammanager.h>
+#include <camera/supercamcentral.h>
+#include <camera/supercam.h>
+#include <worldsim/avatarmanager.h>
+#include <mission/gameplaymanager.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+static const float MAX_LISTENER_DIST_FROM_AVATAR = 10.0f;
+static const float MAX_LISTENER_DIST_FROM_AVATAR_SQR = 100.0f;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// Listener::Listener
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Listener::Listener() :
+ m_theListener( NULL ),
+ m_feCamera( NULL )
+{
+}
+
+//==============================================================================
+// Listener::~Listener
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Listener::~Listener()
+{
+}
+
+//=============================================================================
+// Listener::Initialize
+//=============================================================================
+// Description: Get a handle to the RadSound listener
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Listener::Initialize( Sound::daSoundRenderingManager& renderMgr )
+{
+ m_theListener = renderMgr.GetTheListener();
+}
+
+//=============================================================================
+// Listener::Update
+//=============================================================================
+// Description: Update the listener's position/orientation
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Listener::Update( ContextEnum context )
+{
+ SuperCamCentral* scc;
+ SuperCam* camera;
+ rmt::Vector position;
+ rmt::Vector velocity;
+ rmt::Vector heading;
+ rmt::Vector up;
+ radSoundVector soundVector1;
+ radSoundVector soundVector2;
+ rmt::Vector diff;
+ Avatar* theAvatar;
+ rmt::Vector avatarPosn;
+
+
+ //
+ // Don't do anything if we don't have a listener yet
+ //
+ if( m_theListener == NULL )
+ {
+ return;
+ }
+
+ //
+ // Get the camera positioning and pass it on to the listener.
+ // QUESTION: is it valid to assume that we'll strictly use player 1?
+ // H2H positional sound hasn't really been resolved...
+ //
+ if( context == CONTEXT_FRONTEND )
+ {
+ if( m_feCamera == NULL )
+ {
+ m_feCamera = p3d::find<tVectorCamera>( "FE_Camera" );
+ if( m_feCamera == NULL )
+ {
+ //
+ // Camera hasn't been loaded yet, I guess. Early exit.
+ //
+ return;
+ }
+ }
+
+ m_feCamera->GetPosition( &position );
+ m_feCamera->GetDirection( &heading );
+ m_feCamera->GetUpVector( &up );
+ //
+ // This class doesn't provide velocities, assume zero.
+ //
+ velocity.Clear();
+ }
+ else
+ {
+ m_feCamera = NULL;
+
+ scc = GetSuperCamManager()->GetSCC( 0 );
+ rAssert( scc != NULL );
+
+ camera = scc->GetActiveSuperCam();
+ if( camera == NULL )
+ {
+ //
+ // No camera, nothing to update to.
+ //
+ return;
+ }
+
+ camera->GetPosition( &position );
+ camera->GetVelocity( &velocity );
+ camera->GetHeading( &heading );
+ heading.NormalizeSafe();
+ //
+ // Sadly, the camera defaults allow for a nonsense zero-length
+ // heading vector. Test for this case, and make up a more
+ // lenient default if found
+ //
+ if( ( heading.x == 0.0f ) && ( heading.y == 0.0f ) && ( heading.z == 0.0f ) )
+ {
+ heading.x = 1.0f;
+ }
+ camera->GetCameraUp( &up );
+ up.NormalizeSafe();
+
+ //
+ // We don't want the position to get too far away from the character, so clamp
+ // the distance to some arbitrary maximum
+ //
+ theAvatar = GetAvatarManager()->GetAvatarForPlayer( 0 );
+ if( ( theAvatar != NULL )
+ && ( GetGameplayManager() != NULL )
+ && ( !(GetGameplayManager()->IsSuperSprint()) ) )
+ {
+ theAvatar->GetPosition( avatarPosn );
+ diff = position - avatarPosn;
+ if( diff.MagnitudeSqr() > MAX_LISTENER_DIST_FROM_AVATAR_SQR )
+ {
+ diff.Normalize();
+ diff.Scale( MAX_LISTENER_DIST_FROM_AVATAR );
+ position.Add( avatarPosn, diff );
+ }
+ }
+ }
+
+ // Position
+ soundVector1.SetElements( position.x, position.y, position.z );
+ m_theListener->SetPosition( &soundVector1 );
+
+ // Velocity
+ soundVector1.SetElements( velocity.x, velocity.y, velocity.z );
+ m_theListener->SetVelocity( &soundVector1 );
+
+ // Orientation
+ soundVector1.SetElements( heading.x, heading.y, heading.z );
+ soundVector2.SetElements( up.x, up.y, up.z );
+
+ //
+ // Double-check the values, I'm not sure that DirectSound likes
+ // zero vectors
+ //
+ rAssert( ( heading.x != 0.0f )
+ || ( heading.y != 0.0f )
+ || ( heading.z != 0.0f ) );
+ rAssert( ( up.x != 0.0f ) || ( up.y != 0.0f ) || ( up.z != 0.0f ) );
+
+ m_theListener->SetOrientation( &soundVector1, &soundVector2 );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/listener.h b/game/code/sound/listener.h
new file mode 100644
index 0000000..d41a86b
--- /dev/null
+++ b/game/code/sound/listener.h
@@ -0,0 +1,56 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: listener.h
+//
+// Description: Declaration of Listener class, which tracks the camera and
+// updates the RadSound listener position/orientation to match
+//
+// History: 02/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef LISTENER_H
+#define LISTENER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <contexts/contextenum.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+//========================================
+// Forward References
+//========================================
+
+struct IRadSoundHalListener;
+class tVectorCamera;
+
+//=============================================================================
+//
+// Synopsis: Listener
+//
+//=============================================================================
+
+class Listener
+{
+ public:
+ Listener();
+ virtual ~Listener();
+
+ void Initialize( Sound::daSoundRenderingManager& renderMgr );
+ void Update( ContextEnum context );
+
+ private:
+ //Prevent wasteful constructor creation.
+ Listener( const Listener& original );
+ Listener& operator=( const Listener& rhs );
+
+ IRadSoundHalListener* m_theListener;
+
+ tVectorCamera* m_feCamera;
+};
+
+
+#endif // LISTENER_H
+
diff --git a/game/code/sound/movingpositional/actorplayer.cpp b/game/code/sound/movingpositional/actorplayer.cpp
new file mode 100644
index 0000000..2ddac62
--- /dev/null
+++ b/game/code/sound/movingpositional/actorplayer.cpp
@@ -0,0 +1,194 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: actorplayer.cpp
+//
+// Description: Implement ActorPlayer
+//
+// History: 3/10/2003 + Created -- Esan
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/actorplayer.h>
+
+#include <ai/actor/actor.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// ActorPlayer::ActorPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+ActorPlayer::ActorPlayer() :
+ m_actor( NULL )
+{
+}
+
+//=============================================================================
+// ActorPlayer::~ActorPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+ActorPlayer::~ActorPlayer()
+{
+}
+
+//=============================================================================
+// ActorPlayer::GetPosition
+//=============================================================================
+// Description: Get position of actor for moving positional sound
+//
+// Parameters: position - output parameter, to be filled with actor position
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::GetPosition( radSoundVector& position )
+{
+ rmt::Vector actorPosn;
+
+ m_actor->GetPosition( &actorPosn );
+ position.SetElements( actorPosn.x, actorPosn.y, actorPosn.z );
+}
+
+//=============================================================================
+// ActorPlayer::GetVelocity
+//=============================================================================
+// Description: Get velocity of actor for moving positional sound
+//
+// Parameters: velocity - output parameter, to be filled with actor velocity
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::GetVelocity( radSoundVector& velocity )
+{
+ //
+ // No doppler for actors, therefore make velocity zero
+ //
+ velocity.SetElements( 0.0f, 0.0f, 0.0f );
+}
+
+//=============================================================================
+// ActorPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Service stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::ServiceOncePerFrame()
+{
+ m_player.ServiceOncePerFrame();
+}
+
+//=============================================================================
+// ActorPlayer::OnPlaybackComplete
+//=============================================================================
+// Description: Sound player callback. Do nothing, leave for subclasses
+// to override
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::OnPlaybackComplete()
+{
+}
+
+//=============================================================================
+// ActorPlayer::OnSoundReady
+//=============================================================================
+// Description: Sound player callback. Do nothing, leave for subclasses
+// to override
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::OnSoundReady()
+{
+}
+
+//=============================================================================
+// ActorPlayer::playSound
+//=============================================================================
+// Description: Comment
+//
+// Parameters: settings - positional sound attributes
+// resourceName - name of sound resource to play
+// theActor - the moving object that this sound is associated with
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::playSound( positionalSoundSettings* settings,
+ const char* resourceName,
+ Actor* theActor )
+{
+ rmt::Vector posn;
+
+ m_actor = theActor;
+
+ m_player.SetPositionCarrier( *this );
+ m_player.SetParameters( settings );
+
+ theActor->GetPosition( &posn );
+ m_player.SetPosition( posn.x, posn.y, posn.z );
+
+ m_player.PlaySound( resourceName, this );
+}
+
+//=============================================================================
+// ActorPlayer::deactivate
+//=============================================================================
+// Description: Shut down the sound and disassociate from the actor
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void ActorPlayer::deactivate()
+{
+ m_actor = NULL;
+ m_player.Stop();
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/actorplayer.h b/game/code/sound/movingpositional/actorplayer.h
new file mode 100644
index 0000000..2731d6c
--- /dev/null
+++ b/game/code/sound/movingpositional/actorplayer.h
@@ -0,0 +1,77 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: actorplayer.h
+//
+// Description: Abstract base class for playing sounds associated with moving
+// state props (e.g. wasps)
+//
+// History: 3/10/2003 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef ACTORPLAYER_H
+#define ACTORPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/positionalsoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class Actor;
+
+//=============================================================================
+//
+// Synopsis: ActorPlayer
+//
+//=============================================================================
+
+class ActorPlayer : public PositionCarrier,
+ public SimpsonsSoundPlayerCallback
+{
+public:
+ ActorPlayer();
+ virtual ~ActorPlayer();
+
+ bool IsActive() { return( m_actor != NULL ); }
+ virtual void Activate( Actor* theActor ) = 0;
+
+ virtual void ServiceOncePerFrame();
+
+ //
+ // PositionCarrier functions
+ //
+ void GetPosition( radSoundVector& position );
+ void GetVelocity( radSoundVector& velocity );
+
+ //
+ // SimpsonsSoundPlayerCallback functions
+ //
+ virtual void OnSoundReady();
+ virtual void OnPlaybackComplete();
+
+protected:
+ void playSound( positionalSoundSettings* settings, const char* resourceName, Actor* theActor );
+
+ virtual void deactivate();
+
+ Actor* m_actor;
+
+ PositionalSoundPlayer m_player;
+
+private:
+ //Prevent wasteful constructor creation.
+ ActorPlayer( const ActorPlayer& actorplayer );
+ ActorPlayer& operator=( const ActorPlayer& actorplayer );
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //ACTORPLAYER_H
diff --git a/game/code/sound/movingpositional/aivehiclesoundplayer.cpp b/game/code/sound/movingpositional/aivehiclesoundplayer.cpp
new file mode 100644
index 0000000..3fc866f
--- /dev/null
+++ b/game/code/sound/movingpositional/aivehiclesoundplayer.cpp
@@ -0,0 +1,99 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: aivehiclesoundplayer.cpp
+//
+// Description: Administers the playing of sound for an AI-controlled vehicle
+//
+// History: 1/4/2003 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/aivehiclesoundplayer.h>
+
+#include <worldsim/redbrick/vehicle.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// AIVehicleSoundPlayer::AIVehicleSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AIVehicleSoundPlayer::AIVehicleSoundPlayer()
+{
+}
+
+//=============================================================================
+// AIVehicleSoundPlayer::~AIVehicleSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AIVehicleSoundPlayer::~AIVehicleSoundPlayer()
+{
+}
+
+//=============================================================================
+// AIVehicleSoundPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Adjust the pitch for this vehicle
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void AIVehicleSoundPlayer::ServiceOncePerFrame()
+{
+ float pitch;
+
+ VehiclePositionalSoundPlayer::ServiceOncePerFrame();
+
+ //
+ // Adjust pitch for vehicle speed if desired. I'll probably need to
+ // expose this for designer tuning later.
+ //
+ if( IsActive() && m_tiePitchToVelocity )
+ {
+ pitch = 0.3f + ( 0.7f * ( m_vehicle->GetSpeedKmh() / m_vehicle->mDesignerParams.mDpTopSpeedKmh ) );
+ if( pitch > 1.2f )
+ {
+ pitch = 1.2f;
+ }
+
+ m_player.SetPitch( pitch );
+ }
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/aivehiclesoundplayer.h b/game/code/sound/movingpositional/aivehiclesoundplayer.h
new file mode 100644
index 0000000..36e55ba
--- /dev/null
+++ b/game/code/sound/movingpositional/aivehiclesoundplayer.h
@@ -0,0 +1,53 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: aivehiclesoundplayer.h
+//
+// Description: Administers the playing of sound for an AI-controlled vehicle
+//
+// History: 1/4/2003 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef AIVEHICLESOUNDPLAYER_H
+#define AIVEHICLESOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radtime.hpp>
+
+#include <sound/movingpositional/vehicleposnsoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class Vehicle;
+
+//=============================================================================
+//
+// Synopsis: AIVehicleSoundPlayer
+//
+//=============================================================================
+
+class AIVehicleSoundPlayer : public VehiclePositionalSoundPlayer
+{
+ public:
+ AIVehicleSoundPlayer();
+ virtual ~AIVehicleSoundPlayer();
+
+ void ServiceOncePerFrame();
+
+ private:
+ //Prevent wasteful constructor creation.
+ AIVehicleSoundPlayer( const AIVehicleSoundPlayer& aivehiclesoundplayer );
+ AIVehicleSoundPlayer& operator=( const AIVehicleSoundPlayer& aivehiclesoundplayer );
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //AIVEHICLESOUNDPLAYER_H
diff --git a/game/code/sound/movingpositional/allmovingposn.cpp b/game/code/sound/movingpositional/allmovingposn.cpp
new file mode 100644
index 0000000..5c0b72b
--- /dev/null
+++ b/game/code/sound/movingpositional/allmovingposn.cpp
@@ -0,0 +1,9 @@
+#include <sound/movingpositional/movingsoundmanager.cpp>
+#include <sound/movingpositional/vehicleposnsoundplayer.cpp>
+#include <sound/movingpositional/aivehiclesoundplayer.cpp>
+#include <sound/movingpositional/trafficsoundplayer.cpp>
+#include <sound/movingpositional/avatarvehicleposnplayer.cpp>
+#include <sound/movingpositional/actorplayer.cpp>
+#include <sound/movingpositional/waspsoundplayer.cpp>
+#include <sound/movingpositional/platformsoundplayer.cpp>
+#include <sound/movingpositional/animobjsoundplayer.cpp> \ No newline at end of file
diff --git a/game/code/sound/movingpositional/animobjsoundplayer.cpp b/game/code/sound/movingpositional/animobjsoundplayer.cpp
new file mode 100644
index 0000000..a65c662
--- /dev/null
+++ b/game/code/sound/movingpositional/animobjsoundplayer.cpp
@@ -0,0 +1,202 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: animobjsoundplayer.cpp
+//
+// Description: Plays sound for AnimCollisionEntityDSG objects
+//
+// History: 6/5/2003 + Created -- Esan (post-beta, yay!)
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+#include <p3d/anim/pose.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/animobjsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+
+#include <events/eventdata.h>
+#include <render/DSG/animcollisionentitydsg.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// AnimObjSoundPlayer::AnimObjSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AnimObjSoundPlayer::AnimObjSoundPlayer() :
+ m_joint( NULL ),
+ m_identity( NULL )
+{
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::~AnimObjSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AnimObjSoundPlayer::~AnimObjSoundPlayer()
+{
+ if( m_identity != NULL )
+ {
+ m_identity->Release();
+ }
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::Activate
+//=============================================================================
+// Description: Start playing a sound for a particular platform
+//
+// Parameters: soundData - position and identify info for platform
+//
+// Return: void
+//
+//=============================================================================
+void AnimObjSoundPlayer::Activate( AnimSoundDSGData* soundData )
+{
+ rmt::Vector posn;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+
+ //
+ // Get the positionalSoundSettings object for the platform sound
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( ::radMakeKey32( soundData->positionalSettingName ) );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ m_identity = soundData->soundObject;
+ rAssert( m_identity != NULL );
+
+ m_joint = soundData->animJoint;
+ rAssert( m_joint != NULL );
+
+ m_player.SetPositionCarrier( *this );
+ m_player.SetParameters( parameters );
+
+ //
+ // Get world position of the platform through this joint
+ //
+ posn = m_joint->worldMatrix.Row( 3 );
+ m_player.SetPosition( posn.x, posn.y, posn.z );
+
+ //
+ // Don't buffer, to save IOP
+ //
+
+ m_player.PlaySound( soundData->soundName, NULL );
+ }
+ else
+ {
+ rDebugString( "Couldn't play anim DSG platform sound, no matching settings found" );
+ }
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::Deactivate
+//=============================================================================
+// Description: Stop playing platform sound
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void AnimObjSoundPlayer::Deactivate()
+{
+ m_player.Stop();
+
+ m_identity = NULL;
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the sound player
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void AnimObjSoundPlayer::ServiceOncePerFrame()
+{
+ m_player.ServiceOncePerFrame();
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::GetPosition
+//=============================================================================
+// Description: Get the platform's current position
+//
+// Parameters: position - filled in with platform position
+//
+// Return: void
+//
+//=============================================================================
+void AnimObjSoundPlayer::GetPosition( radSoundVector& position )
+{
+ rmt::Vector posn;
+
+ rAssert( m_joint != NULL );
+ posn = m_joint->worldMatrix.Row( 3 );
+ position.SetElements( posn.x, posn.y, posn.z );
+}
+
+//=============================================================================
+// AnimObjSoundPlayer::GetVelocity
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( radSoundVector& velocity )
+//
+// Return: void
+//
+//=============================================================================
+void AnimObjSoundPlayer::GetVelocity( radSoundVector& velocity )
+{
+ //
+ // Doppler would be a big waste on those platforms anyway
+ //
+ velocity.SetElements( 0.0f, 0.0f, 0.0f );
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/animobjsoundplayer.h b/game/code/sound/movingpositional/animobjsoundplayer.h
new file mode 100644
index 0000000..aa71fb1
--- /dev/null
+++ b/game/code/sound/movingpositional/animobjsoundplayer.h
@@ -0,0 +1,70 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: animobjsoundplayer.h
+//
+// Description: Plays sound for moving anim objs
+//
+// History: 6/5/2003 + Created -- Esan (post-beta, yay!)
+//
+//=============================================================================
+
+#ifndef ANIMOBJSOUNDPLAYER_H
+#define ANIMOBJSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/positionalsoundplayer.h>
+#include <p3d/anim/pose.hpp>
+
+//========================================
+// Forward References
+//========================================
+struct AnimSoundDSGData;
+struct radSoundVector;
+class AnimCollisionEntityDSG;
+
+//=============================================================================
+//
+// Synopsis: AnimObjSoundPlayer
+//
+//=============================================================================
+
+class AnimObjSoundPlayer : public PositionCarrier
+{
+ public:
+ AnimObjSoundPlayer();
+ virtual ~AnimObjSoundPlayer();
+
+ bool IsActive() { return( m_identity != NULL ); }
+ bool UsesObject( AnimCollisionEntityDSG* soundObject ) { return( soundObject == m_identity ); }
+ void Activate( AnimSoundDSGData* soundData );
+ void Deactivate();
+
+ void ServiceOncePerFrame();
+
+ //
+ // PositionCarrier functions
+ //
+ void GetPosition( radSoundVector& position );
+ void GetVelocity( radSoundVector& velocity );
+
+ private:
+ //Prevent wasteful constructor creation.
+ AnimObjSoundPlayer( const AnimObjSoundPlayer& animobjsoundplayer );
+ AnimObjSoundPlayer& operator=( const AnimObjSoundPlayer& animobjsoundplayer );
+
+ tPose::Joint* m_joint;
+ AnimCollisionEntityDSG* m_identity;
+
+ PositionalSoundPlayer m_player;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //ANIMOBJSOUNDPLAYER_H
diff --git a/game/code/sound/movingpositional/avatarvehicleposnplayer.cpp b/game/code/sound/movingpositional/avatarvehicleposnplayer.cpp
new file mode 100644
index 0000000..a1803b9
--- /dev/null
+++ b/game/code/sound/movingpositional/avatarvehicleposnplayer.cpp
@@ -0,0 +1,208 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: avatarvehicleposnplayer.cpp
+//
+// Description: Implement AvatarVehiclePosnPlayer
+//
+// History: 3/7/2003 + Created -- NAME
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/avatarvehicleposnplayer.h>
+
+#include <sound/avatar/carsoundparameters.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <events/eventmanager.h>
+#include <mission/gameplaymanager.h>
+#include <worldsim/redbrick/vehicle.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// AvatarVehiclePosnPlayer::AvatarVehiclePosnPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AvatarVehiclePosnPlayer::AvatarVehiclePosnPlayer()
+{
+ //
+ // Register events
+ //
+ GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_USER_VEHICLE_ADDED_TO_WORLD );
+ GetEventManager()->AddListener( this, EVENT_USER_VEHICLE_REMOVED_FROM_WORLD );
+ GetEventManager()->AddListener( this, EVENT_VEHICLE_DESTROYED );
+}
+
+//=============================================================================
+// AvatarVehiclePosnPlayer::~AvatarVehiclePosnPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+AvatarVehiclePosnPlayer::~AvatarVehiclePosnPlayer()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// AvatarVehiclePosnPlayer::HandleEvent
+//=============================================================================
+// Description: Listen for events directing us to turn positional idle
+// sound on and off
+//
+// Parameters: id - identifier for event being listened for
+// pEventData - unused
+//
+// Return: void
+//
+//=============================================================================
+void AvatarVehiclePosnPlayer::HandleEvent( EventEnum id, void* pEventData )
+{
+ switch( id )
+ {
+ case EVENT_GETOUTOFVEHICLE_END:
+ //Chuck: adding this for the stupid UFO beam, and all the wierdness that it generates.
+ if( GetGameplayManager()->GetCurrentVehicle()->IsVehicleDestroyed() == true)
+ {
+ Deactivate();
+ return;
+ }
+ StartPositionalIdle();
+ break;
+ case EVENT_VEHICLE_DESTROYED:
+ {
+ if(m_vehicle == static_cast<Vehicle*>(pEventData))
+ {
+ Deactivate();
+ }
+ break;
+ }
+
+
+ case EVENT_GETINTOVEHICLE_END:
+ Deactivate();
+ break;
+
+ case EVENT_USER_VEHICLE_ADDED_TO_WORLD:
+ StartPositionalIdle( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_USER_VEHICLE_REMOVED_FROM_WORLD:
+ Deactivate();
+ break;
+
+ default:
+ rAssertMsg( false, "Unexpected event in AvatarVehiclePosnPlayer::HandleEvent\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// AvatarVehiclePosnPlayer::StartPositionalIdle
+//=============================================================================
+// Description: Activate this player with an idle engine clip in the vehicle
+// position
+//
+// Parameters: carPtr - if vehicle is already known, this is non-NULL
+//
+// Return: void
+//
+//=============================================================================
+void AvatarVehiclePosnPlayer::StartPositionalIdle( Vehicle* carPtr /* = NULL */)
+{
+ Vehicle* theCar;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ carSoundParameters* parameters;
+ positionalSoundSettings* soundSettings;
+
+ //
+ // Get name of idle sound clip
+ //
+ if( GetGameplayManager()->GetNumPlayers() == 1 )
+ {
+ if( carPtr != NULL )
+ {
+ theCar = carPtr;
+ }
+ else
+ {
+ theCar = GetGameplayManager()->GetCurrentVehicle();
+ rAssert( theCar != NULL );
+
+ if(!theCar)
+ {
+ rDebugString( "Couldn't find avatar vehicle\n" );
+ return;
+ }
+ }
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ nameSpaceObj = nameSpace->GetInstance( theCar->GetName() );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<carSoundParameters*>( nameSpaceObj );
+
+ //
+ // Now find some positional sound settings
+ //
+ nameSpaceObj = nameSpace->GetInstance( "avatar_idle" );
+ if( nameSpaceObj != NULL )
+ {
+ soundSettings = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ Activate( soundSettings, parameters->GetEngineIdleClipName(), theCar );
+
+ m_player.SetPitch( parameters->GetIdleEnginePitch() );
+ }
+ else
+ {
+ rDebugString( "Couldn't find positional settings for avatar vehicle\n" );
+ }
+ }
+ else
+ {
+ rDebugString( "Couldn't find carSoundParameters for avatar vehicle\n" );
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
+
diff --git a/game/code/sound/movingpositional/avatarvehicleposnplayer.h b/game/code/sound/movingpositional/avatarvehicleposnplayer.h
new file mode 100644
index 0000000..c283d4d
--- /dev/null
+++ b/game/code/sound/movingpositional/avatarvehicleposnplayer.h
@@ -0,0 +1,58 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: avatarvehicleposnplayer.h
+//
+// Description: Plays positional idle for avatar vehicle
+//
+// History: 3/7/2003 + Created -- Esan
+//
+//=============================================================================
+
+#ifndef AVATARVEHICLEPOSNPLAYER_H
+#define AVATARVEHICLEPOSNPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/movingpositional/vehicleposnsoundplayer.h>
+
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: AvatarVehiclePosnPlayer
+//
+//=============================================================================
+
+class AvatarVehiclePosnPlayer : public VehiclePositionalSoundPlayer,
+ public EventListener
+{
+ public:
+ AvatarVehiclePosnPlayer();
+ virtual ~AvatarVehiclePosnPlayer();
+
+ //
+ // EventListener functions
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ void StartPositionalIdle( Vehicle* carPtr = NULL );
+
+ private:
+ //Prevent wasteful constructor creation.
+ AvatarVehiclePosnPlayer( const AvatarVehiclePosnPlayer& avatarvehicleposnplayer );
+ AvatarVehiclePosnPlayer& operator=( const AvatarVehiclePosnPlayer& avatarvehicleposnplayer );
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //AVATARVEHICLEPOSNPLAYER_H
diff --git a/game/code/sound/movingpositional/movingsoundmanager.cpp b/game/code/sound/movingpositional/movingsoundmanager.cpp
new file mode 100644
index 0000000..af4f542
--- /dev/null
+++ b/game/code/sound/movingpositional/movingsoundmanager.cpp
@@ -0,0 +1,747 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: movingsoundmanager.cpp
+//
+// Description: Manages the playing of moving sounds
+//
+// History: 1/4/2003 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/movingsoundmanager.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/avatar/carsoundparameters.h>
+
+#include <events/eventmanager.h>
+#include <events/eventdata.h>
+#include <ai/actor/actor.h>
+#include <worldsim/redbrick/vehicle.h>
+#include <constants/vehicleenum.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+tUID MovingSoundManager::s_waspUID = 0;
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// MovingSoundManager::MovingSoundManager
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+MovingSoundManager::MovingSoundManager()
+{
+ EventManager* eventMgr = GetEventManager();
+
+ //
+ // Start listening for events
+ //
+ eventMgr->AddListener( this, EVENT_CHASE_VEHICLE_SPAWNED );
+ eventMgr->AddListener( this, EVENT_CHASE_VEHICLE_DESTROYED );
+ eventMgr->AddListener( this, EVENT_TRAFFIC_SPAWN );
+ eventMgr->AddListener( this, EVENT_TRAFFIC_REMOVE );
+ eventMgr->AddListener( this, EVENT_ACTOR_CREATED );
+ eventMgr->AddListener( this, EVENT_TRAFFIC_GOT_HIT );
+ eventMgr->AddListener( this, EVENT_TRAFFIC_IMPEDED );
+ eventMgr->AddListener( this, EVENT_BIG_BOOM_SOUND );
+ eventMgr->AddListener( this, EVENT_MISSION_VEHICLE_CREATED );
+ eventMgr->AddListener( this, EVENT_MISSION_VEHICLE_RELEASED );
+ eventMgr->AddListener( this, EVENT_START_ANIMATION_SOUND );
+ eventMgr->AddListener( this, EVENT_STOP_ANIMATION_SOUND );
+ eventMgr->AddListener( this, EVENT_START_ANIM_ENTITY_DSG_SOUND );
+ eventMgr->AddListener( this, EVENT_STOP_ANIM_ENTITY_DSG_SOUND );
+ eventMgr->AddListener( this, static_cast<EventEnum>( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_ROOM_2 ) );
+ eventMgr->AddListener( this, EVENT_AVATAR_VEHICLE_TOGGLE );
+
+ if( s_waspUID == static_cast< tUID >( 0 ) )
+ {
+ s_waspUID = tEntity::MakeUID( "beecamera" );
+ }
+
+ TrafficSoundPlayer::InitializeClass( NUM_TRAFFIC_SOUND_PLAYERS );
+}
+
+//=============================================================================
+// MovingSoundManager::~MovingSoundManager
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+MovingSoundManager::~MovingSoundManager()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+void MovingSoundManager::HandleEvent( EventEnum id, void* pEventData )
+{
+ AnimSoundData* soundData;
+ AnimSoundDSGData* soundDSGData;
+ Vehicle* theCar;
+
+ switch( id )
+ {
+ case EVENT_CHASE_VEHICLE_SPAWNED:
+ //
+ // New chase AI vehicle, play siren for it
+ //
+ addAISound( "siren", static_cast<Vehicle*>(pEventData), false );
+ break;
+
+ case EVENT_CHASE_VEHICLE_DESTROYED:
+ //
+ // Chase AI vehicle gone, stop its siren sound
+ //
+ stopAISound( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_MISSION_VEHICLE_CREATED:
+ //
+ // New mission AI vehicle, play engine for it
+ //
+ theCar = static_cast<Vehicle*>(pEventData);
+ addAISound( getPositionalSettingName( theCar, true ), theCar, true );
+ break;
+
+ case EVENT_MISSION_VEHICLE_RELEASED:
+ //
+ // Mission AI vehicle gone, stop its engine
+ //
+ stopAISound( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_TRAFFIC_SPAWN:
+ //
+ // New traffic vehicle, play engine sound for it
+ //
+ theCar = static_cast<Vehicle*>(pEventData);
+ addTrafficSound( getPositionalSettingName( theCar, false ), theCar, true );
+ break;
+
+ case EVENT_TRAFFIC_REMOVE:
+ //
+ // Traffic vehicle gone
+ //
+ stopTrafficSound( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_AVATAR_VEHICLE_TOGGLE:
+ //
+ // Player avatar has gotten in or out of a vehicle. If it's a traffic
+ // vehicle with an overlay clip, we'll need to toggle it on or off.
+ //
+ toggleOverlayClip( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_ACTOR_CREATED:
+ startWaspSound( static_cast<Actor*>(pEventData) );
+ break;
+
+ case EVENT_TRAFFIC_GOT_HIT:
+ case EVENT_TRAFFIC_IMPEDED:
+ handleTrafficHornEvent( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_BIG_BOOM_SOUND:
+ makeCarGoBoom( static_cast<Vehicle*>(pEventData) );
+ break;
+
+ case EVENT_START_ANIMATION_SOUND:
+ soundData = static_cast<AnimSoundData*>(pEventData);
+ if( soundData->animJoint != NULL )
+ {
+ startPlatformSound( soundData );
+ }
+ break;
+
+ case EVENT_STOP_ANIMATION_SOUND:
+ stopPlatformSound( static_cast<ActionButton::AnimSwitch*>(pEventData) );
+ break;
+
+ case EVENT_START_ANIM_ENTITY_DSG_SOUND:
+ soundDSGData = static_cast<AnimSoundDSGData*>(pEventData);
+ startAnimObjSound( soundDSGData );
+ break;
+
+ case EVENT_STOP_ANIM_ENTITY_DSG_SOUND:
+ stopAnimObjSound( static_cast<AnimCollisionEntityDSG*>(pEventData) );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_ROOM_2:
+ //
+ // If we're hitting this ambience boundary, then we're leaving the platform
+ // room, so kill all the platforms and save ourselves some streamers.
+ //
+ //stopAllPlatforms();
+ break;
+
+ default:
+ rAssertMsg( false, "Unexpected event in MovingSoundManager\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::ServiceOncePerFrame
+//=============================================================================
+// Description: Do once-per-frame update stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::ServiceOncePerFrame()
+{
+ int i;
+
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ m_trafficPlayer[i].ServiceOncePerFrame();
+ }
+ for( i = 0; i < NUM_AI_SOUND_PLAYERS; i++ )
+ {
+ m_aiPlayer[i].ServiceOncePerFrame();
+ }
+ for( i = 0; i < NUM_PLATFORM_SOUND_PLAYERS; i++ )
+ {
+ m_platformPlayer[i].ServiceOncePerFrame();
+ }
+ for( i = 0; i < NUM_ANIM_OBJ_SOUND_PLAYERS; i++ )
+ {
+ m_animObjPlayer[i].ServiceOncePerFrame();
+ }
+ for( i = 0; i < NUM_WASP_SOUND_PLAYERS; i++ )
+ {
+ m_waspPlayer[i].ServiceOncePerFrame();
+ }
+
+ m_avatarVehiclePlayer.ServiceOncePerFrame();
+
+ TrafficSoundPlayer::ServiceTimerList();
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// MovingSoundManager::addTrafficSound
+//=============================================================================
+// Description: Find an inactive sound player and start it up with the given
+// sound and vehicle
+//
+// Parameters: soundName - name of sound resource to play for vehicle
+// vehiclePtr - vehicle whose position the sound will be
+// played from
+// tiePitchToVelocity - set to true if we want the sound pitch
+// to vary (i.e. engine sound)
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::addTrafficSound( const char* soundName, Vehicle* vehiclePtr, bool tiePitchToVelocity )
+{
+ int i;
+ carSoundParameters* carSettings;
+
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ if( !m_trafficPlayer[i].IsActive() )
+ {
+ m_trafficPlayer[i].ActivateByName( soundName, vehiclePtr );
+ m_trafficPlayer[i].TiePitchToVelocity( tiePitchToVelocity );
+
+ //
+ // Play overlay clips for traffic if they've got 'em (e.g. quimby truck)
+ //
+ if( hasOverlayClip( vehiclePtr, &carSettings ) )
+ {
+ m_trafficPlayer[i].AddOverlayClip( carSettings, soundName );
+ }
+ break;
+ }
+ }
+
+#ifdef RAD_DEBUG
+ if( i == NUM_TRAFFIC_SOUND_PLAYERS )
+ {
+ rDebugString( "AI Vehicle sound dropped" );
+ }
+#endif
+}
+
+//=============================================================================
+// MovingSoundManager::stopTrafficSound
+//=============================================================================
+// Description: Stop the sound coming from the given vehicle
+//
+// Parameters: vehiclePtr - vehicle whose sound is to be stopped.
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::stopTrafficSound( Vehicle* vehiclePtr )
+{
+ int i;
+
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ if( m_trafficPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ m_trafficPlayer[i].Deactivate();
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::addAISound
+//=============================================================================
+// Description: Find an inactive sound player and start it up with the given
+// sound and vehicle
+//
+// Parameters: soundName - name of sound resource to play for vehicle
+// vehiclePtr - vehicle whose position the sound will be
+// played from
+// tiePitchToVelocity - set to true if we want the sound pitch
+// to vary (i.e. engine sound)
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::addAISound( const char* soundName, Vehicle* vehiclePtr, bool tiePitchToVelocity )
+{
+ int i;
+
+ for( i = 0; i < NUM_AI_SOUND_PLAYERS; i++ )
+ {
+ if( !m_aiPlayer[i].IsActive() )
+ {
+ m_aiPlayer[i].ActivateByName( soundName, vehiclePtr );
+ m_aiPlayer[i].TiePitchToVelocity( tiePitchToVelocity );
+ break;
+ }
+ }
+
+#ifdef RAD_DEBUG
+ if( i == NUM_AI_SOUND_PLAYERS )
+ {
+ rDebugString( "AI Vehicle sound dropped" );
+ }
+#endif
+}
+
+//=============================================================================
+// MovingSoundManager::stopAISound
+//=============================================================================
+// Description: Stop the sound coming from the given vehicle
+//
+// Parameters: vehiclePtr - vehicle whose sound is to be stopped.
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::stopAISound( Vehicle* vehiclePtr )
+{
+ int i;
+
+ for( i = 0; i < NUM_AI_SOUND_PLAYERS; i++ )
+ {
+ if( m_aiPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ m_aiPlayer[i].Deactivate();
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::handleTrafficHornEvent
+//=============================================================================
+// Description: Horn the horn for the specified car
+//
+// Parameters: vehiclePtr - pointer to vehicle to honk
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::handleTrafficHornEvent( Vehicle* vehiclePtr )
+{
+ int i;
+
+ rAssert( vehiclePtr != NULL );
+
+ //
+ // Find the car matching the vehicle pointer
+ //
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ if( m_trafficPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ m_trafficPlayer[i].HonkHorn();
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::makeCarGoBoom
+//=============================================================================
+// Description: If the vehicle in the explosion event matches one of our
+// vehicles, play a positional explosion
+//
+// Parameters: vehiclePtr - pointer to exploding car
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::makeCarGoBoom( Vehicle* vehiclePtr )
+{
+ int i;
+
+ rAssert( vehiclePtr != NULL );
+
+ if( vehiclePtr->mVehicleType == VT_USER )
+ {
+ //
+ // User vehicles are handled by the sound effect system
+ //
+ return;
+ }
+
+ //
+ // Find the car matching the vehicle pointer
+ //
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ if( m_trafficPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ m_trafficPlayer[i].BlowUp();
+ break;
+ }
+ }
+
+ if( i == NUM_TRAFFIC_SOUND_PLAYERS )
+ {
+ //
+ // It's not a traffic vehicle, try AI
+ //
+ for( i = 0; i < NUM_AI_SOUND_PLAYERS; i++ )
+ {
+ if( m_aiPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ m_aiPlayer[i].BlowUp();
+ break;
+ }
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::startPlatformSound
+//=============================================================================
+// Description: Find a player for the moving platform and hook it up
+//
+// Parameters: soundData - data we need to identify platform identity and
+// position
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::startPlatformSound( AnimSoundData* soundData )
+{
+ int i;
+
+ for( i = 0; i < NUM_PLATFORM_SOUND_PLAYERS; i++ )
+ {
+ if( !m_platformPlayer[i].IsActive() )
+ {
+ m_platformPlayer[i].Activate( soundData );
+ break;
+ }
+ }
+
+#ifdef RAD_DEBUG
+ if( i == NUM_PLATFORM_SOUND_PLAYERS )
+ {
+ rDebugString( "AI Vehicle sound dropped" );
+ }
+#endif
+}
+
+//=============================================================================
+// MovingSoundManager::stopPlatformSound
+//=============================================================================
+// Description: Find the player for this object and stop it
+//
+// Parameters: soundObject - platform identity
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::stopPlatformSound( ActionButton::AnimSwitch* soundObject )
+{
+ int i;
+
+ for( i = 0; i < NUM_PLATFORM_SOUND_PLAYERS; i++ )
+ {
+ if( m_platformPlayer[i].UsesObject( soundObject ) )
+ {
+ m_platformPlayer[i].Deactivate();
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::stopAllPlatforms
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::stopAllPlatforms()
+{
+ int i;
+
+ for( i = 0; i < NUM_PLATFORM_SOUND_PLAYERS; i++ )
+ {
+ m_platformPlayer[i].Deactivate();
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::startAnimObjSound
+//=============================================================================
+// Description: Find a player for the moving platform and hook it up
+//
+// Parameters: soundData - data we need to identify platform identity and
+// position
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::startAnimObjSound( AnimSoundDSGData* soundData )
+{
+ int i;
+
+ for( i = 0; i < NUM_ANIM_OBJ_SOUND_PLAYERS; i++ )
+ {
+ if( !m_animObjPlayer[i].IsActive() )
+ {
+ m_animObjPlayer[i].Activate( soundData );
+ break;
+ }
+ }
+
+#ifdef RAD_DEBUG
+ if( i == NUM_ANIM_OBJ_SOUND_PLAYERS )
+ {
+ rDebugString( "AnimObj sound dropped" );
+ }
+#endif
+}
+
+//=============================================================================
+// MovingSoundManager::stopAnimObjSound
+//=============================================================================
+// Description: Find the player for this object and stop it
+//
+// Parameters: soundObject - platform identity
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::stopAnimObjSound( AnimCollisionEntityDSG* soundObject )
+{
+ int i;
+
+ for( i = 0; i < NUM_ANIM_OBJ_SOUND_PLAYERS; i++ )
+ {
+ if( m_animObjPlayer[i].UsesObject( soundObject ) )
+ {
+ m_animObjPlayer[i].Deactivate();
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::hasOverlayClip
+//=============================================================================
+// Description: Check whether the given vehicle has an overlay clip that
+// we want to move around with its engine sounds
+//
+// Parameters: vehiclePtr - vehicle we're finding a clip name for
+// parameters - pointer which is pointed at car sound settings
+// if clip exists, NULL otherwise
+//
+// Return: true if overlay clip found, false otherwise
+//
+//=============================================================================
+bool MovingSoundManager::hasOverlayClip( Vehicle* vehiclePtr, carSoundParameters** parameters )
+{
+ IRadNameSpace* nameSpace;
+ const char* clipName;
+ bool retVal = false;
+
+ rAssert( vehiclePtr != NULL );
+ rAssert( parameters != NULL );
+
+ //
+ // Ignore the husk
+ //
+ if( vehiclePtr->mVehicleID == VehicleEnum::HUSKA )
+ {
+ return( false );
+ }
+
+ //
+ // Find the settings for this positional sound first
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ *parameters = reinterpret_cast<carSoundParameters*>( nameSpace->GetInstance( vehiclePtr->GetName() ) );
+ if( *parameters != NULL )
+ {
+ clipName = (*parameters)->GetOverlayClipName();
+ if( clipName != NULL )
+ {
+ retVal = true;
+ }
+ else
+ {
+ *parameters = NULL;
+ }
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// MovingSoundManager::toggleOverlayClip
+//=============================================================================
+// Description: Need to switch the overlay clip for the given vehicle
+// if it's a traffic vehicle, because the player is using it
+//
+// Parameters: vehiclePtr - vehicle being gotten in or out of
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::toggleOverlayClip( Vehicle* vehiclePtr )
+{
+ int i;
+ carSoundParameters* parameters;
+
+ for( i = 0; i < NUM_TRAFFIC_SOUND_PLAYERS; i++ )
+ {
+ if( m_trafficPlayer[i].UsesVehicle( vehiclePtr ) )
+ {
+ if( hasOverlayClip( vehiclePtr, &parameters ) )
+ {
+ m_trafficPlayer[i].ToggleOverlayClip( parameters, getPositionalSettingName( vehiclePtr, false ) );
+ }
+ }
+ }
+}
+
+//=============================================================================
+// MovingSoundManager::getPositionalSettingName
+//=============================================================================
+// Description: Figure out which positional values to use for traffic sounds
+// for the given vehicle.
+//
+// Parameters: vehiclePtr - traffic vehicle
+// isMissionVehicle - if true, use louder positional setting
+//
+// Return: name of positional settings object
+//
+//=============================================================================
+const char* MovingSoundManager::getPositionalSettingName( Vehicle* vehiclePtr, bool isMissionVehicle )
+{
+ VehicleEnum::VehicleID carID;
+ const char* settingName;
+
+ rAssert( vehiclePtr != NULL );
+
+ carID = vehiclePtr->mVehicleID;
+ if( carID == VehicleEnum::COFFIN )
+ {
+ settingName = "coffin_posn";
+ }
+ else if( carID == VehicleEnum::HALLO )
+ {
+ settingName = "hearse_posn";
+ }
+ else if( carID == VehicleEnum::CHEARS )
+ {
+ settingName = "chase_hearse_posn";
+ }
+ else if( isMissionVehicle )
+ {
+ settingName = "loud_ai_vehicle";
+ }
+ else
+ {
+ settingName = "generic_traffic";
+ }
+
+ return( settingName );
+}
+
+//=============================================================================
+// MovingSoundManager::startWaspSound
+//=============================================================================
+// Description: Start making waspy noises
+//
+// Parameters: wasp - wasp to start making noise
+//
+// Return: void
+//
+//=============================================================================
+void MovingSoundManager::startWaspSound( Actor* wasp )
+{
+ int i;
+
+ if( wasp->GetStatePropUID() == s_waspUID )
+ {
+ for( i = 0; i < NUM_WASP_SOUND_PLAYERS; i++ )
+ {
+ if( !m_waspPlayer[i].IsActive() )
+ {
+ m_waspPlayer[i].Activate( wasp );
+ break;
+ }
+ }
+ }
+}
diff --git a/game/code/sound/movingpositional/movingsoundmanager.h b/game/code/sound/movingpositional/movingsoundmanager.h
new file mode 100644
index 0000000..1e0d133
--- /dev/null
+++ b/game/code/sound/movingpositional/movingsoundmanager.h
@@ -0,0 +1,108 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: movingsoundmanager.h
+//
+// Description: Manages the playing of moving positional sounds
+//
+// History: 1/4/2003 + Created -- Esan
+//
+//=============================================================================
+
+#ifndef MOVINGSOUNDMANAGER_H
+#define MOVINGSOUNDMANAGER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <p3d/p3dtypes.hpp>
+
+#include <events/eventlistener.h>
+#include <sound/movingpositional/trafficsoundplayer.h>
+#include <sound/movingpositional/aivehiclesoundplayer.h>
+#include <sound/movingpositional/avatarvehicleposnplayer.h>
+#include <sound/movingpositional/waspsoundplayer.h>
+#include <sound/movingpositional/platformsoundplayer.h>
+#include <sound/movingpositional/animobjsoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class Vehicle;
+class carSoundParameters;
+struct AnimSoundData;
+struct AnimSoundDSGData;
+class AnimCollisionEntityDSG;
+
+namespace ActionButton
+{
+ class AnimSwitch;
+};
+
+//=============================================================================
+//
+// Synopsis: MovingSoundManager
+//
+//=============================================================================
+
+class MovingSoundManager : public EventListener
+{
+ public:
+ MovingSoundManager();
+ virtual ~MovingSoundManager();
+
+ void ServiceOncePerFrame();
+
+ //
+ // EventListener functions
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ MovingSoundManager( const MovingSoundManager& original );
+ MovingSoundManager& operator=( const MovingSoundManager& rhs );
+
+ void addTrafficSound( const char* soundName, Vehicle* vehiclePtr, bool tiePitchToVelocity );
+ void stopTrafficSound( Vehicle* vehiclePtr );
+ void addAISound( const char* soundName, Vehicle* vehiclePtr, bool tiePitchToVelocity );
+ void stopAISound( Vehicle* vehiclePtr );
+ void handleTrafficHornEvent( Vehicle* vehiclePtr );
+ void makeCarGoBoom( Vehicle* vehiclePtr );
+ void startPlatformSound( AnimSoundData* soundData );
+ void stopPlatformSound( ActionButton::AnimSwitch* soundObject );
+ void stopAllPlatforms();
+ void startAnimObjSound( AnimSoundDSGData* soundData );
+ void stopAnimObjSound( AnimCollisionEntityDSG* soundObject );
+ void startWaspSound( Actor* wasp );
+ bool hasOverlayClip( Vehicle* vehiclePtr, carSoundParameters** parameters );
+ void toggleOverlayClip( Vehicle* vehiclePtr );
+ const char* getPositionalSettingName( Vehicle* vehiclePtr, bool isMissionVehicle );
+
+ const static int NUM_TRAFFIC_SOUND_PLAYERS = 5;
+ TrafficSoundPlayer m_trafficPlayer[NUM_TRAFFIC_SOUND_PLAYERS];
+
+ const static int NUM_AI_SOUND_PLAYERS = 5;
+ AIVehicleSoundPlayer m_aiPlayer[NUM_AI_SOUND_PLAYERS];
+
+ AvatarVehiclePosnPlayer m_avatarVehiclePlayer;
+
+ const static int NUM_WASP_SOUND_PLAYERS = 2;
+ WaspSoundPlayer m_waspPlayer[NUM_WASP_SOUND_PLAYERS];
+
+ const static int NUM_PLATFORM_SOUND_PLAYERS = 8;
+ PlatformSoundPlayer m_platformPlayer[NUM_PLATFORM_SOUND_PLAYERS];
+
+ const static int NUM_ANIM_OBJ_SOUND_PLAYERS = 5;
+ AnimObjSoundPlayer m_animObjPlayer[NUM_ANIM_OBJ_SOUND_PLAYERS];
+
+ static tUID s_waspUID;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //MOVINGSOUNDMANAGER_H
diff --git a/game/code/sound/movingpositional/platformsoundplayer.cpp b/game/code/sound/movingpositional/platformsoundplayer.cpp
new file mode 100644
index 0000000..2803e8a
--- /dev/null
+++ b/game/code/sound/movingpositional/platformsoundplayer.cpp
@@ -0,0 +1,209 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: platformsoundplayer.cpp
+//
+// Description: Plays sound for moving platforms
+//
+// History: 5/29/2003 + Created -- Esan (two days to beta, yay!)
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+#include <p3d/anim/pose.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/platformsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+
+#include <events/eventdata.h>
+#include <ai/actionbuttonhandler.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// PlatformSoundPlayer::PlatformSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+PlatformSoundPlayer::PlatformSoundPlayer() :
+ m_joint( NULL ),
+ m_identity( NULL )
+{
+}
+
+//=============================================================================
+// PlatformSoundPlayer::~PlatformSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+PlatformSoundPlayer::~PlatformSoundPlayer()
+{
+ if( m_identity != NULL )
+ {
+ //m_identity->Release();
+ }
+}
+
+//=============================================================================
+// PlatformSoundPlayer::Activate
+//=============================================================================
+// Description: Start playing a sound for a particular platform
+//
+// Parameters: soundData - position and identify info for platform
+//
+// Return: void
+//
+//=============================================================================
+void PlatformSoundPlayer::Activate( AnimSoundData* soundData )
+{
+ rmt::Vector posn;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+
+ //
+ // Get the positionalSoundSettings object for the platform sound
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( ::radMakeKey32( soundData->positionalSettingName ) );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ m_joint = soundData->animJoint;
+ rAssert( m_joint != NULL );
+
+ m_identity = soundData->soundObject;
+ rAssert( m_identity != NULL );
+ //m_identity->AddRef();
+
+ m_player.SetPositionCarrier( *this );
+ m_player.SetParameters( parameters );
+
+ //
+ // Get world position of the platform through this joint
+ //
+ posn = m_joint->worldMatrix.Row( 3 );
+ m_player.SetPosition( posn.x, posn.y, posn.z );
+
+ //
+ // Don't buffer, to save IOP
+ //
+
+ m_player.PlaySound( soundData->soundName, NULL );
+ }
+ else
+ {
+ rDebugString( "Couldn't play platform sound, no matching settings found" );
+ }
+}
+
+//=============================================================================
+// PlatformSoundPlayer::Deactivate
+//=============================================================================
+// Description: Stop playing platform sound
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void PlatformSoundPlayer::Deactivate()
+{
+ m_player.Stop();
+
+ if( m_identity != NULL )
+ {
+ //m_identity->Release();
+ m_identity = NULL;
+ }
+
+ m_joint = NULL;
+}
+
+//=============================================================================
+// PlatformSoundPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the sound player
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void PlatformSoundPlayer::ServiceOncePerFrame()
+{
+ m_player.ServiceOncePerFrame();
+}
+
+//=============================================================================
+// PlatformSoundPlayer::GetPosition
+//=============================================================================
+// Description: Get the platform's current position
+//
+// Parameters: position - filled in with platform position
+//
+// Return: void
+//
+//=============================================================================
+void PlatformSoundPlayer::GetPosition( radSoundVector& position )
+{
+ rmt::Vector posn;
+
+ rAssert( m_joint != NULL );
+ posn = m_joint->worldMatrix.Row( 3 );
+ position.SetElements( posn.x, posn.y, posn.z );
+}
+
+//=============================================================================
+// PlatformSoundPlayer::GetVelocity
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( radSoundVector& velocity )
+//
+// Return: void
+//
+//=============================================================================
+void PlatformSoundPlayer::GetVelocity( radSoundVector& velocity )
+{
+ //
+ // Doppler would be a big waste on those platforms anyway
+ //
+ velocity.SetElements( 0.0f, 0.0f, 0.0f );
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/platformsoundplayer.h b/game/code/sound/movingpositional/platformsoundplayer.h
new file mode 100644
index 0000000..67bcdd1
--- /dev/null
+++ b/game/code/sound/movingpositional/platformsoundplayer.h
@@ -0,0 +1,74 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: platformsoundplayer.h
+//
+// Description: Plays sound for moving platforms
+//
+// History: 5/29/2003 + Created -- Esan (two days to beta, yay!)
+//
+//=============================================================================
+
+#ifndef PLATFORMSOUNDPLAYER_H
+#define PLATFORMSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/positionalsoundplayer.h>
+#include <p3d/anim/pose.hpp>
+
+//========================================
+// Forward References
+//========================================
+struct AnimSoundData;
+struct radSoundVector;
+
+namespace ActionButton
+{
+ class AnimSwitch;
+};
+
+//=============================================================================
+//
+// Synopsis: PlatformSoundPlayer
+//
+//=============================================================================
+
+class PlatformSoundPlayer : public PositionCarrier
+{
+ public:
+ PlatformSoundPlayer();
+ virtual ~PlatformSoundPlayer();
+
+ bool IsActive() { return( m_identity != NULL ); }
+ bool UsesObject( ActionButton::AnimSwitch* soundObject ) { return( soundObject == m_identity ); }
+ void Activate( AnimSoundData* soundData );
+ void Deactivate();
+
+ void ServiceOncePerFrame();
+
+ //
+ // PositionCarrier functions
+ //
+ void GetPosition( radSoundVector& position );
+ void GetVelocity( radSoundVector& velocity );
+
+ private:
+ //Prevent wasteful constructor creation.
+ PlatformSoundPlayer( const PlatformSoundPlayer& platformsoundplayer );
+ PlatformSoundPlayer& operator=( const PlatformSoundPlayer& platformsoundplayer );
+
+ tPose::Joint* m_joint;
+ ActionButton::AnimSwitch* m_identity;
+
+ PositionalSoundPlayer m_player;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //PLATFORMSOUNDPLAYER_H
diff --git a/game/code/sound/movingpositional/trafficsoundplayer.cpp b/game/code/sound/movingpositional/trafficsoundplayer.cpp
new file mode 100644
index 0000000..5013d74
--- /dev/null
+++ b/game/code/sound/movingpositional/trafficsoundplayer.cpp
@@ -0,0 +1,458 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: trafficsoundplayer.cpp
+//
+// Description: Administers the playing of sound for a traffic vehicle
+//
+// History: 1/4/2003 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/trafficsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundfx/positionalsoundsettings.h>
+#include <sound/avatar/carsoundparameters.h>
+
+#include <worldsim/redbrick/vehicle.h>
+#include <worldsim/redbrick/trafficlocomotion.h>
+#include <worldsim/traffic/trafficmanager.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+IRadTimerList* TrafficSoundPlayer::s_timerList = NULL;
+
+static const unsigned int s_minHonkShortMsecs = 250;
+static const unsigned int s_maxHonkShortMsecs = 500;
+static const unsigned int s_minHonkLongMsecs = 500;
+static const unsigned int s_maxHonkLongMsecs = 1000;
+static const unsigned int s_minHonkDelay = 250;
+static const unsigned int s_maxHonkDelay = 500;
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// TrafficSoundPlayer::TrafficSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+TrafficSoundPlayer::TrafficSoundPlayer( ) :
+ m_hornTimer( NULL ),
+ m_vehicleParameters( NULL ),
+ m_honkCount( 0 ),
+ m_pitchMultiplier( 1.0f )
+{
+}
+
+//=============================================================================
+// TrafficSoundPlayer::~TrafficSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+TrafficSoundPlayer::~TrafficSoundPlayer()
+{
+ if( m_hornTimer != NULL )
+ {
+ m_hornTimer->UnregisterCallback( this );
+ m_hornTimer->Release();
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::InitializeClass
+//=============================================================================
+// Description: Prep the timer list for tracking horn times
+//
+// Parameters: numVehicles - number of cars, and therefore timers we need
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::InitializeClass( unsigned int numVehicles )
+{
+ if( s_timerList == NULL )
+ {
+ ::radTimeCreateList( &s_timerList, numVehicles, GMA_AUDIO_PERSISTENT );
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::Activate
+//=============================================================================
+// Description: Before we start playing any sound, set a random pitch adjustment
+// to give this thing a little variety
+//
+// Parameters: soundSettings - positional stuff for traffic
+// resourceName - name of engine sound
+// theCar - pointer to traffic vehicle object
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::Activate( positionalSoundSettings* soundSettings,
+ const char* resourceName,
+ Vehicle* theCar )
+{
+ unsigned int randomNumber;
+
+ //
+ // Pick a random pitch multiplier from 0.8 to 1.2. Arbitrary numbers.
+ //
+ randomNumber = rand() % 401;
+ m_pitchMultiplier = 0.8f + ( static_cast<float>(randomNumber) / 1000.0f );
+
+ VehiclePositionalSoundPlayer::Activate( soundSettings, resourceName, theCar );
+
+ m_player.SetPitch( 0.5f );
+}
+
+//=============================================================================
+// TrafficSoundPlayer::Deactivate
+//=============================================================================
+// Description: Stop playing sound.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::Deactivate()
+{
+ VehiclePositionalSoundPlayer::Deactivate();
+
+ if( m_hornTimer != NULL )
+ {
+ m_hornTimer->UnregisterCallback( this );
+ m_hornTimer->Release();
+ m_hornTimer = NULL;
+ }
+
+ m_hornPlayer.Stop();
+
+ m_overlayPlayer.Stop();
+}
+
+//=============================================================================
+// TrafficSoundPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Adjust the pitch for this vehicle
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::ServiceOncePerFrame()
+{
+ float pitch;
+
+ VehiclePositionalSoundPlayer::ServiceOncePerFrame();
+
+ //
+ // Adjust pitch for vehicle speed if desired. I'll probably need to
+ // expose this for designer tuning later.
+ //
+ if( IsActive() && m_tiePitchToVelocity )
+ {
+ pitch = 0.5f + ( 0.5f * ( m_vehicle->mTrafficLocomotion->mActualSpeed / TrafficManager::GetInstance()->GetDesiredTrafficSpeed() ) );
+ pitch *= m_pitchMultiplier;
+
+ //
+ // Arbitrary cap, just in case. Being paranoid.
+ //
+ if( pitch > 1.5f )
+ {
+ pitch = 1.5f;
+ }
+
+ m_player.SetPitch( pitch );
+ }
+
+ m_hornPlayer.ServiceOncePerFrame();
+ m_overlayPlayer.ServiceOncePerFrame();
+}
+
+//=============================================================================
+// TrafficSoundPlayer::ServiceTimerList
+//=============================================================================
+// Description: Service the timer list. Static function, since we only
+// need to service this static member once per frame, not once
+// per object per frame.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::ServiceTimerList()
+{
+ if( s_timerList != NULL )
+ {
+ s_timerList->Service();
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::OnTimerDone
+//=============================================================================
+// Description: Stop the traffic horn associated with this timer
+//
+// Parameters: elapsedTime - unused
+// pUserData - unused
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::OnTimerDone( unsigned int elapsedTime, void * pUserData )
+{
+ unsigned int timeout;
+ rmt::Vector position;
+ positionalSoundSettings* settings;
+ IRadNameSpace* nameSpace;
+
+ if( m_hornPlayer.IsInUse() )
+ {
+ m_hornPlayer.Stop();
+
+ if( m_honkCount == 0 )
+ {
+ //
+ // Last honk done
+ //
+ m_hornTimer->Release();
+ m_hornTimer = NULL;
+ }
+ else
+ {
+ //
+ // Random amount of silence before next honk
+ //
+ timeout = s_minHonkDelay + ( rand() % ( s_maxHonkDelay - s_minHonkDelay ) );
+ m_hornTimer->SetTimeout( timeout );
+ m_hornTimer->Start();
+ }
+ }
+ else
+ {
+ //
+ // Silence done, start another honk
+ //
+ rAssert( m_honkCount > 0 );
+
+ //
+ // Find the settings for this positional sound first
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ settings = reinterpret_cast<positionalSoundSettings*>( nameSpace->GetInstance( "traffic_horn" ) );
+ rAssert( settings != NULL );
+
+ m_vehicle->GetPosition( &position );
+ m_hornPlayer.SetPosition( position.x, position.y, position.z );
+ m_hornPlayer.SetPositionCarrier( *this );
+ m_hornPlayer.SetParameters( settings );
+ m_hornPlayer.PlaySound( "horn" );
+
+ --m_honkCount;
+
+ //
+ // Reset the timer
+ //
+ if( m_honkCount > 0 )
+ {
+ timeout = s_minHonkShortMsecs + ( rand() % ( s_maxHonkShortMsecs - s_minHonkShortMsecs ) );
+ }
+ else
+ {
+ timeout = s_minHonkLongMsecs + ( rand() % ( s_maxHonkLongMsecs - s_minHonkLongMsecs ) );
+ }
+
+ m_hornTimer->SetTimeout( timeout );
+ m_hornTimer->Start();
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::HonkHorn
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::HonkHorn()
+{
+ unsigned int hornTime;
+ rmt::Vector position;
+ positionalSoundSettings* settings;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ float diceRoll;
+ float probability;
+
+ rAssert( m_vehicle != NULL );
+
+ if( m_hornTimer != NULL )
+ {
+ //
+ // Already honking
+ //
+ return;
+ }
+
+ //
+ // Find the settings for this positional sound first
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( "traffic_horn" );
+ if( nameSpaceObj != NULL )
+ {
+ settings = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ probability = settings->GetPlaybackProbability();
+ if( probability < 1.0f )
+ {
+ //
+ // Random play
+ //
+ diceRoll = (static_cast<float>( rand() % 100 )) / 100.0f;
+ if( diceRoll >= probability )
+ {
+ return;
+ }
+ }
+
+ //
+ // Pick a random number of honks from 1 to 3. Pick a random time for
+ // the honk, giving the last one a better chance of being longer.
+ //
+ m_honkCount = rand() % 3;
+ if( m_honkCount > 0 )
+ {
+ hornTime = s_minHonkShortMsecs + ( rand() % ( s_maxHonkShortMsecs - s_minHonkShortMsecs ) );
+ }
+ else
+ {
+ hornTime = s_minHonkLongMsecs + ( rand() % ( s_maxHonkLongMsecs - s_minHonkLongMsecs ) );
+ }
+
+ s_timerList->CreateTimer( &m_hornTimer, hornTime, this, NULL, true,
+ IRadTimer::ResetModeOneShot );
+
+ //
+ // Start honking
+ //
+ m_vehicle->GetPosition( &position );
+ m_hornPlayer.SetPosition( position.x, position.y, position.z );
+ m_hornPlayer.SetPositionCarrier( *this );
+ m_hornPlayer.SetParameters( settings );
+ m_hornPlayer.PlaySound( "horn" );
+ }
+ else
+ {
+ rDebugString( "Couldn't find settings for traffic horn\n" );
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::AddOverlayClip
+//=============================================================================
+// Description: Play a positional clip along with the engine
+//
+// Parameters: parameters - car sound description for traffic vehicle
+// posnSettingsName - name of object with positional settings
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::AddOverlayClip( carSoundParameters* parameters, const char* posnSettingsName )
+{
+ const char* clipName;
+ positionalSoundSettings* settings;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ rmt::Vector position;
+
+ rAssert( parameters != NULL );
+
+ m_vehicleParameters = parameters;
+ clipName = parameters->GetOverlayClipName();
+ if( clipName != NULL )
+ {
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( posnSettingsName );
+ if( nameSpaceObj != NULL )
+ {
+ settings = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ m_vehicle->GetPosition( &position );
+ m_overlayPlayer.SetPosition( position.x, position.y, position.z );
+ m_overlayPlayer.SetPositionCarrier( *this );
+ m_overlayPlayer.SetParameters( settings );
+ m_overlayPlayer.PlaySound( clipName );
+ }
+ else
+ {
+ rTuneAssertMsg( false, "Huh? Positional settings for overlay clip disappeared" );
+ }
+ }
+}
+
+//=============================================================================
+// TrafficSoundPlayer::ToggleOverlayClip
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( carSoundParameters* parameters, const char* posnSettingsName )
+//
+// Return: void
+//
+//=============================================================================
+void TrafficSoundPlayer::ToggleOverlayClip( carSoundParameters* parameters, const char* posnSettingsName )
+{
+ if( m_overlayPlayer.IsInUse() )
+ {
+ m_overlayPlayer.Stop();
+ }
+ else
+ {
+ AddOverlayClip( parameters, posnSettingsName );
+ }
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/trafficsoundplayer.h b/game/code/sound/movingpositional/trafficsoundplayer.h
new file mode 100644
index 0000000..1f5472e
--- /dev/null
+++ b/game/code/sound/movingpositional/trafficsoundplayer.h
@@ -0,0 +1,83 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: trafficsoundplayer.h
+//
+// Description: Administers the playing of sound for a traffic vehicle
+//
+// History: 1/4/2003 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef TRAFFICSOUNDPLAYER_H
+#define TRAFFICSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radtime.hpp>
+
+#include <sound/movingpositional/vehicleposnsoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class Vehicle;
+class carSoundParameters;
+
+//=============================================================================
+//
+// Synopsis: TrafficSoundPlayer
+//
+//=============================================================================
+
+class TrafficSoundPlayer : public VehiclePositionalSoundPlayer,
+ public IRadTimerCallback
+{
+ public:
+ TrafficSoundPlayer( );
+ virtual ~TrafficSoundPlayer();
+
+ static void InitializeClass( unsigned int numVehicles );
+
+ void Activate( positionalSoundSettings* soundSettings,
+ const char* resourceName,
+ Vehicle* theCar );
+ void Deactivate();
+
+ void ServiceOncePerFrame();
+ static void ServiceTimerList();
+
+ void HonkHorn();
+ void AddOverlayClip( carSoundParameters* parameters, const char* posnSettingsName );
+ void ToggleOverlayClip( carSoundParameters* parameters, const char* posnSettingsName );
+
+ //
+ // IRadTimerCallback
+ //
+ void OnTimerDone( unsigned int elapsedTime, void* pUserData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ TrafficSoundPlayer( const TrafficSoundPlayer& trafficsoundplayer );
+ TrafficSoundPlayer& operator=( const TrafficSoundPlayer& trafficsoundplayer );
+
+ IRadTimer* m_hornTimer;
+ PositionalSoundPlayer m_hornPlayer;
+
+ carSoundParameters* m_vehicleParameters;
+ PositionalSoundPlayer m_overlayPlayer;
+
+ unsigned int m_honkCount;
+ float m_pitchMultiplier;
+
+ static IRadTimerList* s_timerList;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //TRAFFICSOUNDPLAYER_H
diff --git a/game/code/sound/movingpositional/vehicleposnsoundplayer.cpp b/game/code/sound/movingpositional/vehicleposnsoundplayer.cpp
new file mode 100644
index 0000000..8fbb446
--- /dev/null
+++ b/game/code/sound/movingpositional/vehicleposnsoundplayer.cpp
@@ -0,0 +1,258 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclepositionalsoundplayer.cpp
+//
+// Description: Implement VehiclePositionalSoundPlayer
+//
+// History: 3/7/2003 + Created -- Esan
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/vehicleposnsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundfx/positionalsoundsettings.h>
+
+#include <worldsim/redbrick/vehicle.h>
+
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::VehiclePositionalSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+VehiclePositionalSoundPlayer::VehiclePositionalSoundPlayer( ) :
+ m_vehicle( NULL ),
+ m_tiePitchToVelocity( false )
+{
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::~VehiclePositionalSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+VehiclePositionalSoundPlayer::~VehiclePositionalSoundPlayer()
+{
+}
+
+//=============================================================================
+// AIVehicleSoundPlayer::ActivateByName
+//=============================================================================
+// Description: Start playing given sound for given vehicle
+//
+// Parameters: soundName - name of positional sound setting object containing
+// data on sound to play
+// theCar - vehicle to associate sound with
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::ActivateByName( const char* soundName, Vehicle* theCar )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+
+ //
+ // Find the tunable sound settings that go with the name
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( ::radMakeKey32( soundName ) );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ Activate( parameters, parameters->GetClipName(), theCar );
+ }
+ else
+ {
+ rDebugString( "Couldn't play AI car sound, no matching settings found" );
+ }
+}
+
+//=============================================================================
+// AIVehicleSoundPlayer::Activate
+//=============================================================================
+// Description: Start playing given sound for given vehicle
+//
+// Parameters: soundSettings - positional sound setting object containing
+// data on sound to play
+// resourceName - name of sound resource to play positionally
+// theCar - vehicle to associate sound with
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::Activate( positionalSoundSettings* soundSettings,
+ const char* resourceName,
+ Vehicle* theCar )
+{
+ rmt::Vector posn;
+
+ m_vehicle = theCar;
+
+ m_player.SetPositionCarrier( *this );
+ m_player.SetParameters( soundSettings );
+
+ theCar->GetPosition( &posn );
+ m_player.SetPosition( posn.x, posn.y, posn.z );
+
+ m_player.PlaySound( resourceName, NULL );
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::Deactivate
+//=============================================================================
+// Description: Stop playing sound.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::Deactivate()
+{
+ m_vehicle = NULL;
+ m_tiePitchToVelocity = false;
+
+ m_player.Stop();
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::GetPosition
+//=============================================================================
+// Description: Return position of vehicle we're playing sound for
+//
+// Parameters: position - vector to be filled in with position
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::GetPosition( radSoundVector& position )
+{
+ rmt::Vector vehiclePosn;
+
+ m_vehicle->GetPosition( &vehiclePosn );
+ position.SetElements( vehiclePosn.x, vehiclePosn.y, vehiclePosn.z );
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::GetVelocity
+//=============================================================================
+// Description: Return velocity of vehicle we're playing sound for
+//
+// Parameters: velocity - vector to be filled in with velocity
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::GetVelocity( radSoundVector& velocity )
+{
+ rmt::Vector vehicleVel;
+
+ m_vehicle->GetVelocity( &vehicleVel );
+ velocity.SetElements( vehicleVel.x, vehicleVel.y, vehicleVel.z );
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::ServiceOncePerFrame()
+{
+ m_player.ServiceOncePerFrame();
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::UsesVehicle
+//=============================================================================
+// Description: Indicate whether we're currently playing sound for given
+// vehicle
+//
+// Parameters: car - vehicle to match against
+//
+// Return: true if we're playing sound for that car, false otherwise
+//
+//=============================================================================
+bool VehiclePositionalSoundPlayer::UsesVehicle( Vehicle* car )
+{
+ return( ( m_vehicle != NULL ) && ( car == m_vehicle ) );
+}
+
+//=============================================================================
+// VehiclePositionalSoundPlayer::BlowUp
+//=============================================================================
+// Description: Play an explosion sound. Yay!
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void VehiclePositionalSoundPlayer::BlowUp()
+{
+ IRadNameSpace* nameSpace;
+ positionalSoundSettings* settings;
+ rmt::Vector position;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ settings = reinterpret_cast<positionalSoundSettings*>( nameSpace->GetInstance( "collision_sounds" ) );
+ if( settings != NULL )
+ {
+ m_vehicle->GetPosition( &position );
+ m_explosionPlayer.SetPosition( position.x, position.y, position.z );
+ m_explosionPlayer.SetPositionCarrier( *this );
+ m_explosionPlayer.SetParameters( settings );
+ m_explosionPlayer.PlaySound( "generic_car_explode" );
+ }
+ else
+ {
+ rDebugString( "Couldn't find positional explosion settings for AI vehicle" );
+ }
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/movingpositional/vehicleposnsoundplayer.h b/game/code/sound/movingpositional/vehicleposnsoundplayer.h
new file mode 100644
index 0000000..dc47e2f
--- /dev/null
+++ b/game/code/sound/movingpositional/vehicleposnsoundplayer.h
@@ -0,0 +1,81 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: vehiclepositionalsoundplayer.h
+//
+// Description: Base class for moving vehicle sounds. This includes traffic
+// vehicles and positional idle on the user vehicle
+//
+// History: 3/7/2003 + Created -- Esan
+//
+//=============================================================================
+
+#ifndef VEHICLEPOSITIONALSOUNDPLAYER_H
+#define VEHICLEPOSITIONALSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/positionalsoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class Vehicle;
+
+//=============================================================================
+//
+// Synopsis: VehiclePositionalSoundPlayer
+//
+//=============================================================================
+
+class VehiclePositionalSoundPlayer : public PositionCarrier
+{
+ public:
+ VehiclePositionalSoundPlayer( );
+ virtual ~VehiclePositionalSoundPlayer();
+
+ bool IsActive() { return( m_vehicle != NULL ); }
+ void ActivateByName( const char* soundName, Vehicle* theCar );
+ virtual void Activate( positionalSoundSettings* soundSettings,
+ const char* resourceName,
+ Vehicle* theCar );
+ virtual void Deactivate();
+
+ bool UsesVehicle( Vehicle* car );
+
+ virtual void ServiceOncePerFrame();
+
+ void TiePitchToVelocity( bool flag ) { m_tiePitchToVelocity = flag; }
+
+ void BlowUp();
+
+ //
+ // PositionCarrier functions
+ //
+ void GetPosition( radSoundVector& position );
+ void GetVelocity( radSoundVector& velocity );
+
+ protected:
+ Vehicle* m_vehicle;
+
+ PositionalSoundPlayer m_player;
+
+ bool m_tiePitchToVelocity;
+
+
+ private:
+ //Prevent wasteful constructor creation.
+ VehiclePositionalSoundPlayer( const VehiclePositionalSoundPlayer& vehiclepositionalsoundplayer );
+ VehiclePositionalSoundPlayer& operator=( const VehiclePositionalSoundPlayer& vehiclepositionalsoundplayer );
+
+ PositionalSoundPlayer m_explosionPlayer;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //VEHICLEPOSITIONALSOUNDPLAYER_H
diff --git a/game/code/sound/movingpositional/waspsoundplayer.cpp b/game/code/sound/movingpositional/waspsoundplayer.cpp
new file mode 100644
index 0000000..97eb98a
--- /dev/null
+++ b/game/code/sound/movingpositional/waspsoundplayer.cpp
@@ -0,0 +1,260 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: waspsoundplayer.cpp
+//
+// Description: Implement WaspSoundPlayer
+//
+// History: 3/10/2003 + Created -- Esan
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/movingpositional/waspsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <events/eventmanager.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// WaspSoundPlayer::WaspSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+WaspSoundPlayer::WaspSoundPlayer() :
+ m_isFadingIn( false ),
+ m_attacking( false ),
+ m_blowingUp( false )
+{
+ EventManager* eventMgr = GetEventManager();
+
+ eventMgr->AddListener( this, EVENT_ACTOR_REMOVED );
+ eventMgr->AddListener( this, EVENT_WASP_CHARGING );
+ eventMgr->AddListener( this, EVENT_WASP_CHARGED );
+ eventMgr->AddListener( this, EVENT_WASP_ATTACKING );
+ eventMgr->AddListener( this, EVENT_WASP_BLOWED_UP );
+}
+
+//=============================================================================
+// WaspSoundPlayer::~WaspSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+WaspSoundPlayer::~WaspSoundPlayer()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// WaspSoundPlayer::Activate
+//=============================================================================
+// Description: Start playing wasp noises
+//
+// Parameters: theActor - wasp object
+// soundName - name of sound resource to start playing for wasp
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::Activate( Actor* theActor )
+{
+ //
+ // Play the fade-in sound
+ //
+ playWaspSound( "wasp_fade_in", theActor );
+ m_isFadingIn = true;
+}
+
+//=============================================================================
+// WaspSoundPlayer::HandleEvent
+//=============================================================================
+// Description: Look for actor destruction and disassociate when it happens
+//
+// Parameters: id - event ID
+// pEventData - event user data
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::HandleEvent( EventEnum id, void* pEventData )
+{
+ //
+ // Make sure we've got the event for the right wasp
+ //
+ if( static_cast<Actor*>(pEventData) != m_actor )
+ {
+ return;
+ }
+
+ switch( id )
+ {
+ case EVENT_ACTOR_REMOVED:
+ deactivate();
+ break;
+
+ case EVENT_WASP_CHARGING:
+ playWaspSound( "wasp_charging", m_actor );
+ break;
+
+ case EVENT_WASP_CHARGED:
+ playWaspSound( "wasp_charged_idle", m_actor );
+ break;
+
+ case EVENT_WASP_ATTACKING:
+ playWaspSound( "wasp_attack", m_actor );
+ m_attacking = true;
+ break;
+
+ case EVENT_WASP_BLOWED_UP:
+ playWaspSound( "wasp_destroyed", m_actor );
+ m_blowingUp = true;
+ break;
+
+ default:
+ rAssertMsg( false, "Unexpected event in WaspSoundPlayer::HandleEvent\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// WaspSoundPlayer::OnPlaybackComplete
+//=============================================================================
+// Description: Playback callback, so that we can make sound transitions
+// if necessary
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::OnPlaybackComplete()
+{
+ if( m_isFadingIn || m_attacking )
+ {
+ m_isFadingIn = false;
+ m_attacking = false;
+
+ playWaspSound( "wasp_idle", m_actor );
+ }
+ else if( m_blowingUp )
+ {
+ //
+ // Wasp destroyed, deactivate player
+ //
+ m_blowingUp = false;
+ deactivate();
+ }
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// WaspSoundPlayer::deactivate
+//=============================================================================
+// Description: Stop sound playback and free player for next wasp
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::deactivate()
+{
+ safeStop();
+
+ ActorPlayer::deactivate();
+}
+
+//=============================================================================
+// WaspSoundPlayer::safeStop
+//=============================================================================
+// Description: Stop sound without triggering playback callbacks
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::safeStop()
+{
+ //
+ // Kill the callbacks before stopping, so we don't get sounds
+ // lingering around after we think we're stopped
+ //
+ m_isFadingIn = false;
+ m_attacking = false;
+
+ m_player.Stop();
+}
+
+//=============================================================================
+// WaspSoundPlayer::playWaspSound
+//=============================================================================
+// Description: Play a sound for the wasp
+//
+// Parameters: soundName - name of sound resource
+// theActor - wasp actor object
+//
+// Return: void
+//
+//=============================================================================
+void WaspSoundPlayer::playWaspSound( const char* soundName, Actor* theActor )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+
+ //
+ // Kill the old sound, disabling any callback action first.
+ //
+ safeStop();
+
+ //
+ // Get the positionalSoundSettings object for the wasp sound
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( ::radMakeKey32( "wasp_settings" ) );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ playSound( parameters, soundName, theActor );
+ }
+ else
+ {
+ rDebugString( "Couldn't play wasp sound, no matching settings found" );
+ }
+}
diff --git a/game/code/sound/movingpositional/waspsoundplayer.h b/game/code/sound/movingpositional/waspsoundplayer.h
new file mode 100644
index 0000000..f368b14
--- /dev/null
+++ b/game/code/sound/movingpositional/waspsoundplayer.h
@@ -0,0 +1,71 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: waspsoundplayer.h
+//
+// Description: Plays sound for those flying bugs
+//
+// History: 3/10/2003 + Created -- Esan
+//
+//=============================================================================
+
+#ifndef WASPSOUNDPLAYER_H
+#define WASPSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/movingpositional/actorplayer.h>
+
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: WaspSoundPlayer
+//
+//=============================================================================
+
+class WaspSoundPlayer : public ActorPlayer,
+ public EventListener
+{
+ public:
+ WaspSoundPlayer();
+ virtual ~WaspSoundPlayer();
+
+ //
+ // ActorPlayer functions
+ //
+ void Activate( Actor* theActor );
+ void OnPlaybackComplete();
+
+ //
+ // EventListener functions
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ WaspSoundPlayer( const WaspSoundPlayer& waspsoundplayer );
+ WaspSoundPlayer& operator=( const WaspSoundPlayer& waspsoundplayer );
+
+ void playWaspSound( const char* soundName, Actor* theActor );
+
+ void deactivate();
+ void safeStop();
+
+ bool m_isFadingIn;
+ bool m_attacking;
+ bool m_blowingUp;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //WASPSOUNDPLAYER_H
diff --git a/game/code/sound/music/allmusic.cpp b/game/code/sound/music/allmusic.cpp
new file mode 100644
index 0000000..0b5fb3f
--- /dev/null
+++ b/game/code/sound/music/allmusic.cpp
@@ -0,0 +1 @@
+#include <sound/music/musicplayer.cpp>
diff --git a/game/code/sound/music/musicplayer.cpp b/game/code/sound/music/musicplayer.cpp
new file mode 100644
index 0000000..b03dfbb
--- /dev/null
+++ b/game/code/sound/music/musicplayer.cpp
@@ -0,0 +1,2284 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: musicplayer.cpp
+//
+// Description: Implement MusicPlayer class. Plays all music in
+// the game using RadMusic.
+//
+// History: 17/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/music/musicplayer.h>
+
+#include <sound/soundmanager.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/dasoundgroup.h>
+
+#include <main/commandlineoptions.h>
+#include <memory/srrmemory.h>
+#include <events/eventmanager.h>
+#include <gameflow/gameflow.h>
+#include <loading/loadingmanager.h>
+#include <loading/soundfilehandler.h>
+#include <mission/missionmanager.h>
+#include <worldsim/character/character.h>
+#include <worldsim/avatarmanager.h>
+#include <meta/eventlocator.h>
+#include <worldsim/character/charactermanager.h>
+#include <worldsim/character/character.h>
+
+#include <Render/Enums/RenderEnums.h>
+
+#include <interiors/interiormanager.h>
+
+#include <radload/radload.hpp>
+
+//========================================
+// System Includes
+//========================================
+#include <string.h>
+
+#include <radmusic/radmusic.hpp>
+#include <p3d/entity.hpp>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+static const char* AMBIENT_FILE_NAME = "sound\\ambience\\ambience.rms";
+static const char* LEVEL_FILE_NAME_PREFIX = "sound\\music\\L";
+static const char* LEVEL_FILE_NAME_SUFFIX = "_music.rms";
+static const char* MUSIC_SEARCH_PATH = "sound\\music\\";
+static const char* AMBIENCE_SEARCH_PATH = "sound\\ambience\\";
+
+struct InteriorIDEntry
+{
+ radInt64 id;
+ const char* name;
+ MusicEventList musicEvent;
+};
+
+static InteriorIDEntry interiorNameTable[] =
+{
+ { 0, "KwikEMart", MEVENT_INTERIOR_KWIK_E_MART },
+ { 0, "SpringfieldElementary", MEVENT_INTERIOR_SCHOOL },
+ { 0, "SimpsonsHouse", MEVENT_INTERIOR_HOUSE },
+ { 0, "Krustylu", MEVENT_INTERIOR_HOUSE },
+ { 0, "dmv", MEVENT_INTERIOR_DMV }
+};
+
+static int interiorTableLength = sizeof( interiorNameTable ) / sizeof( InteriorIDEntry );
+
+//
+// Tables for mapping music/ambience events to indices into radMusic scripts
+//
+
+struct MusicScriptTableEntry
+{
+ const char* name;
+ radKey32 nameKey;
+ int scriptIndex;
+};
+static const int NO_INDEX = -1;
+
+static MusicScriptTableEntry musicEventTable[] =
+{
+ { "movie", 0, 0 },
+ { "pause", 0, 0 },
+ { "unpause", 0, 0 },
+ { "FE", 0, 0 },
+ { "Loading_screen", 0, 0 },
+ { "Newspaper_Spin", 0, 0 },
+ { "SuperSprint", 0, 0 },
+ { "Win_SuperSprint", 0, 0 },
+ { "Lose_SuperSprint", 0, 0 },
+ { "Level_Intro", 0, 0 },
+ { "Sunday_Drive_start", 0, 0 },
+ { "Sunday_Drive_Get_out_of_Car", 0, 0 },
+ { "Store", 0, 0 },
+ { "Enter_StoneCutters_Tunnel", 0, 0 },
+ { "Exit_StoneCutters_Tunnel", 0, 0 },
+ { "OF_explore_mission", 0, 0 },
+ { "OF_found_card", 0, 0 },
+ { "OF_time_out", 0, 0 },
+ { "OF_Apu_Oasis", 0, 0 },
+ { "OF_House", 0, 0 },
+ { "OF_KiwkEMart", 0, 0 },
+ { "OF_School", 0, 0 },
+ { "OF_Moes", 0, 0 },
+ { "OF_DMV", 0, 0 },
+ { "OF_Android_Dungeon", 0, 0 },
+ { "OF_Observatory", 0, 0 },
+ { "Win_3Street_Races", 0, 0 },
+ { "Level_Completed", 0, 0 },
+ { "Destroy_Camera_Bonus", 0, 0 },
+ { "StoneCutters", 0, 0 },
+ { "Social_Club", 0, 0 },
+ { "DuffBeer", 0, 0 },
+ { "Hit_and_Run", 0, 0 },
+ { "Hit_and_Run_Caught", 0, 0 },
+ { "Wasp_Attack", 0, 0 },
+ { "Gated_Mission", 0, 0 },
+ { "ScaryMusic01", 0, 0 },
+ { "Credits", 0, 0 }
+};
+
+static unsigned int musicEventTableLength = sizeof( musicEventTable ) / sizeof( MusicScriptTableEntry );
+
+struct MissionNameScriptEntry
+{
+ radKey32 nameKey;
+ int scriptIndex;
+};
+static const unsigned int MISSION_TABLE_SIZE = 81;
+static MissionNameScriptEntry missionScriptTable[MISSION_TABLE_SIZE];
+static unsigned int missionScriptTableLength;
+
+static const unsigned int RACE_TABLE_SIZE = 12;
+static MissionNameScriptEntry raceScriptTable[RACE_TABLE_SIZE];
+static unsigned int raceScriptTableLength;
+
+struct MatrixStateScriptEntry
+{
+ radKey32 stateNameKey;
+ unsigned int stateIndex;
+ radKey32 stateValueNameKey;
+ unsigned int stateValueIndex;
+};
+static const unsigned int MATRIX_TABLE_SIZE = 6;
+static MatrixStateScriptEntry matrixStateTable[MATRIX_TABLE_SIZE];
+static unsigned int matrixStateTableLength;
+
+// Should change to whatever the global constant is
+static const int NUM_LEVELS = 7;
+static const int NUM_STARTING_MISSIONS = 8;
+
+static AmbientEventList startingAmbiences[NUM_LEVELS][NUM_STARTING_MISSIONS] =
+{
+ // L1
+ {
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PP_ROOM_2 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_COUNTRY_HIGHWAY - LocatorEvent::AMBIENT_SOUND_CITY ) )
+ },
+
+ // L2
+ {
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ },
+
+ // L3
+ {
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_LIGHT_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_LIGHT_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_LIGHT_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_FOREST_HIGHWAY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_LIGHT_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_QUAY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_QUAY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ },
+
+ // L4
+ {
+ AEVENT_INTERIOR_HOUSE,
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_COUNTRY_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ },
+
+ // L5
+ {
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_CITY - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ },
+
+ // L6
+ {
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER10 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER10 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SEASIDE_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_COUNTRY_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_SEASIDE_NIGHT - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER10 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER10 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ },
+
+ // L7
+ {
+ AEVENT_INTERIOR_HOUSE,
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER7 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_HALLOWEEN1 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE,
+ AEVENT_INTERIOR_HOUSE,
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER7 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ static_cast<AmbientEventList>( AEVENT_TRIGGER_START +
+ ( LocatorEvent::AMBIENT_SOUND_PLACEHOLDER7 - LocatorEvent::AMBIENT_SOUND_CITY ) ),
+ AEVENT_INTERIOR_HOUSE // unused
+ }
+};
+
+static LocatorEvent::Event startingExteriorAmbiences[NUM_LEVELS] =
+{
+ LocatorEvent::AMBIENT_SOUND_SUBURBS,
+ LocatorEvent::AMBIENT_SOUND_CITY,
+ LocatorEvent::AMBIENT_SOUND_LIGHT_CITY,
+ LocatorEvent::AMBIENT_SOUND_SUBURBS_NIGHT,
+ LocatorEvent::AMBIENT_SOUND_CITY,
+ LocatorEvent::AMBIENT_SOUND_PLACEHOLDER10,
+ LocatorEvent::AMBIENT_SOUND_HALLOWEEN1
+};
+
+static int s_PostHitAndRunTimer = -99;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// MusicPlayer::MusicPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+MusicPlayer::MusicPlayer( Sound::IDaSoundTuner& tuner ) :
+ m_lastServiceTime( ::radTimeGetMilliseconds( ) ),
+ m_isLoadingMusic( false ),
+ m_isInCar( false ),
+ m_radLoadRequest( NULL ),
+ m_musicPerformance( NULL ),
+ m_musicComposition( NULL ),
+ m_isLoadingAmbient( false ),
+ m_ambientPerformance( NULL ),
+ m_ambientComposition( NULL ),
+ m_currentAmbient( AEVENT_TRIGGER_START ),
+ m_ambiencePlaying( false ),
+ m_onApuRooftop( false ),
+ m_stoneCutterSong( false ),
+ m_LBCSong( false ),
+ m_delayedMusicStart( false ),
+ m_wasp( NULL )
+{
+ EventManager* eventMgr;
+ unsigned int event;
+
+ //
+ // Register as an event listener
+ //
+
+ eventMgr = GetEventManager();
+
+ eventMgr->AddListener( this, EVENT_GETINTOVEHICLE_END );
+ eventMgr->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
+ eventMgr->AddListener( this, EVENT_INTERIOR_SWITCH );
+ eventMgr->AddListener( this, EVENT_MISSION_DRAMA );
+ eventMgr->AddListener( this, EVENT_MISSION_FAILURE );
+ eventMgr->AddListener( this, EVENT_MISSION_SUCCESS );
+ eventMgr->AddListener( this, EVENT_CARD_COLLECTED );
+ eventMgr->AddListener( this, EVENT_FE_START_GAME_SELECTED );
+ eventMgr->AddListener( this, EVENT_HIT_AND_RUN_START );
+ eventMgr->AddListener( this, EVENT_HIT_AND_RUN_CAUGHT );
+ eventMgr->AddListener( this, EVENT_HIT_AND_RUN_EVADED );
+
+ //
+ // Temporarily remove wasp music
+ //
+ //eventMgr->AddListener( this, EVENT_WASP_CHARGING );
+ //eventMgr->AddListener( this, EVENT_WASP_BLOWED_UP );
+
+ eventMgr->AddListener( this, EVENT_ACTOR_REMOVED );
+ eventMgr->AddListener( this, EVENT_CHANGE_MUSIC );
+ eventMgr->AddListener( this, EVENT_CHANGE_MUSIC_STATE );
+ eventMgr->AddListener( this, EVENT_STAGE_TRANSITION_FAILED );
+ eventMgr->AddListener( this, EVENT_COMPLETED_ALLSTREETRACES );
+ eventMgr->AddListener( this, EVENT_MISSION_RESET );
+ eventMgr->AddListener( this, EVENT_CHARACTER_POS_RESET );
+ eventMgr->AddListener( this, EVENT_PLAY_CREDITS );
+ eventMgr->AddListener( this, EVENT_PLAY_FE_MUSIC );
+ eventMgr->AddListener( this, EVENT_PLAY_MUZAK );
+ //eventMgr->AddListener( this, EVENT_PLAY_IDLE_MUSIC );
+ eventMgr->AddListener( this, EVENT_SUPERSPRINT_WIN );
+ eventMgr->AddListener( this, EVENT_SUPERSPRINT_LOSE );
+ eventMgr->AddListener( this, EVENT_STOP_THE_MUSIC );
+
+ //
+ // Register all of the ambience events
+ //
+ for( event = EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY;
+ event <= EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER16;
+ ++event )
+ {
+ if( ( event < EVENT_LOCATOR + LocatorEvent::PARKED_BIRDS )
+ || ( ( event > EVENT_LOCATOR + LocatorEvent::FAR_PLANE )
+ && ( event < EVENT_LOCATOR + LocatorEvent::GOO_DAMAGE ) )
+ || ( event > EVENT_LOCATOR + LocatorEvent::TRAP ) )
+ {
+ eventMgr->AddListener( this, static_cast<EventEnum>(event) );
+ }
+ }
+
+ //
+ // Fill in the script tables with name keys
+ //
+ initializeTableNameKeys();
+}
+
+//==============================================================================
+// MusicPlayer::~MusicPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+MusicPlayer::~MusicPlayer()
+{
+ //
+ // Deregister from EventManager
+ //
+ GetEventManager()->RemoveAll( this );
+
+ if( m_musicPerformance != NULL )
+ {
+ radmusic::performance_stop( m_musicPerformance );
+ radmusic::performance_delete( & m_musicPerformance );
+ }
+
+ if ( m_musicComposition != NULL )
+ {
+ radmusic::composition_delete( & m_musicComposition );
+ }
+
+ if( m_ambientPerformance != NULL )
+ {
+ radmusic::performance_stop( m_ambientPerformance );
+ radmusic::performance_delete( & m_ambientPerformance );
+ }
+
+ if ( m_ambientComposition != NULL )
+ {
+ radmusic::composition_delete( & m_ambientComposition );
+ }
+}
+
+void MusicPlayer::TriggerMusicEvent( MusicEventList event )
+{
+ int scriptIndex;
+ int tableIndex;
+
+ if( !(CommandLineOptions::Get( CLO_NO_MUSIC )) )
+ {
+ //
+ // Much necessary hack: screen out music we're tired of hearing
+ //
+ if( CommandLineOptions::Get( CLO_NO_AVRIL ) )
+ {
+ if( ( event == MEVENT_FE )
+ || ( event == MEVENT_SUNDAY_DRIVE_START )
+ || ( event == MEVENT_STREETRACE_START ) )
+ {
+ // Silence
+ event = MEVENT_MOVIE;
+ }
+ }
+
+ //
+ // Get the script index for this event from the appropriate table
+ //
+ if( event < MEVENT_END_STANDARD_EVENTS )
+ {
+ scriptIndex = musicEventTable[event].scriptIndex;
+ }
+ else if( event < MEVENT_END_MISSION_EVENTS )
+ {
+ tableIndex = ( ( event - MEVENT_MISSION_START ) + calculateMissionIndex() );
+ scriptIndex = missionScriptTable[tableIndex].scriptIndex;
+ }
+ else
+ {
+ tableIndex = ( ( event - MEVENT_STREETRACE_START ) + calculateMissionIndex() );
+ scriptIndex = raceScriptTable[tableIndex].scriptIndex;
+ }
+
+ //
+ // TODO: Uncomment after all the missions are set up and ready to go
+ //
+ //rAssertMsg( ( scriptIndex != NO_INDEX ), "Music event not found in script? (E-mail Esan, then continue)" );
+
+ if( ( scriptIndex != NO_INDEX )
+ && ( m_musicPerformance != NULL ) )
+ {
+ radmusic::performance_trigger_event(
+ m_musicPerformance,
+ scriptIndex );
+ }
+ }
+}
+
+void MusicPlayer::TriggerAmbientEvent( unsigned int event )
+{
+ unsigned int scriptLength;
+
+ if( m_ambientPerformance == NULL )
+ {
+ return;
+ }
+
+ if( !(CommandLineOptions::Get( CLO_NO_MUSIC )) )
+ {
+ scriptLength = radmusic::performance_num_events( m_ambientPerformance );
+
+ if( event < scriptLength )
+ {
+ radmusic::performance_trigger_event( m_ambientPerformance, event );
+ }
+ else
+ {
+ //
+ // TODO: reinstate this after MS 17, get ambience for all interiors
+ //
+
+ //rAssertMsg( false, "Invalid ambient event received, ignored\n" );
+ }
+ }
+}
+
+//=============================================================================
+// MusicPlayer::HandleEvent
+//=============================================================================
+// Description: Listen for when the player gets in and out of cars
+//
+// Parameters: id - event ID
+// pEventData - user data, unused
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::HandleEvent( EventEnum id, void* pEventData )
+{
+ bool inCar;
+ int interiorIndex;
+ MusicStateData* musicState;
+ EventLocator* pLocator = (EventLocator*)pEventData;
+ Character* pCharacter = NULL;
+ int levelIndex;
+ int missionIndex;
+
+ static bool s_HitAndRun = false;
+ static int previousTime = 0, recentTime = 0;
+ static EventEnum previousEvent = EVENT_LOCATOR;
+ static EventEnum recentEvent = EVENT_LOCATOR;
+ static EventLocator* previousLocator = NULL;
+ static EventLocator* recentLocator = NULL;
+ static bool bSpecialCaseMusic = false;
+ static MusicEventList lastSpecialMusic = MEVENT_MOVIE; // default
+
+ // bmc: don't pay attention to music events when in hit and run mode
+ /*
+ if ( s_HitAndRun )
+ {
+ if ( id != EVENT_HIT_AND_RUN_CAUGHT && id != EVENT_HIT_AND_RUN_EVADED &&
+ id != EVENT_MISSION_FAILURE && id != EVENT_MISSION_SUCCESS && id != EVENT_MISSION_RESET )
+ return;
+ else
+ s_HitAndRun = false;
+ }
+ */
+
+ switch( id )
+ {
+ case EVENT_FE_START_GAME_SELECTED:
+ TriggerMusicEvent( MEVENT_NEWSPAPER_SPIN );
+ break;
+
+ case EVENT_GETINTOVEHICLE_END:
+ m_isInCar = true;
+
+ if ( !s_HitAndRun )
+ {
+ if ( bSpecialCaseMusic )
+ {
+ TriggerMusicEvent( lastSpecialMusic );
+ }
+ else
+ {
+ startMusic();
+ }
+ }
+ break;
+
+ case EVENT_GETOUTOFVEHICLE_END:
+ // bmc: have to validate that it's not an ai player getting out of the car...
+ pCharacter = static_cast<Character*>( pEventData );
+ if ( !pCharacter->IsNPC() )
+ {
+ m_isInCar = false;
+
+ // if playing special music then we don't want to mess with it...
+ if ( !bSpecialCaseMusic )
+ {
+ if ( !s_HitAndRun && !musicLockedOnForStage() )
+ {
+ if( currentMissionIsSundayDrive() )
+ {
+ TriggerMusicEvent( MEVENT_SUNDAY_DRIVE_GET_OUT_OF_CAR );
+ }
+ else if( currentMissionIsRace() )
+ {
+ TriggerMusicEvent( MEVENT_STREETRACE_GET_OUT_OF_CAR );
+ }
+ else
+ {
+ TriggerMusicEvent( MEVENT_GET_OUT_OF_CAR );
+ }
+ turnAmbienceOn( m_currentAmbient );
+ }
+ }
+ }
+ break;
+
+ case EVENT_MISSION_RESET:
+ {
+ s_HitAndRun = false;
+ bSpecialCaseMusic = false;
+ lastSpecialMusic = MEVENT_MOVIE;
+ // bmc: play music if just declined restarting of a mission
+ if ( GetGameplayManager()->IsSundayDrive() &&
+ GetInteriorManager()->GetInterior() == static_cast< tUID >( 0 ) && (int)pEventData == 0 )
+ {
+ startMusic();
+ }
+
+ inCar = GetAvatarManager()->GetAvatarForPlayer( 0 )->IsInCar();
+ if( inCar != m_isInCar )
+ {
+ m_isInCar = inCar;
+ startMusic();
+ }
+ else if ( inCar )
+ {
+ // bmc: another hack -- if restarting a mission and we're in a car to start it then play the damn music
+ startMusic();
+ }
+
+#if defined( RAD_XBOX ) || defined( RAD_WIN32 )
+ // XBox seems to like this syntax better.
+ bool jumpStage = reinterpret_cast<bool>( pEventData );
+#else
+ bool jumpStage = (bool)( pEventData );
+#endif
+
+ if( jumpStage )
+ {
+ //
+ // Make sure we're playing the right ambience
+ //
+ levelIndex = calculateLevelIndex();
+ missionIndex = GetGameplayManager()->GetCurrentMissionIndex();
+
+ if( startingAmbiences[levelIndex][missionIndex] == AEVENT_INTERIOR_HOUSE )
+ {
+ m_currentAmbient = AEVENT_TRIGGER_START + ( startingExteriorAmbiences[calculateLevelIndex()] - LocatorEvent::AMBIENT_SOUND_CITY );
+ }
+ else
+ {
+ m_currentAmbient = startingAmbiences[levelIndex][missionIndex];
+ }
+ if( !inCar )
+ {
+ turnAmbienceOn( startingAmbiences[levelIndex][missionIndex] );
+ }
+ }
+ }
+ break;
+
+ case EVENT_CHARACTER_POS_RESET:
+ if ( pEventData )
+ pCharacter = static_cast<Character*>( pEventData );
+
+ if ( pCharacter && pCharacter->IsNPC() )
+ break;
+
+ inCar = GetAvatarManager()->GetAvatarForPlayer( 0 )->IsInCar();
+ if( inCar != m_isInCar )
+ {
+ m_isInCar = inCar;
+ startMusic();
+ }
+
+ break;
+
+ case EVENT_INTERIOR_SWITCH:
+ //
+ // We sometimes get these events on loading screens. Filter them out.
+ //
+ if( GetGameFlow()->GetCurrentContext() == CONTEXT_LOADING_GAMEPLAY )
+ {
+ break;
+ }
+
+ if(pEventData)
+ {
+ // switching to interior
+ interiorIndex = calculateInteriorIndex( GetInteriorManager()->GetInterior() );
+ turnAmbienceOn( AEVENT_INTERIOR_KWIK_E_MART + interiorIndex );
+ if( !musicLockedOnForStage() )
+ {
+ TriggerMusicEvent( interiorNameTable[interiorIndex].musicEvent );
+ }
+ }
+ else if( !m_isInCar )
+ {
+ // switching to exterior
+ turnAmbienceOn( m_currentAmbient );
+ if( !musicLockedOnForStage() )
+ {
+ TriggerMusicEvent( MEVENT_OF_EXPLORE_MISSION );
+ }
+ }
+ break;
+
+ case EVENT_MISSION_DRAMA:
+ TriggerMusicEvent( MEVENT_MISSION_DRAMA );
+ break;
+
+ case EVENT_CHANGE_MUSIC:
+ triggerMusicMissionEventByName( static_cast<radKey32*>( pEventData ) );
+ break;
+
+ case EVENT_CHANGE_MUSIC_STATE:
+ musicState = static_cast<MusicStateData*>( pEventData );
+ triggerMusicStateChange( musicState->stateKey, musicState->stateEventKey );
+ break;
+
+ case EVENT_MISSION_SUCCESS:
+ s_HitAndRun = false;
+ if( currentMissionIsRace() )
+ {
+ TriggerMusicEvent( MEVENT_STREETRACE_WIN );
+ }
+ else
+ {
+ TriggerMusicEvent( MEVENT_WIN_MISSION );
+ }
+ playPostMissionSounds();
+ break;
+
+ case EVENT_MISSION_FAILURE:
+ s_HitAndRun = false;
+ if( currentMissionIsRace() )
+ {
+ TriggerMusicEvent( MEVENT_STREETRACE_LOSE );
+ }
+ else
+ {
+ TriggerMusicEvent( MEVENT_LOSE_MISSION );
+ }
+
+ //playPostMissionSounds();
+ break;
+
+ case EVENT_STAGE_TRANSITION_FAILED:
+ TriggerMusicEvent( MEVENT_GATED_MISSION );
+ break;
+
+ case EVENT_CARD_COLLECTED:
+ //
+ // If we're in the car, don't interrupt the music, we'll play
+ // a sound effect instead
+ //
+ if( !m_isInCar )
+ {
+ TriggerMusicEvent( MEVENT_OF_FOUND_CARD );
+ }
+ break;
+
+ case EVENT_HIT_AND_RUN_START:
+ TriggerMusicEvent( MEVENT_HIT_AND_RUN_START );
+ s_HitAndRun = true;
+ // bmc: queueing this after the hit and run music seems to do the trick when hit and run ends...but only on evade...
+ //startMusic();
+ break;
+
+ case EVENT_HIT_AND_RUN_CAUGHT:
+ TriggerMusicEvent( MEVENT_HIT_AND_RUN_CAUGHT );
+ s_HitAndRun = false;
+ // begin counter -- (x) ticks until startMusic call...
+ s_PostHitAndRunTimer = 110;
+ break;
+
+ case EVENT_HIT_AND_RUN_EVADED:
+ // bmc: play nothing...
+ //TriggerMusicEvent( MEVENT_SUNDAY_DRIVE_START );
+ s_HitAndRun = false;
+ // begin counter -- (x) ticks until startMusic call...
+ s_PostHitAndRunTimer = 10;
+ break;
+
+ case EVENT_WASP_CHARGING:
+ if( !m_isInCar )
+ {
+ m_wasp = static_cast<Actor*>( pEventData );
+ TriggerMusicEvent( MEVENT_WASP_ATTACK );
+ }
+ break;
+
+ case EVENT_WASP_BLOWED_UP:
+ case EVENT_ACTOR_REMOVED:
+ if( static_cast<Actor*>( pEventData ) == m_wasp )
+ {
+ TriggerMusicEvent( MEVENT_OF_EXPLORE_MISSION );
+
+ m_wasp = NULL;
+ }
+ break;
+
+ case EVENT_COMPLETED_ALLSTREETRACES:
+ TriggerMusicEvent( MEVENT_WIN_3_RACES );
+ break;
+
+ case EVENT_DESTROYED_ALLCAMERAS:
+ TriggerMusicEvent( MEVENT_DESTROY_CAMERA_BONUS );
+ break;
+
+ case EVENT_SUPERSPRINT_WIN:
+ TriggerMusicEvent( MEVENT_SUPERSPRINT_WIN );
+ break;
+
+ case EVENT_SUPERSPRINT_LOSE:
+ TriggerMusicEvent( MEVENT_SUPERSPRINT_LOSE );
+ break;
+
+ case EVENT_PLAY_CREDITS:
+ TriggerMusicEvent( MEVENT_CREDITS );
+ break;
+
+ case EVENT_PLAY_FE_MUSIC:
+ TriggerMusicEvent( MEVENT_FE );
+ break;
+
+ case EVENT_PLAY_MUZAK:
+ TriggerMusicEvent( MEVENT_STORE );
+ break;
+
+ case EVENT_PLAY_IDLE_MUSIC:
+ // bmc: do nothing here -- it fucks things over anyway
+ // TriggerMusicEvent( MEVENT_OF_TIME_OUT );
+ break;
+
+ case EVENT_STOP_THE_MUSIC:
+ TriggerMusicEvent( MEVENT_MOVIE );
+ break;
+
+ default:
+ //
+ // This should be triggered with ambience events. Easier to handle here
+ // than writing dozens of cases above
+ //
+ rAssert( id >= EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY );
+ rAssert( id <= EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER16 );
+ rAssert( ! ( ( id >= EVENT_LOCATOR + LocatorEvent::PARKED_BIRDS )
+ && ( id <= EVENT_LOCATOR + LocatorEvent::FAR_PLANE ) ) );
+ rAssert( ! ( ( id >= EVENT_LOCATOR + LocatorEvent::GOO_DAMAGE )
+ && ( id <= EVENT_LOCATOR + LocatorEvent::TRAP ) ) );
+
+ // don't play specific music if in hit and run
+ if ( s_HitAndRun || !pLocator->GetPlayerEntered() )
+ break;
+
+
+#ifdef RAD_DEBUG
+ char temp[256];
+
+ radmusic::performance_event_name( m_ambientPerformance,
+ AEVENT_TRIGGER_START + id - (EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY),
+ temp,
+ 256 );
+
+ rDebugPrintf( "Hit ambient trigger for %s\n", temp );
+#endif
+
+ if( m_ambiencePlaying )
+ {
+ turnAmbienceOn( AEVENT_TRIGGER_START + id - (EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY) );
+ }
+ else
+ {
+ m_currentAmbient = AEVENT_TRIGGER_START + id - (EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY);
+ }
+
+ //
+ // Icky special case
+ //
+ unsigned int now = ::radTimeGetMilliseconds();
+
+ // bmc: thrashing of events when driving over transition volumes is quite hazardous...
+ // implementing a system with a time threshold on it, so for e.g. when thrashing quickly
+ // between two volumes ABBAABABABA etc. will only handle B. ...however still troublesome
+ // if the player continuously drives back and forth over the volumes...may become confused
+ // as to which one to actually choose and end up with the wrong one :(
+
+ if ( id == recentEvent )
+ {
+ // ignore
+ id = id;
+ }
+ else if ( id == previousEvent && ( ( now - previousTime ) < ( 500 ) ) )
+ {
+ rDebugPrintf( "Sound ignoring likely thrashing event id = %d with time delay %d\n", id, now-previousTime );
+ id = id;
+ }
+ else
+ {
+ if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER9 ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_STONECUTTER_SONG;
+ TriggerMusicEvent( MEVENT_STONECUTTER_SONG );
+ bSpecialCaseMusic = true;
+ }
+ else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER8 ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_LBC_SONG;
+ TriggerMusicEvent( MEVENT_LBC_SONG );
+ bSpecialCaseMusic = true;
+ }
+ //else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_STONE_CUTTER_TUNNEL ) )
+ // && ( GetGameplayManager()->IsSundayDrive() ) )
+ //{
+ // TriggerMusicEvent( MEVENT_STONECUTTER_SONG );
+ // bSpecialCaseMusic = true;
+ //}
+ else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_STONE_CUTTER_HALL ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_ENTER_STONECUTTER_TUNNEL;
+ TriggerMusicEvent( MEVENT_ENTER_STONECUTTER_TUNNEL );
+ bSpecialCaseMusic = true;
+ }
+ else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_KWIK_E_MART_ROOFTOP ) ) ||
+ ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER3 ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_APU_OASIS;
+ TriggerMusicEvent( MEVENT_APU_OASIS );
+ bSpecialCaseMusic = true;
+ }
+ else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_HALLOWEEN2 ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_SCARYMUSIC;
+ TriggerMusicEvent( MEVENT_SCARYMUSIC );
+ bSpecialCaseMusic = true;
+ }
+ else if( ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_DUFF_EXTERIOR ) ) ||
+ ( id == ( EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_BREWERY_NIGHT ) )
+ && ( GetGameplayManager()->IsSundayDrive() ) )
+ {
+ lastSpecialMusic = MEVENT_DUFF_SONG;
+ TriggerMusicEvent( MEVENT_DUFF_SONG );
+ bSpecialCaseMusic = true;
+ }
+ else if( bSpecialCaseMusic )
+ {
+ startMusic(); // bmc: test
+ bSpecialCaseMusic = false;
+ lastSpecialMusic = MEVENT_MOVIE; // default
+ }
+
+ previousEvent = recentEvent;
+ previousTime = recentTime;
+ previousLocator = recentLocator;
+
+ recentEvent = id;
+ recentTime = now;
+ recentLocator = pLocator;
+ }
+ break;
+
+ }
+}
+
+//=============================================================================
+// MusicPlayer::Service
+//=============================================================================
+// Description: Extract the composition from the radload request, create the
+// performance and hook up the composition.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+
+void MusicPlayer::SetUpPerformance(
+ radmusic::performance ** ppPerformance,
+ radmusic::composition ** ppComposition,
+ const char * searchPath )
+{
+ rAssert( NULL != ppPerformance );
+ rAssert( NULL != ppComposition );
+ rAssert( NULL == *ppPerformance );
+ rAssert( NULL == *ppComposition );
+
+ radmusic::radload_composition_adapter * compAdapter =
+ radLoadFind< radmusic::radload_composition_adapter >(
+ m_radLoadRequest->GetInventory( ), "my_composition" );
+
+ rAssert( NULL != compAdapter );
+
+ *ppComposition = compAdapter->p_composition;
+
+ rAssert( NULL != *ppComposition );
+
+ compAdapter->p_composition = NULL;
+
+ m_radLoadRequest->Release( );
+ m_radLoadRequest = NULL;
+
+ if ( CommandLineOptions::Get( CLO_FIREWIRE ) )
+ {
+ *ppPerformance = radmusic::performance_new( *ppComposition, searchPath, radMemorySpace_Local );
+ }
+ else
+ {
+ *ppPerformance = radmusic::performance_new( *ppComposition, searchPath );
+ }
+
+ rAssert( *ppPerformance != NULL );
+}
+
+//=============================================================================
+// MusicPlayer::Service
+//=============================================================================
+// Description: Service RadMusic, and check the composition loader if we're
+// still in a loading state
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::Service()
+{
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ unsigned int now = ::radTimeGetMilliseconds( );
+ unsigned int dif = now - m_lastServiceTime;
+
+ if ( m_musicPerformance != NULL )
+ {
+ radmusic::performance_update( m_musicPerformance, dif );
+ }
+
+ if ( m_ambientPerformance != NULL )
+ {
+ radmusic::performance_update( m_ambientPerformance, dif );
+ }
+
+ m_lastServiceTime = now;
+
+ //
+ // According to Tim, this can be changed to a synchronous
+ // load on a thread using:
+ //
+ // radmusic::composition_new_from_file( const char * p_file_name );
+ //
+
+ if( m_isLoadingMusic && ( m_radLoadRequest->IsComplete( ) ) )
+ {
+ SetUpPerformance( & m_musicPerformance, & m_musicComposition, MUSIC_SEARCH_PATH );
+
+ m_isLoadingMusic = false;
+
+ //
+ // Construct the event lookup tables
+ //
+ buildEventTables();
+
+ m_loadCompleteCallback->LoadCompleted();
+ }
+ else if( m_isLoadingAmbient && m_radLoadRequest->IsComplete( ) )
+ {
+ SetUpPerformance( & m_ambientPerformance, & m_ambientComposition, AMBIENCE_SEARCH_PATH );
+
+ m_isLoadingAmbient = false;
+
+ rAssert( radmusic::performance_num_events( m_ambientPerformance ) == AEVENT_NUM_EVENTS );
+
+
+ m_loadCompleteCallback->LoadCompleted();
+ }
+
+ HeapMgr()->PopHeap( GMA_AUDIO_PERSISTENT );
+
+ // bmc: hit-and-run post music hack
+ if ( s_PostHitAndRunTimer > 0 )
+ {
+ if ( --s_PostHitAndRunTimer == 0 )
+ {
+ s_PostHitAndRunTimer = -99;
+ startMusic();
+ }
+ }
+
+ // My own music hack -- DE
+ if( m_delayedMusicStart )
+ {
+ if( m_musicPerformance == NULL )
+ {
+ m_delayedMusicStart = false;
+ }
+ else
+ {
+ //
+ // Check to see if the mission success/fail stinger is done yet
+ //
+ if( radmusic::performance_is_state_steady_idle( m_musicPerformance ) )
+ {
+ char regionName[ 64 ];
+ radmusic::debug_performance_current_region_name( m_musicPerformance, regionName, 64 );
+
+ if( strcmp( regionName, "stopped" ) == 0 )
+ {
+ m_delayedMusicStart = false;
+ startMusic();
+ }
+ }
+ }
+ }
+}
+
+//=============================================================================
+// MusicPlayer::QueueRadmusicScriptLoad
+//=============================================================================
+// Description: Queue the RadMusic composition script files in the loading
+// manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::QueueRadmusicScriptLoad()
+{
+ GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, AMBIENT_FILE_NAME, GMA_LEVEL_AUDIO );
+
+ //
+ // For the front end, any music script will do right now
+ //
+ QueueMusicLevelLoad( RenderEnums::L1 );
+}
+
+//=============================================================================
+// MusicPlayer::QueueMusicLevelLoad
+//=============================================================================
+// Description: Queue the music script for the given level in the loading
+// manager
+//
+// Parameters: level - enumeration indicating which level we're loading
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::QueueMusicLevelLoad( RenderEnums::LevelEnum level )
+{
+ char musicScriptName[100];
+ int levelNum = level - RenderEnums::L1 + 1;
+
+ //TODO: Esan are we going to play special music here?
+ if ( levelNum > RenderEnums::numLevels )
+ {
+ levelNum -= RenderEnums::numLevels;
+ }
+
+ sprintf( musicScriptName, "%s%d%s", LEVEL_FILE_NAME_PREFIX, levelNum, LEVEL_FILE_NAME_SUFFIX );
+ GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, musicScriptName, GMA_LEVEL_AUDIO );
+}
+
+//=============================================================================
+// MusicPlayer::LoadRadmusicScript
+//=============================================================================
+// Description: Load the RadMusic script
+//
+// Parameters: fileHandler - completion callback object
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::LoadRadmusicScript( const char* filename, SoundFileHandler* fileHandler )
+{
+ rAssert( NULL == m_radLoadRequest );
+
+ if( strcmp( filename, AMBIENT_FILE_NAME ) == 0 )
+ {
+ m_isLoadingAmbient = true;
+ }
+ else
+ {
+ UnloadRadmusicScript();
+ m_isLoadingMusic = true;
+ }
+
+ m_loadCompleteCallback = fileHandler;
+
+ // We have to keep the string around--problem with radload.
+
+ strncpy( n_currentLoadName, filename, 64 );
+
+ radLoadOptions options;
+ options.filename = n_currentLoadName;
+ options.allocator = GMA_MUSIC;
+
+ HeapMgr()->PushHeap(GMA_MUSIC);
+ radLoadInstance()->Load( & options, & m_radLoadRequest );
+ HeapMgr()->PopHeap(GMA_MUSIC);
+}
+
+//=============================================================================
+// MusicPlayer::UnloadRadmusicScript
+//=============================================================================
+// Description: Dump the music script, if it's loaded
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::UnloadRadmusicScript()
+{
+ if( NULL != m_musicPerformance )
+ {
+ radmusic::performance_stop( m_musicPerformance );
+ radmusic::performance_delete( & m_musicPerformance );
+
+ m_musicPerformance = NULL;
+ }
+
+ if ( NULL != m_musicComposition )
+ {
+ radmusic::composition_delete( & m_musicComposition );
+
+ m_musicComposition = NULL;
+ }
+}
+
+//=============================================================================
+// MusicPlayer::OnFrontEndStart
+//=============================================================================
+// Description: Notify RadMusic composition that we've started the front end
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnFrontEndStart()
+{
+ TriggerMusicEvent( MEVENT_FE );
+}
+
+//=============================================================================
+// MusicPlayer::OnFrontEndFinish
+//=============================================================================
+// Description: Notify RadMusic composition that we've finished the front end
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnFrontEndFinish()
+{
+ if( CommandLineOptions::Get( CLO_NO_MUSIC ) )
+ {
+ return;
+ }
+}
+
+//=============================================================================
+// MusicPlayer::OnGameplayStart
+//=============================================================================
+// Description: Notify RadMusic composition that we've started gameplay
+//
+// Parameters: playerInCar - should be true if player 0 is in the car, meaning
+// that we play music instead of ambient sound
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnGameplayStart( bool playerInCar )
+{
+ int levelIndex;
+ int missionIndex;
+
+ m_isInCar = playerInCar;
+
+ if( !(GetGameplayManager()->IsSuperSprint()) )
+ {
+ TriggerMusicEvent( MEVENT_LEVEL_INTRO );
+ }
+
+ //
+ // We want music playing for in-car characters. SuperSprint is a special
+ // case, since the characters can't be placed in cars until they select
+ // their cars, but we want music at gameplay start anyway
+ //
+ if( playerInCar || GetGameplayManager()->IsSuperSprint() )
+ {
+ startMusic();
+ }
+ else
+ {
+ levelIndex = calculateLevelIndex();
+ missionIndex = GetGameplayManager()->GetCurrentMissionIndex();
+
+ if( startingAmbiences[levelIndex][missionIndex] == AEVENT_INTERIOR_HOUSE )
+ {
+ m_currentAmbient = AEVENT_TRIGGER_START + ( startingExteriorAmbiences[calculateLevelIndex()] - LocatorEvent::AMBIENT_SOUND_CITY );
+ }
+ else
+ {
+ m_currentAmbient = startingAmbiences[levelIndex][missionIndex];
+ }
+ turnAmbienceOn( startingAmbiences[levelIndex][missionIndex] );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::OnGameplayFinish
+//=============================================================================
+// Description: Notify RadMusic composition that we've finished gameplay
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnGameplayFinish()
+{
+ TriggerMusicEvent( MEVENT_LOADING_SCREEN );
+
+ turnAmbienceOff( AEVENT_FRONTEND );
+
+ m_delayedMusicStart = false;
+}
+
+//=============================================================================
+// MusicPlayer::OnPauseStart
+//=============================================================================
+// Description: Entering pause menu, pause the music
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnPauseStart()
+{
+ TriggerMusicEvent( MEVENT_PAUSE );
+ turnAmbienceOff( AEVENT_PAUSE );
+}
+
+//=============================================================================
+// MusicPlayer::OnPauseEnd
+//=============================================================================
+// Description: Leaving pause menu, restart the music
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnPauseEnd()
+{
+ TriggerMusicEvent( MEVENT_UNPAUSE );
+ turnAmbienceOn( AEVENT_UNPAUSE );
+}
+
+//=============================================================================
+// MusicPlayer::OnStoreStart
+//=============================================================================
+// Description: Triggered when we enter a reward screen, like the clothes
+// shop
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnStoreStart()
+{
+ TriggerMusicEvent( MEVENT_STORE );
+}
+
+//=============================================================================
+// MusicPlayer::OnStoreEnd
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::OnStoreEnd()
+{
+ //
+ // We actually reuse this for supersprint
+ //
+ if( !(GetGameplayManager()->IsSuperSprint()) )
+ {
+ if( GetInteriorManager()->GetInterior() == static_cast< tUID >( 0 ) )
+ {
+ TriggerMusicEvent( MEVENT_OF_EXPLORE_MISSION );
+ }
+ else
+ {
+ TriggerMusicEvent( interiorNameTable[calculateInteriorIndex( GetInteriorManager()->GetInterior() )].musicEvent );
+ }
+ }
+}
+
+//=============================================================================
+// MusicPlayer::StopForMovie
+//=============================================================================
+// Description: Stop the music for a movie
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::StopForMovie()
+{
+ TriggerMusicEvent( MEVENT_PAUSE );
+ turnAmbienceOff( AEVENT_PAUSE );
+}
+
+//=============================================================================
+// MusicPlayer::ResumeAfterMovie
+//=============================================================================
+// Description: Start the FE music again after an FMV
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::ResumeAfterMovie()
+{
+ TriggerMusicEvent( MEVENT_UNPAUSE );
+ turnAmbienceOn( AEVENT_UNPAUSE );
+}
+
+bool MusicPlayer::IsStoppedForMovie( void )
+{
+ char regionName[ 64 ];
+ if ( !m_musicPerformance )
+ {
+ return true;
+ }
+ radmusic::debug_performance_current_region_name( m_musicPerformance, regionName, 64 );
+
+ bool steadyIdle = radmusic::performance_is_state_steady_idle( m_musicPerformance );
+
+ bool paused = ( strcmp( regionName, "stopped" ) == 0 || strcmp( regionName, "pause_region" ) == 0 );
+
+ return paused && steadyIdle;
+}
+
+//=============================================================================
+// MusicPlayer::RestartSupersprintMusic
+//=============================================================================
+// Description: Give the supersprint music a kick
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::RestartSupersprintMusic()
+{
+ TriggerMusicEvent( MEVENT_SUPERSPRINT );
+}
+
+//=============================================================================
+// MusicPlayer::GetVolume
+//=============================================================================
+// Description: Get the volume. Duh.
+//
+// Parameters: None
+//
+// Return: Float value for volume
+//
+//=============================================================================
+float MusicPlayer::GetVolume()
+{
+ rAssert( NULL != m_musicPerformance );
+ if ( NULL == m_musicPerformance )
+ {
+ return 0.0f;
+ }
+ else
+ {
+ return( radmusic::performance_volume( m_musicPerformance ) );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::SetVolume
+//=============================================================================
+// Description: Set the volume. Also duh.
+//
+// Parameters: volume - new volume setting
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::SetVolume( float volume )
+{
+ if ( NULL != m_musicPerformance )
+ {
+ radmusic::performance_volume( m_musicPerformance, volume );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::GetAmbienceVolume
+//=============================================================================
+// Description: Get the ambience volume.
+//
+// Parameters: None
+//
+// Return: Float value for volume
+//
+//=============================================================================
+float MusicPlayer::GetAmbienceVolume()
+{
+ rAssert( NULL != m_ambientPerformance );
+ if ( NULL == m_ambientPerformance )
+ {
+ return 0.0f;
+ }
+ else
+ {
+ return( radmusic::performance_volume( m_ambientPerformance ) );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::SetAmbienceVolume
+//=============================================================================
+// Description: Set the ambience volume.
+//
+// Parameters: volume - new volume setting
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::SetAmbienceVolume( float volume )
+{
+ rAssert( NULL != m_ambientPerformance );
+ if ( NULL != m_ambientPerformance )
+ {
+ radmusic::performance_volume( m_ambientPerformance, volume );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::GetBeatValue
+//=============================================================================
+// Description: Pass on the beat from the music performance
+//
+// Parameters: None
+//
+// Return: float from 0.0f to 4.0f
+//
+//=============================================================================
+float MusicPlayer::GetBeatValue()
+{
+ float beat = 0.0f;
+
+ if( m_musicPerformance != NULL )
+ {
+ radmusic::debug_performance_current_beat( m_musicPerformance, &beat );
+ }
+
+ return( beat );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// MusicPlayer::calculateLevelIndex
+//=============================================================================
+// Description: Figure out an index for the current level (0 for L1, 1 for L2...)
+//
+// Parameters: None
+//
+// Return: Index
+//
+//=============================================================================
+int MusicPlayer::calculateLevelIndex()
+{
+ RenderEnums::LevelEnum level;
+
+ level = GetGameplayManager()->GetCurrentLevelIndex();
+
+ return( static_cast<int>( level - RenderEnums::L1 ) );
+}
+
+//=============================================================================
+// MusicPlayer::calculateMissionIndex
+//=============================================================================
+// Description: Figure out an index for the current mission (0 for M1, 1 for M2...).
+// Use -1 for Sunday Drive.
+//
+// Parameters: None
+//
+// Return: Index
+//
+//=============================================================================
+int MusicPlayer::calculateMissionIndex()
+{
+ int index;
+ int missionIndex;
+ Mission* currentMission;
+ GameplayManager* gameplayMgr = GetGameplayManager();
+
+ if( gameplayMgr->IsSundayDrive() )
+ {
+ index = -1;
+ }
+ else
+ {
+ currentMission = gameplayMgr->GetCurrentMission();
+ rAssert( currentMission != NULL );
+
+ if( currentMission->IsRaceMission() )
+ {
+ index = ( gameplayMgr->GetCurrentMissionNum() - GameplayManager::MAX_MISSIONS ) * ( MEVENT_END_RACE_EVENTS - MEVENT_STREETRACE_START );
+ }
+ else if( currentMission->IsBonusMission() )
+ {
+ index = 8 * ( MEVENT_END_MISSION_EVENTS - MEVENT_MISSION_START ); // 0-7 are regular missions, 8 is bonus
+ }
+ else
+ {
+ missionIndex = gameplayMgr->GetCurrentMissionIndex();
+
+ //
+ // Stupid dummy level 1 and its special-case training mission
+ //
+ if( gameplayMgr->GetCurrentLevelIndex() != RenderEnums::L1 )
+ {
+ missionIndex += 1;
+ }
+
+ index = missionIndex * ( MEVENT_END_MISSION_EVENTS - MEVENT_MISSION_START );
+ }
+ }
+
+ return( index );
+}
+
+//=============================================================================
+// MusicPlayer::calculateInteriorIndex
+//=============================================================================
+// Description: Figure out an index for the interior being entered
+//
+// Parameters: None
+//
+// Return: Index starting from 0, to be added to first interior event
+// in ambient list
+//
+//=============================================================================
+int MusicPlayer::calculateInteriorIndex( tUID interiorID )
+{
+ int i;
+ int retVal = 2; // Default to Simpsons house sound
+
+ //
+ // We should've be calculating this unless we're actually inside
+ //
+ rAssert( interiorID != static_cast< tUID >( 0 ) );
+
+ if( interiorNameTable[0].id == static_cast< tUID >( 0 ) )
+ {
+ //
+ // Initialize table
+ //
+ for( i = 0; i < interiorTableLength; i++ )
+ {
+ interiorNameTable[i].id = tName::MakeUID( interiorNameTable[i].name );
+ }
+ }
+
+ for( i = 0; i < interiorTableLength; i++ )
+ {
+ if( interiorID == static_cast< tUID >( interiorNameTable[i].id ) )
+ {
+ retVal = i;
+ break;
+ }
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// MusicPlayer::musicLockedOnForStage
+//=============================================================================
+// Description: Checks the current mission stage to see if we need to keep
+// the music playing when we get out of the car
+//
+// Parameters: None
+//
+// Return: True if music stays on, false otherwise
+//
+//=============================================================================
+bool MusicPlayer::musicLockedOnForStage()
+{
+ Mission* mission;
+ MissionStage* stage;
+ bool musicLocked = false;
+
+ mission = GetGameplayManager()->GetCurrentMission();
+ if( mission != NULL )
+ {
+ stage = mission->GetCurrentStage();
+ if( stage != NULL )
+ {
+ musicLocked = stage->GetMusicAlwaysOnFlag();
+ }
+ }
+
+ return( musicLocked );
+}
+
+//=============================================================================
+// MusicPlayer::startMusic
+//=============================================================================
+// Description: Figure out which music track to play and play it
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::startMusic()
+{
+ // bmc: if calling startMusic then hit and run *must* be over...clean it up
+ s_PostHitAndRunTimer = -99;
+ // bmc
+
+ int mission;
+ bool onFoot = false;
+
+ mission = calculateMissionIndex();
+ if( mission >= 0 )
+ {
+ if( currentMissionIsRace() )
+ {
+ TriggerMusicEvent( MEVENT_STREETRACE_START );
+ }
+ else if ( m_isInCar )
+ {
+ TriggerMusicEvent( MEVENT_MISSION_START );
+ }
+ else
+ {
+ TriggerMusicEvent( MEVENT_OF_EXPLORE_MISSION );
+ onFoot = true;
+ }
+
+ }
+ else if( GetGameplayManager()->IsSuperSprint() )
+ {
+ //
+ // Play Fox's licensed music. Fox sucks.
+ //
+ TriggerMusicEvent( MEVENT_SUPERSPRINT );
+ }
+ else if ( m_isInCar )
+ {
+ TriggerMusicEvent( MEVENT_SUNDAY_DRIVE_START );
+ }
+ else
+ {
+ TriggerMusicEvent( MEVENT_OF_EXPLORE_MISSION );
+ onFoot = true;
+ }
+
+ if( !onFoot )
+ {
+ turnAmbienceOff( AEVENT_PAUSE );
+ }
+ else if( ( GetInteriorManager() != NULL )
+ && ( GetInteriorManager()->IsInside() ) )
+ {
+ triggerCurrentInteriorAmbience();
+ }
+ else
+ {
+ turnAmbienceOn( m_currentAmbient );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::playPostMissionSounds
+//=============================================================================
+// Description: Figure out what to play when the mission ends
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::playPostMissionSounds()
+{
+ if( !m_isInCar )
+ {
+ if( ( GetInteriorManager() != NULL )
+ && ( GetInteriorManager()->IsInside() ) )
+ {
+ triggerCurrentInteriorAmbience();
+ }
+ else
+ {
+ turnAmbienceOn( m_currentAmbient );
+ }
+ }
+
+ m_delayedMusicStart = true;
+}
+
+//=============================================================================
+// MusicPlayer::turnAmbienceOn
+//=============================================================================
+// Description: Send the given ambience event and mark ambience as not
+// playing
+//
+// Parameters: event - event to give to ambient performance object (shouldn't
+// be pause or stop event)
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::turnAmbienceOn( unsigned int event )
+{
+ TriggerAmbientEvent( event );
+
+ if( ( event != AEVENT_UNPAUSE ) && ( event <= AEVENT_TRIGGER_END ) )
+ {
+ m_currentAmbient = event;
+ }
+ m_ambiencePlaying = true;
+}
+
+//=============================================================================
+// MusicPlayer::turnAmbienceOff
+//=============================================================================
+// Description: Send the given ambience event and mark ambience as playing
+//
+// Parameters: event - event to give to ambient performance object (should
+// be pause or stop event)
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::turnAmbienceOff( unsigned int event )
+{
+ rAssert( ( event == AEVENT_PAUSE ) || ( event == AEVENT_MOVIE )
+ || ( event == AEVENT_FRONTEND ) );
+
+ TriggerAmbientEvent( event );
+ m_ambiencePlaying = false;
+}
+
+//=============================================================================
+// MusicPlayer::currentMissionIsRace
+//=============================================================================
+// Description: As the name says
+//
+// Parameters: None
+//
+// Return: True if there's a current mission and it's a race, false
+// otherwise
+//
+//=============================================================================
+bool MusicPlayer::currentMissionIsRace()
+{
+ bool retVal = false;
+ Mission* theMission = GetGameplayManager()->GetCurrentMission();
+
+ if( ( theMission != NULL ) && ( theMission->IsRaceMission() ) )
+ {
+ retVal = true;
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// MusicPlayer::currentMissionIsSundayDrive
+//=============================================================================
+// Description: As the name says
+//
+// Parameters: None
+//
+// Return: True if there's a current mission and it's Sunday Drive, false
+// otherwise
+//
+//=============================================================================
+bool MusicPlayer::currentMissionIsSundayDrive()
+{
+ bool retVal = false;
+ Mission* theMission = GetGameplayManager()->GetCurrentMission();
+
+ if( ( theMission != NULL ) && ( theMission->IsSundayDrive() ) )
+ {
+ retVal = true;
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// MusicPlayer::initializeTableNameKeys
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::initializeTableNameKeys()
+{
+ unsigned int i;
+ char temp[256];
+ unsigned int tableIndex;
+ char prefix[10];
+
+ //
+ // We've already got strings for the musicEventTable, just make keys
+ //
+ for( i = 0; i < musicEventTableLength; i++ )
+ {
+ musicEventTable[i].nameKey = ::radMakeCaseInsensitiveKey32( musicEventTable[i].name );
+ }
+
+ //
+ // For the mission and race tables, generate strings and store the keys
+ //
+ tableIndex = 0;
+ for( i = 0; i < 9; i++ ) // min. 8 missions per level + bonus
+ {
+ if( i == 8 )
+ {
+ strcpy( prefix, "Bonus" );
+ }
+ else
+ {
+ sprintf( prefix, "M%d", i );
+ }
+
+ sprintf( temp, "%s_start", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "%s_drama", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "%s_win", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "%s_lose", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "%s_get_out_of_car", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "%s_10sec_to_go", prefix );
+ missionScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+ }
+ //
+ // Record the length of this table
+ //
+ rAssert( tableIndex <= MISSION_TABLE_SIZE );
+ missionScriptTableLength = tableIndex;
+
+ //
+ // Just to be safe
+ //
+ for( i = missionScriptTableLength; i < MISSION_TABLE_SIZE; i++ )
+ {
+ missionScriptTable[i].nameKey = 0;
+ missionScriptTable[i].scriptIndex = NO_INDEX;
+ }
+
+ tableIndex = 0;
+ for( i = 0; i < 3; i++ ) // 3 race missions
+ {
+ sprintf( temp, "StreetRace0%d_start", i+1 );
+ raceScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "StreetRace0%d_win", i+1 );
+ raceScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "StreetRace0%d_lose", i+1 );
+ raceScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ sprintf( temp, "StreetRace0%d_getoutofcar", i+1 );
+ raceScriptTable[tableIndex++].nameKey = ::radMakeCaseInsensitiveKey32( temp );
+ }
+ //
+ // Record the length of this table
+ //
+ rAssert( tableIndex <= RACE_TABLE_SIZE );
+ raceScriptTableLength = tableIndex;
+
+ //
+ // Just to be safe one more time
+ //
+ for( i = raceScriptTableLength; i < RACE_TABLE_SIZE; i++ )
+ {
+ raceScriptTable[i].nameKey = 0;
+ raceScriptTable[i].scriptIndex = NO_INDEX;
+ }
+}
+
+//=============================================================================
+// MusicPlayer::buildEventTables
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::buildEventTables()
+{
+ unsigned int i, j;
+ unsigned int scriptLength;
+ char temp[256];
+ radKey32 tempKey;
+ bool found;
+ unsigned int numStates;
+ unsigned int numStateEvents;
+ radKey32 stateKey;
+ radKey32 stateEventKey;
+ unsigned int currentTableLine;
+
+ //
+ // First, clear the old values out
+ //
+ for( i = 0; i < musicEventTableLength; i++ )
+ {
+ musicEventTable[i].scriptIndex = NO_INDEX;
+ }
+
+ for( i = 0; i < MISSION_TABLE_SIZE; i++ )
+ {
+ missionScriptTable[i].scriptIndex = NO_INDEX;
+ }
+
+ for( i = 0; i < RACE_TABLE_SIZE; i++ )
+ {
+ raceScriptTable[i].scriptIndex = NO_INDEX;
+ }
+
+ for( i = 0; i < MATRIX_TABLE_SIZE; i++ )
+ {
+ matrixStateTable[i].stateNameKey = 0;
+ matrixStateTable[i].stateIndex = NO_INDEX;
+ matrixStateTable[i].stateValueNameKey = 0;
+ matrixStateTable[i].stateValueIndex = NO_INDEX;
+ }
+
+ //
+ // Now, go through each event in the script and search for a match
+ // in the tables. If one is found, fill in its index
+ //
+ scriptLength = radmusic::performance_num_events( m_musicPerformance );
+ for( i = 0; i < scriptLength; i++ )
+ {
+ radmusic::performance_event_name( m_musicPerformance, i, temp, 256 );
+ tempKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ found = false;
+
+ //
+ // Check standard music events first
+ //
+ for( j = 0; j < musicEventTableLength; j++ )
+ {
+ if( musicEventTable[j].nameKey == tempKey )
+ {
+ musicEventTable[j].scriptIndex = i;
+ found = true;
+ break;
+ }
+ }
+
+ //
+ // If not there, try mission events
+ //
+ if( !found )
+ {
+ for( j = 0; j < missionScriptTableLength; j++ )
+ {
+ if( missionScriptTable[j].nameKey == tempKey )
+ {
+ missionScriptTable[j].scriptIndex = i;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ //
+ // Finally, try race events
+ //
+ if( !found )
+ {
+ for( j = 0; j < raceScriptTableLength; j++ )
+ {
+ if( raceScriptTable[j].nameKey == tempKey )
+ {
+ raceScriptTable[j].scriptIndex = i;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ //
+ // If we get here without a match, Marc's got an event we're not using
+ // anywhere yet. Assert on this at some point once the script appears
+ // stabilized.
+ //
+ //rAssert( found );
+ }
+
+ //
+ // Now, build the matrix event table. Go through all the states, and make
+ // a table of all the state/event pairs
+ //
+ currentTableLine = 0;
+
+ numStates = radmusic::performance_num_states( m_musicPerformance );
+ for( i = 0; i < numStates; i++ )
+ {
+ radmusic::performance_state_name( m_musicPerformance, i, temp, 256 );
+ stateKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ numStateEvents = radmusic::performance_num_state_values( m_musicPerformance, i );
+ for( j = 0; j < numStateEvents; j++ )
+ {
+ radmusic::performance_state_value_name( m_musicPerformance, i, j, temp, 256 );
+ stateEventKey = ::radMakeCaseInsensitiveKey32( temp );
+
+ rAssert( currentTableLine < MATRIX_TABLE_SIZE );
+
+ matrixStateTable[currentTableLine].stateIndex = i;
+ matrixStateTable[currentTableLine].stateValueIndex = j;
+ matrixStateTable[currentTableLine].stateNameKey = stateKey;
+ matrixStateTable[currentTableLine++].stateValueNameKey = stateEventKey;
+ }
+ }
+
+ matrixStateTableLength = currentTableLine;
+}
+
+//=============================================================================
+// MusicPlayer::triggerMusicMissionEventByName
+//=============================================================================
+// Description: Trigger a music event by matching the key to the event names
+// in the mission event table
+//
+// Parameters: key - radKey for the name of the event to trigger
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::triggerMusicMissionEventByName( radKey32* key )
+{
+ unsigned int i;
+
+ rAssert( key != NULL );
+
+ if( !(CommandLineOptions::Get( CLO_NO_MUSIC )) )
+ {
+ for( i = 0; i < missionScriptTableLength; i++ )
+ {
+ if( missionScriptTable[i].nameKey == *key )
+ {
+ if( missionScriptTable[i].scriptIndex != NO_INDEX )
+ {
+ radmusic::performance_trigger_event( m_musicPerformance,
+ missionScriptTable[i].scriptIndex );
+ }
+ break;
+ }
+ }
+ }
+}
+
+//=============================================================================
+// MusicPlayer::triggerMusicStateChange
+//=============================================================================
+// Description: Change the radMusic state
+//
+// Parameters: stateKey - name of state
+// stateEventKey - name of event
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::triggerMusicStateChange( radKey32 stateKey, radKey32 stateEventKey )
+{
+ unsigned int i;
+
+ //
+ // Look for a match in the matrix table
+ //
+ for( i = 0; i < matrixStateTableLength; i++ )
+ {
+ if( ( matrixStateTable[i].stateNameKey == stateKey )
+ && ( matrixStateTable[i].stateValueNameKey == stateEventKey ) )
+ {
+ //
+ // Match, trigger the state change
+ //
+ radmusic::performance_state_value( m_musicPerformance,
+ matrixStateTable[i].stateIndex,
+ matrixStateTable[i].stateValueIndex );
+
+ //
+ // We need to trigger an event to prompt the change. Presumably
+ // we do this only for in-car stuff.
+ //
+ if( m_isInCar )
+ {
+ TriggerMusicEvent( MEVENT_MISSION_START );
+ }
+ break;
+ }
+ }
+
+ if( i == matrixStateTableLength )
+ {
+ rAssertMsg( false, "Mission script calling non-existent radMusic state" );
+ }
+}
+
+//=============================================================================
+// MusicPlayer::triggerCurrentInteriorAmbience
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void MusicPlayer::triggerCurrentInteriorAmbience()
+{
+ int interiorIndex;
+
+ interiorIndex = calculateInteriorIndex( GetInteriorManager()->GetInterior() );
+ turnAmbienceOn( AEVENT_INTERIOR_KWIK_E_MART + interiorIndex );
+} \ No newline at end of file
diff --git a/game/code/sound/music/musicplayer.h b/game/code/sound/music/musicplayer.h
new file mode 100644
index 0000000..046c0a3
--- /dev/null
+++ b/game/code/sound/music/musicplayer.h
@@ -0,0 +1,344 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: musicplayer.h
+//
+// Description: Declaration of the MusicPlayer class. Plays all music in
+// the game using RadMusic.
+//
+// History: 17/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef MUSICPLAYER_H
+#define MUSICPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <p3d/p3dtypes.hpp>
+
+#include <events/eventlistener.h>
+#include <render/Enums/RenderEnums.h>
+
+//========================================
+// Forward References
+//========================================
+
+namespace Sound
+{
+ struct IDaSoundTuner;
+}
+namespace radmusic
+{
+ struct performance;
+ struct composition;
+}
+
+class SoundFileHandler;
+class radLoadRequest;
+class Actor;
+
+//
+// Events for interactive music.
+//
+enum MusicEventList
+{
+ MEVENT_MOVIE,
+
+ MEVENT_PAUSE,
+ MEVENT_UNPAUSE,
+
+ MEVENT_FE,
+
+ MEVENT_LOADING_SCREEN,
+ MEVENT_NEWSPAPER_SPIN,
+
+ MEVENT_SUPERSPRINT,
+ MEVENT_SUPERSPRINT_WIN,
+ MEVENT_SUPERSPRINT_LOSE,
+
+ MEVENT_LEVEL_INTRO,
+
+ MEVENT_SUNDAY_DRIVE_START,
+ MEVENT_SUNDAY_DRIVE_GET_OUT_OF_CAR,
+
+ MEVENT_STORE,
+
+ MEVENT_ENTER_STONECUTTER_TUNNEL,
+ MEVENT_EXIT_STONECUTTER_TUNNEL,
+
+ MEVENT_OF_EXPLORE_MISSION,
+ MEVENT_OF_FOUND_CARD,
+ MEVENT_OF_TIME_OUT,
+
+ MEVENT_APU_OASIS,
+
+ MEVENT_INTERIOR_HOUSE,
+ MEVENT_INTERIOR_KWIK_E_MART,
+ MEVENT_INTERIOR_SCHOOL,
+ MEVENT_INTERIOR_MOES,
+ MEVENT_INTERIOR_DMV,
+ MEVENT_INTERIOR_ANDROID_DUNGEON,
+ MEVENT_INTERIOR_OBSERVATORY,
+
+ MEVENT_WIN_3_RACES,
+ MEVENT_LEVEL_COMPLETED,
+ MEVENT_DESTROY_CAMERA_BONUS,
+
+ MEVENT_STONECUTTER_SONG,
+ MEVENT_LBC_SONG,
+ MEVENT_DUFF_SONG,
+
+ MEVENT_HIT_AND_RUN_START,
+ MEVENT_HIT_AND_RUN_CAUGHT,
+
+ MEVENT_WASP_ATTACK,
+
+ MEVENT_GATED_MISSION,
+
+ MEVENT_SCARYMUSIC,
+
+ MEVENT_CREDITS,
+
+ MEVENT_END_STANDARD_EVENTS,
+
+ MEVENT_MISSION_START,
+ MEVENT_MISSION_DRAMA,
+ MEVENT_WIN_MISSION,
+ MEVENT_LOSE_MISSION,
+ MEVENT_GET_OUT_OF_CAR,
+ MEVENT_10_SEC_TO_GO,
+
+ MEVENT_END_MISSION_EVENTS,
+
+ MEVENT_STREETRACE_START,
+ MEVENT_STREETRACE_WIN,
+ MEVENT_STREETRACE_LOSE,
+ MEVENT_STREETRACE_GET_OUT_OF_CAR,
+
+ MEVENT_END_RACE_EVENTS,
+
+ MEVENT_NUM_EVENTS
+};
+
+//
+// Events for ambient sound script. Not actually stored anywhere, but it gives
+// me some identifiers to play with
+//
+enum AmbientEventList
+{
+ AEVENT_FRONTEND,
+
+ AEVENT_MOVIE,
+ AEVENT_PAUSE,
+ AEVENT_UNPAUSE,
+
+ AEVENT_TRIGGER_START,
+
+ AEVENT_TRIGGER_END = 73,
+
+ AEVENT_INTERIOR_KWIK_E_MART,
+ AEVENT_INTERIOR_SCHOOL,
+ AEVENT_INTERIOR_HOUSE,
+ AEVENT_INTERIOR_KRUSTYLU,
+ AEVENT_INTERIOR_DMV,
+
+ AEVENT_NUM_EVENTS
+};
+
+//=============================================================================
+//
+// Synopsis: MusicPlayer
+//
+//=============================================================================
+
+class MusicPlayer : public EventListener
+{
+ public:
+ MusicPlayer( Sound::IDaSoundTuner& tuner );
+ virtual ~MusicPlayer();
+
+ void Service();
+
+ void QueueRadmusicScriptLoad();
+ void QueueMusicLevelLoad( RenderEnums::LevelEnum level );
+
+ //
+ // Notify loading system when script file load complete
+ //
+ void LoadRadmusicScript( const char* filename, SoundFileHandler* fileHandler );
+ void UnloadRadmusicScript();
+
+ //
+ // Look for notification when the player gets in and out of the car
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ //
+ // Functions for notification of change in game state
+ //
+ void OnFrontEndStart();
+ void OnFrontEndFinish();
+
+ void OnGameplayStart( bool playerInCar );
+ void OnGameplayFinish();
+
+ void OnPauseStart();
+ void OnPauseEnd();
+
+ void OnStoreStart();
+ void OnStoreEnd();
+
+ void StopForMovie();
+ void ResumeAfterMovie();
+
+ bool IsStoppedForMovie();
+
+ void RestartSupersprintMusic();
+
+ //
+ // Volume controls
+ //
+ float GetVolume();
+ void SetVolume( float volume );
+ float GetAmbienceVolume();
+ void SetAmbienceVolume( float volume );
+
+ //
+ // Beat values
+ //
+ float GetBeatValue();
+
+ private:
+ //Prevent wasteful constructor creation.
+ MusicPlayer();
+ MusicPlayer( const MusicPlayer& original );
+ MusicPlayer& operator=( const MusicPlayer& rhs );
+
+ void SetUpPerformance(
+ radmusic::performance **,
+ radmusic::composition **,
+ const char * searchPath );
+
+ void TriggerMusicEvent( MusicEventList event );
+ void TriggerAmbientEvent( unsigned int event );
+ void triggerMusicMissionEventByName( radKey32* key );
+
+ unsigned int m_lastServiceTime;
+
+ // Needed for polling the composition loader
+ bool m_isLoadingMusic;
+
+ // True if player currently in car, false otherwise
+ bool m_isInCar;
+
+ // Composition loader
+
+ radLoadRequest* m_radLoadRequest;
+ char n_currentLoadName[ 64 ]; // hack for radload memory leak.
+
+ // Performance object
+ radmusic::performance * m_musicPerformance;
+ radmusic::composition * m_musicComposition;
+
+ //
+ // Ambient script stuff
+ //
+ bool m_isLoadingAmbient;
+
+ radmusic::performance * m_ambientPerformance;
+ radmusic::composition * m_ambientComposition;
+
+ // File load completion callback object
+ SoundFileHandler* m_loadCompleteCallback;
+
+ // Current ambient sound
+ unsigned int m_currentAmbient;
+ bool m_ambiencePlaying;
+
+ //
+ // Special music cases
+ //
+ bool m_onApuRooftop;
+ bool m_stoneCutterSong;
+ bool m_LBCSong;
+
+ //
+ // Delayed music start
+ //
+ bool m_delayedMusicStart;
+
+ //
+ // Wasp that triggered music
+ //
+ Actor* m_wasp;
+
+ //
+ // Calculate offset for current level
+ //
+ int calculateLevelIndex();
+
+ //
+ // Calculate offset for current mission
+ //
+ int calculateMissionIndex();
+
+ //
+ // Calculate offset for interior we're about to enter
+ //
+ int calculateInteriorIndex( tUID interiorID );
+
+ //
+ // Returns flag indicating whether we use ambient on-foot stuff for
+ // this stage
+ //
+ bool musicLockedOnForStage();
+
+ //
+ // Trigger the events to start music
+ //
+ void startMusic();
+
+ //
+ // Figure out what to do after the mission ends
+ //
+ void playPostMissionSounds();
+
+ //
+ // Turn ambient sound on and off
+ //
+ void turnAmbienceOn( unsigned int event );
+ void turnAmbienceOff( unsigned int event );
+
+ //
+ // True if current mission is a race, false otherwise
+ //
+ bool currentMissionIsRace();
+
+ //
+ // True if we're in Sunday Drive, false otherwise
+ //
+ bool currentMissionIsSundayDrive();
+
+ //
+ // Construct tables for faster lookup of music events in script
+ //
+ void initializeTableNameKeys();
+ void buildEventTables();
+
+ //
+ // Change the radMusic state
+ //
+ void triggerMusicStateChange( radKey32 stateKey, radKey32 stateEventKey );
+
+ int findStandardMusicEvent( MusicEventList event );
+ int findMissionEvent( MusicEventList event, int mission );
+ int findRaceEvent( MusicEventList event, int race );
+
+ void triggerCurrentInteriorAmbience();
+};
+
+
+#endif // MUSICPLAYER_H
+
diff --git a/game/code/sound/nis/allnissound.cpp b/game/code/sound/nis/allnissound.cpp
new file mode 100644
index 0000000..b943327
--- /dev/null
+++ b/game/code/sound/nis/allnissound.cpp
@@ -0,0 +1 @@
+#include <sound/nis/nissoundplayer.cpp>
diff --git a/game/code/sound/nis/nissoundplayer.cpp b/game/code/sound/nis/nissoundplayer.cpp
new file mode 100644
index 0000000..14d118e
--- /dev/null
+++ b/game/code/sound/nis/nissoundplayer.cpp
@@ -0,0 +1,388 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: nissoundplayer.cpp
+//
+// Description: Implement NISSoundPlayer, which interacts with the dialog
+// system to provide NIS sounds.
+//
+// History: 10/5/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+// Foundation Tech
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/nis/nissoundplayer.h>
+
+#include <sound/soundmanager.h>
+
+#include <events/eventmanager.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Table of NIS resources.
+//
+
+NISPlayerGroup::NISPlayerGroup() :
+ m_soundID( 0 ),
+ m_loadCallback( NULL ),
+ m_playCallback( NULL ),
+ m_soundQueued( false )
+{
+}
+
+NISPlayerGroup::~NISPlayerGroup()
+{
+}
+
+void NISPlayerGroup::LoadSound( radKey32 soundID, NISSoundLoadedCallback* callback )
+{
+ //
+ // For NIS playback, don't use buffered data sources. Hopefully we
+ // won't be play these in situations where skipping is likely. If it
+ // happens, then we can experiment with short buffers, I suppose.
+ // Stinky limited IOP memory.
+ //
+ m_soundQueued = m_player.QueueSound( soundID, this );
+
+ if( m_soundQueued )
+ {
+ m_loadCallback = callback;
+ m_soundID = soundID;
+ }
+}
+
+void NISPlayerGroup::PlaySound( rmt::Box3D* box, NISSoundPlaybackCompleteCallback* callback )
+{
+ radSoundVector position;
+ rmt::Vector midpoint;
+
+ if( m_soundQueued )
+ {
+ //
+ // Calculate position to play at
+ //
+ rAssert( box != NULL );
+ midpoint = box->Mid();
+ position.SetElements( midpoint.x, midpoint.y, midpoint.z );
+
+ m_playCallback = callback;
+ m_player.PlayQueuedSound( position, this );
+ }
+}
+
+void NISPlayerGroup::StopAndDumpSound()
+{
+ // Just in case.
+ m_loadCallback = NULL;
+ m_playCallback = NULL;
+ m_soundQueued = false;
+ m_soundID = 0;
+
+ m_player.Stop();
+}
+
+bool NISPlayerGroup::IsSoundIDLoaded( radKey32 soundID )
+{
+ return( m_soundID == soundID );
+}
+
+void NISPlayerGroup::Continue()
+{
+ if( m_player.IsPaused() )
+ {
+ m_player.Continue();
+ }
+}
+
+//=============================================================================
+// NISPlayerGroup::OnSoundReady
+//=============================================================================
+// Description: Called from m_player when sound is cued. Notify the
+// callback object
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void NISPlayerGroup::OnSoundReady()
+{
+ if( m_loadCallback )
+ {
+ m_loadCallback->NISSoundLoaded();
+ m_loadCallback = NULL;
+ }
+}
+
+//=============================================================================
+// NISPlayerGroup::OnPlaybackComplete
+//=============================================================================
+// Description: Called from m_player when playback is done. Notify the
+// callback object
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void NISPlayerGroup::OnPlaybackComplete()
+{
+ if( m_playCallback )
+ {
+ m_playCallback->NISSoundPlaybackComplete();
+ m_playCallback = NULL;
+ }
+
+ m_soundID = 0;
+}
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// NISSoundPlayer::NISSoundPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+NISSoundPlayer::NISSoundPlayer() :
+ m_currentFEGag( 0 )
+{
+ //
+ // Register as an event listener
+ //
+ GetEventManager()->AddListener( this, EVENT_FE_GAG_INIT );
+ GetEventManager()->AddListener( this, EVENT_FE_GAG_START );
+ GetEventManager()->AddListener( this, EVENT_FE_GAG_STOP );
+}
+
+//==============================================================================
+// NISSoundPlayer::~NISSoundPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+NISSoundPlayer::~NISSoundPlayer()
+{
+}
+
+//=============================================================================
+// NISSoundPlayer::LoadNISSound
+//=============================================================================
+// Description: Cue an NIS sound for playback
+//
+// Parameters: NISSound - sound to load
+// callback - object to notify when loading is complete
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::LoadNISSound( radKey32 NISSoundID, NISSoundLoadedCallback* callback )
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_NIS_PLAYERS; i++ )
+ {
+ if( m_NISPlayers[i].IsFree() )
+ {
+ m_NISPlayers[i].LoadSound( NISSoundID, callback );
+ break;
+ }
+ }
+
+ rAssert( i < NUM_NIS_PLAYERS );
+}
+
+//=============================================================================
+// NISSoundPlayer::PlayNISSound
+//=============================================================================
+// Description: Play the cued NIS sound
+//
+// Parameters: callback - object to notify when playback is complete
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::PlayNISSound( radKey32 NISSoundID, rmt::Box3D* box, NISSoundPlaybackCompleteCallback* callback )
+{
+ unsigned int i;
+
+ if( NISSoundID == 0 )
+ {
+ rDebugString( "Attempting to play NIS sound where no sound file specified. Ignored.\n" );
+ }
+ else
+ {
+ for( i = 0; i < NUM_NIS_PLAYERS; i++ )
+ {
+ if( m_NISPlayers[i].IsSoundIDLoaded( NISSoundID ) )
+ {
+ m_NISPlayers[i].PlaySound( box, callback );
+ break;
+ }
+ }
+
+ if( i >= NUM_NIS_PLAYERS )
+ {
+ rTuneString( "Attempting to play NIS sound which wasn't loaded. Tell Cory.\n" );
+ //rTuneAssert( false );
+ }
+ }
+}
+
+//=============================================================================
+// NISSoundPlayer::StopAndDumpNISSound
+//=============================================================================
+// Description: Stop the NIS sound if it's playing
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::StopAndDumpNISSound( radKey32 NISSoundID )
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_NIS_PLAYERS; i++ )
+ {
+ if( m_NISPlayers[i].IsSoundIDLoaded( NISSoundID ) )
+ {
+ m_NISPlayers[i].StopAndDumpSound();
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// NISSoundPlayer::PauseAllNISPlayers
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::PauseAllNISPlayers()
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_NIS_PLAYERS; i++ )
+ {
+ m_NISPlayers[i].Pause();
+ }
+}
+
+//=============================================================================
+// NISSoundPlayer::ContinueAllNISPlayers
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::ContinueAllNISPlayers()
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_NIS_PLAYERS; i++ )
+ {
+ m_NISPlayers[i].Continue();
+ }
+}
+
+//=============================================================================
+// NISSoundPlayer::HandleEvent
+//=============================================================================
+// Description: Take care of NIS events thrown by the front end.
+//
+// Parameters: id - event ID
+// pEventData - FE gag name (radKey32) for EVENT_FE_GAG_INIT, unused for rest
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::HandleEvent( EventEnum id, void* pEventData )
+{
+ rmt::Box3D box;
+ rmt::Vector low;
+ rmt::Vector high;
+ radKey32 gagName = 0;
+
+ switch( id )
+ {
+ case EVENT_FE_GAG_INIT:
+ gagName = reinterpret_cast<radKey32>( pEventData );
+ loadFEGag( gagName );
+ break;
+
+ case EVENT_FE_GAG_START:
+ //
+ // Use a hardcoded position here for now. Not ideal, but the
+ // window isn't going anywhere soon.
+ //
+ low.Set( -2.04f, 1.9f, -0.2f );
+ high.Set( -2.0f, 1.96f, -0.1f );
+ box.Set( low, high );
+
+ PlayNISSound( m_currentFEGag, &box, NULL );
+ break;
+
+ case EVENT_FE_GAG_STOP:
+ StopAndDumpNISSound( m_currentFEGag );
+ break;
+
+ default:
+ rAssertMsg( false, "Huh? Shouldn't get an event here." );
+ break;
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// NISSoundPlayer::loadFEGag
+//=============================================================================
+// Description: Find the appropriate FE gag and prep it for playback
+//
+// Parameters: gagIndex - index for gag, sent from front end
+//
+// Return: void
+//
+//=============================================================================
+void NISSoundPlayer::loadFEGag( radKey32 gagKey )
+{
+ m_currentFEGag = gagKey;
+
+ LoadNISSound( gagKey, NULL );
+}
diff --git a/game/code/sound/nis/nissoundplayer.h b/game/code/sound/nis/nissoundplayer.h
new file mode 100644
index 0000000..e9475a6
--- /dev/null
+++ b/game/code/sound/nis/nissoundplayer.h
@@ -0,0 +1,115 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: nissoundplayer.h
+//
+// Description: Declare NISSoundPlayer, which interacts with the dialog
+// system to provide NIS sounds.
+//
+// History: 10/5/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef NISSOUNDPLAYER_H
+#define NISSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radmath/radmath.hpp>
+
+#include <sound/nisenum.h>
+#include <sound/positionalsoundplayer.h>
+
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+struct NISSoundLoadedCallback;
+struct NISSoundPlaybackCompleteCallback;
+
+//=============================================================================
+//
+// Synopsis: NISSoundPlayer
+//
+//=============================================================================
+
+class NISPlayerGroup : public SimpsonsSoundPlayerCallback
+{
+ public:
+ NISPlayerGroup();
+ virtual ~NISPlayerGroup();
+
+ void LoadSound( radKey32 soundID, NISSoundLoadedCallback* callback );
+ void PlaySound( rmt::Box3D* box, NISSoundPlaybackCompleteCallback* callback );
+ void StopAndDumpSound();
+ void Pause() { m_player.Pause(); }
+ void Continue();
+
+ bool IsSoundIDLoaded( radKey32 soundID );
+ bool IsFree() { return( m_soundID == 0 ); }
+
+ //
+ // SimpsonsSoundPlayerCallback interface functions
+ //
+ void OnSoundReady();
+ void OnPlaybackComplete();
+
+ protected:
+ private:
+ //Prevent wasteful constructor creation.
+ NISPlayerGroup( const NISPlayerGroup& original );
+ NISPlayerGroup& operator=( const NISPlayerGroup& rhs );
+
+ PositionalSoundPlayer m_player;
+
+ radKey32 m_soundID;
+
+ NISSoundLoadedCallback* m_loadCallback;
+ NISSoundPlaybackCompleteCallback* m_playCallback;
+
+ bool m_soundQueued;
+};
+
+//=============================================================================
+//
+// Synopsis: NISSoundPlayer
+//
+//=============================================================================
+
+class NISSoundPlayer : public EventListener
+{
+ public:
+ NISSoundPlayer();
+ virtual ~NISSoundPlayer();
+
+ void LoadNISSound( radKey32 NISSoundID, NISSoundLoadedCallback* callback );
+ void PlayNISSound( radKey32 NISSoundID, rmt::Box3D* box, NISSoundPlaybackCompleteCallback* callback );
+ void StopAndDumpNISSound( radKey32 NISSoundID );
+
+ void PauseAllNISPlayers();
+ void ContinueAllNISPlayers();
+
+ //
+ // EventListener functions
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ NISSoundPlayer( const NISSoundPlayer& original );
+ NISSoundPlayer& operator=( const NISSoundPlayer& rhs );
+
+ void loadFEGag( radKey32 gagKey );
+
+ static const unsigned int NUM_NIS_PLAYERS = 6;
+
+ NISPlayerGroup m_NISPlayers[NUM_NIS_PLAYERS];
+
+ radKey32 m_currentFEGag;
+};
+
+
+#endif // NISSOUNDPLAYER_H
+
diff --git a/game/code/sound/nisenum.h b/game/code/sound/nisenum.h
new file mode 100644
index 0000000..f34949f
--- /dev/null
+++ b/game/code/sound/nisenum.h
@@ -0,0 +1,41 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: nisenum.h
+//
+// Description: Enumeration for the NIS sounds
+//
+// History: 10/5/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef NISENUM_H
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: nisenum.h
+//
+// Description: Enumeration of NIS sounds
+//
+// History: + Created -- Darren
+//
+//=============================================================================
+
+#define NISENUM_H
+
+enum NISSoundEnum
+{
+ MOLEMAN_GAG,
+ GRAMPA_GAG,
+ FRINK_GAG,
+ BARNEY_GAG,
+ MOE_GAG,
+ SNAKE_GAG,
+ SEA_CAPTAIN_GAG,
+ DR_NICK_GAG,
+
+ NIS_ENUM_COUNT
+};
+
+#endif // NISENUM_H
+
diff --git a/game/code/sound/positionalsoundplayer.cpp b/game/code/sound/positionalsoundplayer.cpp
new file mode 100644
index 0000000..f3693eb
--- /dev/null
+++ b/game/code/sound/positionalsoundplayer.cpp
@@ -0,0 +1,283 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: positionalsoundplayer.cpp
+//
+// Description: Implement PositionalSoundPlayer
+//
+// History: 12/18/2002 + Created -- NAME
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+#include <sound/soundrenderer/soundplayer.h>
+//========================================
+// Project Includes
+//========================================
+#include <sound/positionalsoundplayer.h>
+
+#include <sound/soundfx/positionalsoundsettings.h>
+
+#include <memory/srrmemory.h>
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+static const float POSITIONAL_PAUSE_BUFFER_DIST = 25.0f;
+
+//=============================================================================
+// PositionCarrier::PositionCarrier
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None
+//
+// Return: N/A
+//
+//=============================================================================
+PositionCarrier::PositionCarrier()
+{
+}
+
+//=============================================================================
+// PositionCarrier::~PositionCarrier
+//=============================================================================
+// Description: Destructor
+//
+// Parameters: None
+//
+// Return: N/A
+//
+//=============================================================================
+PositionCarrier::~PositionCarrier()
+{
+}
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// PositionalSoundPlayer::PositionalSoundPlayer
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+PositionalSoundPlayer::PositionalSoundPlayer( ) :
+ m_positionCarrier( NULL ),
+ m_positionalSettings( NULL ),
+ m_minDist( 3.0f ),
+ m_maxDist( 100.f ),
+ m_position( 0.0f, 0.0f, 0.0f ),
+ m_outOfRange( false )
+{
+ m_Type = Type_Positional;
+}
+
+//=============================================================================
+// PositionalSoundPlayer::~PositionalSoundPlayer
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+PositionalSoundPlayer::~PositionalSoundPlayer()
+{
+ delete m_positionCarrier;
+
+ if( m_positionalSettings != NULL )
+ {
+ m_positionalSettings->Release();
+ m_positionalSettings = NULL;
+ }
+}
+
+bool PositionalSoundPlayer::PlayResource( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback /* = NULL */)
+{
+ bool canPlay;
+
+ canPlay = QueueSound( resource, callback );
+ if( canPlay )
+ {
+ //
+ // m_position should have been set in an earlier call to SetPosition.
+ // If not, then it should be a moving sound and should therefore
+ // get set later by the service function.
+ //
+ PlayQueuedSound( m_position, callback );
+ }
+
+ return( canPlay );
+}
+
+//=============================================================================
+// PositionalSoundPlayer::PlayQueuedSound
+//=============================================================================
+// Description: Sets the position for the sound, then calls PlayQueuedSound
+// in the SimpsonsSoundPlayer base class
+//
+// Parameters: position - position that sound is to be played at
+// callback - object to inform when playback complete
+//
+// Return: void
+//
+//=============================================================================
+void PositionalSoundPlayer::PlayQueuedSound( radSoundVector& position,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ //
+ // Before playing the sound, create a positional group and set the position.
+ // The group is reference counted, so the player will release it when
+ // the sound resource is released.
+ //
+
+ if ( m_playa )
+ {
+ radSoundVector velocity( 0.0f, 0.0f, 0.0f );
+
+ m_playa->SetPositionAndVelocity( & position, & velocity );
+ m_playa->SetMinMaxDistance( m_minDist, m_maxDist );
+ }
+
+ SimpsonsSoundPlayer::PlayQueuedSound( callback );
+}
+
+void PositionalSoundPlayer::ServiceOncePerFrame()
+{
+ radSoundVector position;
+ radSoundVector velocity;
+
+ radSoundVector distanceVector;
+ radSoundVector soundPosition;
+ radSoundVector listenerPosition;
+ float positionalMax;
+ float distance;
+
+ //
+ // Update the positional group with new vehicle position
+ //
+ if( ( m_positionCarrier != NULL ) )
+ {
+ m_positionCarrier->GetPosition( position );
+ m_positionCarrier->GetVelocity( velocity );
+
+ if ( m_playa )
+ {
+ m_playa->SetPositionAndVelocity( & position, & velocity );
+ }
+ }
+
+ //
+ // Do unpause/pause on players when they get in and out of range
+ //
+ if( ( m_playa != NULL ) && ( m_positionalSettings != NULL ) )
+ {
+ ::radSoundHalListenerGet()->GetPosition( &listenerPosition );
+ m_playa->GetPositionalGroup()->GetPosition( &soundPosition );
+ distanceVector = listenerPosition - soundPosition;
+ distance = distanceVector.GetLength();
+
+ positionalMax = m_positionalSettings->GetMaxDistance();
+
+ if( m_outOfRange && ( distance <= ( positionalMax + POSITIONAL_PAUSE_BUFFER_DIST ) ) )
+ {
+ if( IsPaused() )
+ {
+ Continue();
+ }
+ m_outOfRange = false;
+ }
+ else if( ( !m_outOfRange ) && ( distance > ( positionalMax + POSITIONAL_PAUSE_BUFFER_DIST ) ) )
+ {
+ Pause();
+ m_outOfRange = true;
+ }
+ }
+}
+
+void PositionalSoundPlayer::SetPositionCarrier( PositionCarrier& movingSound )
+{
+ m_positionCarrier = &movingSound;
+}
+
+//=============================================================================
+// PositionalSoundPlayer::SetParameters
+//=============================================================================
+// Description: Set the min/max and whatever else from the tunable
+// sound settings object
+//
+// Parameters: settings - object containing sound settings
+//
+// Return: void
+//
+//=============================================================================
+void PositionalSoundPlayer::SetParameters( positionalSoundSettings* settings )
+{
+ m_minDist = settings->GetMinDistance();
+ m_maxDist = settings->GetMaxDistance();
+
+ m_positionalSettings = settings;
+ m_positionalSettings->AddRef();
+
+ if( m_playa != NULL )
+ {
+ m_playa->SetMinMaxDistance( m_minDist, m_maxDist );
+ }
+}
+
+//=============================================================================
+// PositionalSoundPlayer::SetPosition
+//=============================================================================
+// Description: Set the position for the sound
+//
+// Parameters: x,y,z - position
+//
+// Return: void
+//
+//=============================================================================
+void PositionalSoundPlayer::SetPosition( float x, float y, float z )
+{
+ m_position.SetElements( x, y, z );
+}
+
+//*****************************************************************************
+//
+// Protected Member Functions
+//
+//*****************************************************************************
+
+void PositionalSoundPlayer::dumpSoundPlayer()
+{
+ //
+ // Get rid of the positional group
+ //
+
+ if( m_positionalSettings != NULL )
+ {
+ m_positionalSettings->Release();
+ m_positionalSettings = NULL;
+ }
+
+ m_positionCarrier = NULL;
+
+ //
+ // Let the parent clean up now
+ //
+ SimpsonsSoundPlayer::dumpSoundPlayer();
+} \ No newline at end of file
diff --git a/game/code/sound/positionalsoundplayer.h b/game/code/sound/positionalsoundplayer.h
new file mode 100644
index 0000000..dbc1032
--- /dev/null
+++ b/game/code/sound/positionalsoundplayer.h
@@ -0,0 +1,109 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: positionalsoundplayer.h
+//
+// Description: Declaration of wrapper class for playing positional sounds
+//
+// History: 12/18/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef POSITIONALSOUNDPLAYER_H
+#define POSITIONALSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radsoundmath.hpp>
+
+#include <sound/simpsonssoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+class positionalSoundSettings;
+struct IRadSoundHalPositionalGroup;
+
+//=============================================================================
+//
+// Synopsis: PositionCarrier
+//
+//=============================================================================
+
+class PositionCarrier
+{
+ public:
+ PositionCarrier();
+ virtual ~PositionCarrier();
+
+ virtual void GetPosition( radSoundVector& position ) = 0;
+ virtual void GetVelocity( radSoundVector& velocity ) = 0;
+
+ protected:
+ private:
+ //Prevent wasteful constructor creation.
+ PositionCarrier( const PositionCarrier& positioncarrier );
+ PositionCarrier& operator=( const PositionCarrier& positioncarrier );
+};
+
+//=============================================================================
+//
+// Synopsis: PositionalSoundPlayer
+//
+//=============================================================================
+
+class PositionalSoundPlayer : public SimpsonsSoundPlayer
+{
+ public:
+ PositionalSoundPlayer( );
+ virtual ~PositionalSoundPlayer();
+
+ bool PlayResource( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback = NULL );
+ void PlayQueuedSound( radSoundVector& position,
+ SimpsonsSoundPlayerCallback* callback = NULL );
+
+ void SetPositionCarrier( PositionCarrier& movingSound );
+ void UnsetPositionCarrier();
+
+ void SetParameters( positionalSoundSettings* settings );
+ positionalSoundSettings* GetParameters() { return( m_positionalSettings ); }
+
+ void ServiceOncePerFrame();
+
+ void SetPosition( float x, float y, float z );
+
+ protected:
+ //
+ // Called when we're done with the sound renderer player object
+ //
+ void dumpSoundPlayer();
+
+ private:
+ //Prevent wasteful constructor creation.
+ PositionalSoundPlayer( const PositionalSoundPlayer& positionalsoundplayer );
+ PositionalSoundPlayer& operator=( const PositionalSoundPlayer& positionalsoundplayer );
+
+ //
+ // Pointer to sound source, used only if source is moving
+ //
+ PositionCarrier* m_positionCarrier;
+
+ positionalSoundSettings* m_positionalSettings;
+
+ float m_minDist;
+ float m_maxDist;
+
+ radSoundVector m_position;
+
+ bool m_outOfRange;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //POSITIONALSOUNDPLAYER_H
diff --git a/game/code/sound/simpsonssoundplayer.cpp b/game/code/sound/simpsonssoundplayer.cpp
new file mode 100644
index 0000000..a5eb0c7
--- /dev/null
+++ b/game/code/sound/simpsonssoundplayer.cpp
@@ -0,0 +1,539 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: simpsonssoundplayer.cpp
+//
+// Description: Implement SimpsonsSoundPlayer class, which interacts with
+// the sound renderer to play sounds, and tracks the player
+// resources in use.
+//
+// History: 29/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/simpsonssoundplayer.h>
+
+#include <sound/soundmanager.h>
+#include <sound/soundloader.h>
+#include <sound/soundrenderercallback.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <sound/soundrenderer/playermanager.h>
+#include <sound/soundrenderer/idasoundresource.h>
+
+#include <memory/srrmemory.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+unsigned int SimpsonsSoundPlayer::s_playersCreated = 0;
+unsigned int SimpsonsSoundPlayer::s_clipPlayersInUse = 0;
+unsigned int SimpsonsSoundPlayer::s_streamPlayersInUse = 0;
+Sound::daSoundResourceManager* SimpsonsSoundPlayer::s_resourceManager = NULL;
+Sound::daSoundPlayerManager* SimpsonsSoundPlayer::s_playerManager = NULL;
+SoundLoader* SimpsonsSoundPlayer::s_soundLoader = NULL;
+
+//
+// Limits on the number of players that can be playing clips/streams at once.
+// Numbers are arbitrary and subject to experimentation
+//
+static const unsigned int s_maxActiveClipPlayersAllowed = 25;
+static const unsigned int s_maxActiveStreamPlayersAllowed = 8;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SimpsonsSoundPlayer::SimpsonsSoundPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SimpsonsSoundPlayer::SimpsonsSoundPlayer() :
+ m_playa( NULL ),
+ m_callback( NULL )
+
+{
+ m_Type = Type_NonPositional;
+ //
+ // Get resource manager ptr and sound loader ptr if that hasn't been done yet
+ //
+ if( s_resourceManager == NULL )
+ {
+ s_resourceManager = Sound::daSoundRenderingManagerGet()->GetResourceManager();
+ }
+
+ if( s_playerManager == NULL )
+ {
+ s_playerManager = Sound::daSoundRenderingManagerGet()->GetPlayerManager();
+ }
+
+ if( s_soundLoader == NULL )
+ {
+ s_soundLoader = SoundManager::GetInstance()->GetSoundLoader();
+ }
+
+ //
+ // Update statistics
+ //
+ ++s_playersCreated;
+}
+
+//==============================================================================
+// SimpsonsSoundPlayer::~SimpsonsSoundPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SimpsonsSoundPlayer::~SimpsonsSoundPlayer()
+{
+ //
+ // Update statistics
+ //
+ --s_playersCreated;
+
+ if( m_callback != NULL )
+ {
+ m_callback->CancelGameCallbackAndRelease();
+ }
+
+ rAssert( m_playa == NULL );
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::PlaySound
+//=============================================================================
+// Description: Play the sound resource with the given name
+//
+// Parameters: resourceName - string with name of resource to play
+// callback - optional callback on playback completion
+//
+// Return: true if sound could be played, false otherwise
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::PlaySound( const char* resourceName,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ return( PlaySound( ::radMakeKey32( resourceName ), callback ) );
+}
+
+
+//=============================================================================
+// SimpsonsSoundPlayer::PlayResource
+//=============================================================================
+// Description: Play the sound resource
+//
+// Parameters: resource - resource to play
+// callback - object to notify when we're done
+//
+// Return: true if sound could be played, false otherwise
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::PlayResource( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback /* = NULL */ )
+{
+ bool canPlay;
+
+ canPlay = QueueSound( resource, callback );
+ if( canPlay )
+ {
+ PlayQueuedSound();
+ }
+
+ return( canPlay );
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::PlaySound
+//=============================================================================
+// Description: Comment
+//
+// Parameters: resourceKey - hashed value of the name of the sound resource
+// to play
+//
+// Return: true if sound could be played, false otherwise
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::PlaySound( Sound::daResourceKey resourceKey,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ IDaSoundResource* resource;
+ bool retVal;
+
+ resource = s_resourceManager->FindResource( resourceKey );
+
+ if( resource != NULL )
+ {
+ retVal = PlayResource( resource, callback );
+ }
+ else
+ {
+ rDebugString( "Tried to play missing sound resource\n" );
+ retVal = false;
+ }
+
+ return( retVal );
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::QueueSound
+//=============================================================================
+// Description: Queue up a sound for playback, but don't play it. Useful
+// for streamed dialog
+//
+// Parameters: resourceName - name of sound resource to queue
+// callback - playback completion callback, unused if NULL
+// playUnbuffered - if streamer, don't use buffered data source
+//
+// Return: true if sound could be played, false otherwise
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::QueueSound( radKey32 resourceID,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ IDaSoundResource* resource = s_resourceManager->FindResource( resourceID );
+
+ if( resource != NULL )
+ {
+ return( QueueSound( resource, callback ) );
+ }
+ else
+ {
+ rDebugPrintf( "Couldn't play sound resource ID %d\n", resourceID );
+ return( false );
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::QueueSound
+//=============================================================================
+// Description: Queue up a sound for playback, but don't play it. Useful
+// for streamed dialog
+//
+// Parameters: resource - sound resource to queue
+// callback - playback completion callback, unused if NULL
+// playUnbuffered - if streamer, don't use buffered data source
+//
+// Return: true if sound could be played, false otherwise
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::QueueSound( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback )
+{
+ if( m_playa != NULL )
+ {
+ rDebugString( "Dropped sound, player busy\n" );
+ return( false );
+ }
+
+ //
+ // Make sure we haven't maxed our limit on playback of this type of
+ // resource
+ //
+ if( resource->GetType() == IDaSoundResource::CLIP )
+ {
+ if( s_clipPlayersInUse < s_maxActiveClipPlayersAllowed )
+ {
+ ++s_clipPlayersInUse;
+ }
+ else
+ {
+ rAssertMsg( false, "Reached maximum allowable number of clip players\n" );
+ return( false );
+ }
+ }
+ else
+ {
+ rAssert( resource->GetType() == IDaSoundResource::STREAM );
+
+ if( s_streamPlayersInUse < s_maxActiveStreamPlayersAllowed )
+ {
+ ++s_streamPlayersInUse;
+ }
+ else
+ {
+ rAssertMsg( false, "Reached maximum allowable number of stream players\n" );
+ return( false );
+ }
+ }
+
+ s_playerManager->CaptureFreePlayer( &m_playa,
+ resource,
+ Type_Positional == m_Type );
+ rAssert( m_playa != NULL );
+
+ //
+ // Reset trim, just to be safe
+ //
+ m_playa->SetExternalTrim( 1.0f );
+
+ //
+ // Create a callback object and point it toward whoever wants the callback
+ //
+ if( ( callback != NULL ) && ( m_callback == NULL ) )
+ {
+ m_callback = new(GMA_TEMP) SoundRenderingPlayerCallback( *this, callback );
+ m_playa->RegisterSoundPlayerStateCallback( m_callback, NULL );
+ }
+
+ return( true );
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::PlayQueuedSound
+//=============================================================================
+// Description: Play the sound we've queued for playback
+//
+// Parameters: callback - callback to trigger on playback completion, ignored
+// if NULL
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::PlayQueuedSound( SimpsonsSoundPlayerCallback* callback )
+{
+ rAssert( m_playa != NULL );
+
+ //
+ // Play should not get stuck on pauses. If this causes problems,
+ // then I'll have to figure out how to make 100% sure that all
+ // paused streams (e.g. NIS) get unpaused in a proper fashion
+ //
+ if( m_playa->IsPaused() )
+ {
+ m_playa->UberContinue();
+ }
+
+ m_playa->Play();
+
+ //
+ // If requested, create a callback object and point it toward whoever
+ // wants the callback
+ //
+ if( m_callback == NULL )
+ {
+ m_callback = new(GMA_TEMP) SoundRenderingPlayerCallback( *this, callback );
+ m_playa->RegisterSoundPlayerStateCallback( m_callback, NULL );
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::OnPlaybackComplete
+//=============================================================================
+// Description: Callback from the sound renderer callback object when the
+// clip stops playback (not called for looping clips)
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::OnPlaybackComplete()
+{
+ dumpSoundPlayer();
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::Stop
+//=============================================================================
+// Description: Stop playing sound.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::Stop()
+{
+ if( m_playa != NULL )
+ {
+ //
+ // Stop() doesn't seem to play well with paused players. They tend
+ // to remain paused when you reuse them later.
+ //
+ if( m_playa->IsPaused() )
+ {
+ m_playa->Continue();
+ }
+
+ m_playa->Stop();
+
+ if( m_playa != NULL )
+ {
+ //
+ // The player didn't get released because we don't have
+ // a callback set (presumably), so we do it ourselves
+ //
+ dumpSoundPlayer();
+ }
+
+ rAssert( m_playa == NULL );
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::Pause
+//=============================================================================
+// Description: Pause the sound player
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::Pause()
+{
+ if( m_playa != NULL )
+ {
+ m_playa->Pause();
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::Continue
+//=============================================================================
+// Description: Unpause the sound player
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::Continue()
+{
+ if( m_playa != NULL )
+ {
+ m_playa->Continue();
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::IsPaused
+//=============================================================================
+// Description: Indicate whether the player is paused
+//
+// Parameters: None
+//
+// Return: true if paused, false if not or player unused
+//
+//=============================================================================
+bool SimpsonsSoundPlayer::IsPaused()
+{
+ if( m_playa != NULL )
+ {
+ return( m_playa->IsPaused() );
+ }
+ else
+ {
+ return( false );
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::SetPitch
+//=============================================================================
+// Description: Set the pitch of the currently playing clip
+//
+// Parameters: pitch - pitch setting to apply
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::SetPitch( float pitch )
+{
+ if( m_playa != NULL )
+ {
+ m_playa->SetPitch( pitch );
+ }
+ else
+ {
+ rDebugString( "Can't set pitch without associated player\n" );
+ }
+}
+
+//=============================================================================
+// SimpsonsSoundPlayer::SetTrim
+//=============================================================================
+// Description: Set the trim of the currently playing clip
+//
+// Parameters: trim - trim setting to apply
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::SetTrim( float trim )
+{
+ if( m_playa != NULL )
+ {
+ m_playa->SetExternalTrim( trim );
+ }
+ else
+ {
+ rDebugString( "Can't set trim without associated player\n" );
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SimpsonsSoundPlayer::dumpSoundPlayer
+//=============================================================================
+// Description: To be called when we're done with the sound renderer's player
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SimpsonsSoundPlayer::dumpSoundPlayer()
+{
+ if( m_callback )
+ {
+ m_callback->CancelGameCallbackAndRelease();
+ m_playa->UnregisterSoundPlayerStateCallback( m_callback, NULL );
+ m_callback = NULL;
+ }
+
+ if( m_playa->GetPlayerType() == IDaSoundResource::CLIP )
+ {
+ --s_clipPlayersInUse;
+ }
+ else
+ {
+ rAssert( m_playa->GetPlayerType() != IDaSoundResource::UNKNOWN );
+ --s_streamPlayersInUse;
+ }
+
+ if( m_playa->IsCaptured() )
+ {
+ m_playa->UnCapture();
+ }
+ m_playa = NULL;
+} \ No newline at end of file
diff --git a/game/code/sound/simpsonssoundplayer.h b/game/code/sound/simpsonssoundplayer.h
new file mode 100644
index 0000000..98ad6b3
--- /dev/null
+++ b/game/code/sound/simpsonssoundplayer.h
@@ -0,0 +1,136 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: simpsonssoundplayer.h
+//
+// Description: Declaration for SimpsonsSoundPlayer class, which interacts with
+// the sound renderer to play sounds, and tracks the player
+// resources in use.
+//
+// History: 29/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SIMPSONSSOUNDPLAYER_H
+#define SIMPSONSSOUNDPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundrenderer/soundsystem.h>
+
+//========================================
+// Forward References
+//========================================
+namespace Sound
+{
+ class daSoundResourceManager;
+ class daSoundClipStreamPlayer;
+ class daSoundPlayerManager;
+}
+
+struct IDaSoundResource;
+class SoundLoader;
+class SoundRenderingPlayerCallback;
+struct IRadSoundHalPositionalGroup;
+
+//=============================================================================
+//
+// Synopsis: SimpsonsSoundPlayerCallback
+//
+//=============================================================================
+
+struct SimpsonsSoundPlayerCallback
+{
+ virtual void OnSoundReady() = 0;
+ virtual void OnPlaybackComplete() = 0;
+};
+
+//=============================================================================
+//
+// Synopsis: SimpsonsSoundPlayer
+//
+//=============================================================================
+
+class SimpsonsSoundPlayer
+{
+ public:
+ SimpsonsSoundPlayer();
+ virtual ~SimpsonsSoundPlayer();
+
+ bool PlaySound( const char* resourceName, SimpsonsSoundPlayerCallback* callback = NULL );
+
+ bool PlaySound( Sound::daResourceKey resourceKey, SimpsonsSoundPlayerCallback* callback = NULL );
+
+ virtual bool PlayResource( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback = NULL );
+
+ bool QueueSound( const char* resourceName,
+ SimpsonsSoundPlayerCallback* callback = NULL )
+ { return( QueueSound( ::radMakeKey32( resourceName ), callback ) ); }
+
+ bool QueueSound( radKey32 resourceKey,
+ SimpsonsSoundPlayerCallback* callback = NULL );
+
+ bool QueueSound( IDaSoundResource* resource,
+ SimpsonsSoundPlayerCallback* callback = NULL );
+
+ virtual void PlayQueuedSound( SimpsonsSoundPlayerCallback* callback = NULL );
+
+ void Stop();
+ void Pause();
+ void Continue();
+ bool IsPaused();
+
+ void OnPlaybackComplete();
+
+ bool IsInUse() { return( m_playa != NULL ); }
+
+ void SetPitch( float pitch );
+ void SetTrim( float trim );
+
+ protected:
+
+ //
+ // Sound renderer's player object
+ //
+ Sound::daSoundClipStreamPlayer* m_playa;
+
+ //
+ // Call when we're done with the sound renderer player object
+ //
+ virtual void dumpSoundPlayer();
+
+ protected:
+
+ enum Type { Type_Positional, Type_NonPositional } m_Type;
+
+ private:
+ //Prevent wasteful constructor creation.
+ SimpsonsSoundPlayer( const SimpsonsSoundPlayer& original );
+ SimpsonsSoundPlayer& operator=( const SimpsonsSoundPlayer& rhs );
+
+ //
+ // Sound renderer resource manager
+ //
+ static Sound::daSoundResourceManager* s_resourceManager;
+ static Sound::daSoundPlayerManager* s_playerManager;
+ static SoundLoader* s_soundLoader;
+
+ //
+ // Statistics on players in use
+ //
+ static unsigned int s_playersCreated;
+ static unsigned int s_clipPlayersInUse;
+ static unsigned int s_streamPlayersInUse;
+
+ //
+ // Callback object for playback completion
+ //
+ SoundRenderingPlayerCallback* m_callback;
+
+};
+
+
+#endif // SIMPSONSSOUNDPLAYER_H
+
diff --git a/game/code/sound/soundcluster.cpp b/game/code/sound/soundcluster.cpp
new file mode 100644
index 0000000..99e5d4f
--- /dev/null
+++ b/game/code/sound/soundcluster.cpp
@@ -0,0 +1,276 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundcluster.cpp
+//
+// Description: Implement SoundCluster
+//
+// History: 26/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundcluster.h>
+
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+
+#include <loading/soundfilehandler.h>
+#include <memory/srrmemory.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+static const radKey32 NULL_SOUND_KEY = 0;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundCluster::SoundCluster
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundCluster::SoundCluster( int clusterIndex,
+ IRadNameSpace* soundNamespace ) :
+ m_isLoaded( false ),
+ m_namespace( soundNamespace ),
+ m_loadCompleteCallbackObj( NULL )
+{
+ int i;
+
+ //
+ // Initialize the sound list to zeroes, which is hopefully an unlikely radKey32 value
+ //
+ for( i = 0; i < MAX_RESOURCES; i++ )
+ {
+ m_soundList[i] = NULL_SOUND_KEY;
+ }
+
+#ifdef RAD_DEBUG
+ m_clusterIndex = clusterIndex;
+#endif
+}
+
+//==============================================================================
+// SoundCluster::~SoundCluster
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundCluster::~SoundCluster()
+{
+}
+
+//=============================================================================
+// SoundCluster::LoadSounds
+//=============================================================================
+// Description: Loads the sounds listed in m_soundList
+//
+// Parameters: none
+//
+// Return: void
+//
+//=============================================================================
+void SoundCluster::LoadSounds( SoundFileHandler* callbackObj /* = NULL */ )
+{
+ IDaSoundResource* resource;
+ int i;
+
+ MEMTRACK_PUSH_GROUP( "Sound" );
+
+ for( i = 0; i < MAX_RESOURCES; i++ )
+ {
+ if( m_soundList[i] != NULL_SOUND_KEY )
+ {
+ resource = reinterpret_cast< IDaSoundResource* >
+ (
+ m_namespace->GetInstance( m_soundList[i] )
+ );
+
+ if( resource != NULL )
+ {
+ resource->CaptureResource();
+ }
+#ifdef RAD_DEBUG
+ else
+ {
+ //
+ // Sound not found, spew debug message
+ //
+ rDebugPrintf( "Sound resource #%d couldn't be found in cluster #%d\n", i, m_clusterIndex );
+ }
+#endif
+ }
+ }
+
+ //
+ // Register for notification on load completion
+ //
+ Sound::daSoundRenderingManagerGet()->GetDynaLoadManager()->AddCompletionCallback( this, NULL );
+
+ m_loadCompleteCallbackObj = callbackObj;
+
+ //
+ // Tell the resource manager that we're using this namespace
+ //
+ Sound::daSoundRenderingManagerGet()->GetResourceManager()->SetActiveResource( m_namespace );
+
+ MEMTRACK_POP_GROUP( "Sound" );
+}
+
+//=============================================================================
+// SoundCluster::UnloadSounds
+//=============================================================================
+// Description: Unloads the sounds listed in m_soundList
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundCluster::UnloadSounds()
+{
+ IDaSoundResource* resource;
+ int i;
+
+ for( i = 0; i < MAX_RESOURCES; i++ )
+ {
+ if( m_soundList[i] != NULL_SOUND_KEY )
+ {
+ resource = reinterpret_cast< IDaSoundResource* >
+ (
+ m_namespace->GetInstance( m_soundList[i] )
+ );
+
+ if( resource != NULL )
+ {
+ resource->ReleaseResource();
+ }
+#ifdef RAD_DEBUG
+ else
+ {
+ //
+ // Sound not found, spew debug message
+ //
+ rDebugPrintf( "Tried to free unloaded sound resource #%d in cluster #%d\n", i, m_clusterIndex );
+ }
+#endif
+ }
+ }
+
+ //
+ // Tell the resource manager that we're no longer using this namespace
+ //
+ Sound::daSoundRenderingManagerGet()->GetResourceManager()->ReleaseActiveResource( m_namespace );
+
+
+ m_isLoaded = false;
+}
+
+//=============================================================================
+// SoundCluster::AddResource
+//=============================================================================
+// Description: Add given sound resource to the list of resources associated
+// with this cluster
+//
+// Parameters: resourceKey - radKey32 crunched from sound resource name
+//
+// Return: true if we could add it to the list, false otherwise
+//
+//=============================================================================
+bool SoundCluster::AddResource( Sound::daResourceKey resourceKey )
+{
+ int i;
+ bool added = false;
+
+ for( i = 0; i < MAX_RESOURCES; i++ )
+ {
+ if( m_soundList[i] == NULL_SOUND_KEY )
+ {
+ m_soundList[i] = resourceKey;
+ added = true;
+ break;
+ }
+ }
+
+ return( added );
+}
+
+//=============================================================================
+// SoundCluster::ContainsResource
+//=============================================================================
+// Description: Search the sound list and return a bool indicating whether
+// this sound cluster contains the indicated resource
+//
+// Parameters: resourceKey - hashed name of resource to search for
+//
+// Return: true if resource present, false otherwise
+//
+//=============================================================================
+bool SoundCluster::ContainsResource( Sound::daResourceKey resourceKey )
+{
+ int i;
+
+ rAssert( resourceKey != NULL_SOUND_KEY );
+
+ for( i = 0; i < MAX_RESOURCES; i++ )
+ {
+ if( m_soundList[i] == resourceKey )
+ {
+ return( true );
+ }
+ }
+
+ return( false );
+}
+
+//=============================================================================
+// SoundCluster::OnDynaLoadOperationsComplete
+//=============================================================================
+// Description: Called when the sound renderer is finished loading the cluster
+//
+// Parameters: pUserData - user data, unused
+//
+// Return: void
+//
+//=============================================================================
+void SoundCluster::OnDynaLoadOperationsComplete( void* pUserData )
+{
+ m_isLoaded = true;
+ if( m_loadCompleteCallbackObj != NULL )
+ {
+ m_loadCompleteCallbackObj->LoadCompleted();
+ m_loadCompleteCallbackObj = NULL;
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundcluster.h b/game/code/sound/soundcluster.h
new file mode 100644
index 0000000..2abec0c
--- /dev/null
+++ b/game/code/sound/soundcluster.h
@@ -0,0 +1,103 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundcluster.h
+//
+// Description: Declaration of SoundCluster class. Used to allocate a group
+// of related sounds in sound memory. This is an abstract base
+// class, the subclasses are used to differentiate between clips
+// and streams.
+//
+// History: 26/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDCLUSTER_H
+#define SOUNDCLUSTER_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/sounddynaload.h>
+
+//========================================
+// Forward References
+//========================================
+
+class SoundFileHandler;
+struct IRadNameSpace;
+
+//=============================================================================
+//
+// Synopsis: SoundCluster
+//
+//=============================================================================
+
+class SoundCluster : public Sound::IDaSoundDynaLoadCompletionCallback,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "SoundCluster" );
+
+ SoundCluster( int clusterIndex,
+ IRadNameSpace* soundNamespace );
+ virtual ~SoundCluster();
+
+ bool AddResource( const char* resourceName )
+ { return( AddResource( ::radMakeKey32( resourceName ) ) ); }
+ bool AddResource( Sound::daResourceKey resourceKey );
+
+ bool IsLoaded() const { return m_isLoaded; }
+
+ void LoadSounds( SoundFileHandler* callbackObj = NULL );
+ void UnloadSounds();
+
+ bool ContainsResource( const char* resourceName )
+ { return ContainsResource( ::radMakeKey32( resourceName ) ); }
+ bool ContainsResource( Sound::daResourceKey resourceKey );
+
+ IRadNameSpace* GetMyNamespace() { return( m_namespace ); }
+
+ //
+ // Interface for sound renderer load completion callback
+ //
+ void OnDynaLoadOperationsComplete( void* pUserData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundCluster();
+ SoundCluster( const SoundCluster& original );
+ SoundCluster& operator=( const SoundCluster& rhs );
+
+ static const int MAX_RESOURCES = 80;
+
+ //
+ // True if the sounds for this cluster are allocated in sound memory
+ //
+ bool m_isLoaded;
+
+ //
+ // List of sound clips
+ //
+ Sound::daResourceKey m_soundList[MAX_RESOURCES];
+
+ //
+ // Namespace containing these resources
+ //
+ IRadNameSpace* m_namespace;
+
+ //
+ // Callback object on load completion
+ //
+ SoundFileHandler* m_loadCompleteCallbackObj;
+
+#ifdef RAD_DEBUG
+ int m_clusterIndex;
+#endif
+};
+
+
+#endif // SOUNDCLUSTER_H
+
diff --git a/game/code/sound/soundclusternameenum.h b/game/code/sound/soundclusternameenum.h
new file mode 100644
index 0000000..daa6fcf
--- /dev/null
+++ b/game/code/sound/soundclusternameenum.h
@@ -0,0 +1,51 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundclusternameenum.h
+//
+// Description: Definition for SoundClusterName enum
+//
+// History: 11/18/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDCLUSTERNAMEENUM_H
+#define SOUNDCLUSTERNAMEENUM_H
+
+#include <constants/vehicleenum.h>
+
+enum SoundClusterName
+{
+ SC_ALWAYS_LOADED,
+ SC_FRONTEND,
+ SC_INGAME,
+
+ SC_LEVEL_SUBURBS,
+ SC_LEVEL_DOWNTOWN,
+ SC_LEVEL_SEASIDE,
+
+ SC_LEVEL1,
+ SC_LEVEL2,
+ SC_LEVEL3,
+ SC_LEVEL4,
+ SC_LEVEL5,
+ SC_LEVEL6,
+ SC_LEVEL7,
+ SC_MINIGAME,
+
+ SC_NEVER_LOADED,
+
+ SC_CHAR_APU,
+ SC_CHAR_BART,
+ SC_CHAR_HOMER,
+ SC_CHAR_LISA,
+ SC_CHAR_MARGE,
+
+ SC_CAR_BASE,
+
+ SC_MAX_CLUSTERS = SC_CAR_BASE + VehicleEnum::NUM_VEHICLES // SC_CAR_BASE + 53 cars
+};
+
+
+#endif // SOUNDCLUSTERNAMEENUM_H
+
diff --git a/game/code/sound/soundcollisiondata.h b/game/code/sound/soundcollisiondata.h
new file mode 100644
index 0000000..2a986bf
--- /dev/null
+++ b/game/code/sound/soundcollisiondata.h
@@ -0,0 +1,58 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundcollisiondata.h
+//
+// Description: Declaration for SoundCollisionData structure, which carries
+// collision information through the event manager to the sound
+// system
+//
+// History: 04/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDCOLLISIONDATA_H
+#define SOUNDCOLLISIONDATA_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <render/DSG/collisionentitydsg.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: SoundCollisionData
+//
+//=============================================================================
+
+class SoundCollisionData
+{
+ public:
+ SoundCollisionData( float intensity, CollisionEntityDSG* objA, CollisionEntityDSG* objB )
+ {
+ //impulse = vector;
+ mIntensity = intensity;
+ collObjA = objA;
+ collObjB = objB;
+ }
+ ~SoundCollisionData() {}
+
+ float mIntensity; // 0.0f - 1.0f
+ CollisionEntityDSG* collObjA;
+ CollisionEntityDSG* collObjB;
+
+ private:
+ //
+ // In this case, allow the shallow-copy assignment and copy constructors.
+ // We don't want the default constructor, though.
+ //
+ SoundCollisionData();
+};
+
+
+#endif // SOUNDCOLLISIONDATA_H
+
diff --git a/game/code/sound/sounddebug/allsounddebug.cpp b/game/code/sound/sounddebug/allsounddebug.cpp
new file mode 100644
index 0000000..de95350
--- /dev/null
+++ b/game/code/sound/sounddebug/allsounddebug.cpp
@@ -0,0 +1,2 @@
+#include <sound/sounddebug/sounddebugdisplay.cpp>
+#include <sound/sounddebug/sounddebugpage.cpp>
diff --git a/game/code/sound/sounddebug/sounddebugdisplay.cpp b/game/code/sound/sounddebug/sounddebugdisplay.cpp
new file mode 100644
index 0000000..b31a7e9
--- /dev/null
+++ b/game/code/sound/sounddebug/sounddebugdisplay.cpp
@@ -0,0 +1,438 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddebugdisplay.cpp
+//
+// Description: Implement SoundDebugDisplay
+//
+// History: 10/26/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <pddi/pddi.hpp>
+#include <p3d/utility.hpp>
+
+#include <raddebugwatch.hpp>
+#include <radsound_hal.hpp>
+#include <radtypeinfo.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/sounddebug/sounddebugdisplay.h>
+
+#include <sound/sounddebug/sounddebugpage.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/playermanager.h>
+
+#include <render/IntersectManager/IntersectManager.h>
+#include <render/DSG/StaticPhysDSG.h>
+#include <render/DSG/DynaPhysDSG.h>
+#include <render/DSG/animcollisionentitydsg.h>
+#include <worldsim/avatarmanager.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+//
+// Watcher tunables
+//
+bool SoundDebugDisplay::s_isVisible = false;
+int SoundDebugDisplay::s_red = 255;
+int SoundDebugDisplay::s_green = 255;
+int SoundDebugDisplay::s_blue = 0;
+// Text position
+int SoundDebugDisplay::s_leftOffset = 0;
+int SoundDebugDisplay::s_topOffset = 0;
+// Displayed page
+unsigned int SoundDebugDisplay::s_page = 0;
+bool SoundDebugDisplay::s_dumpToWindow = false;
+// Name display radius
+float SoundDebugDisplay::s_radius = 2.0f;
+// Type info
+bool SoundDebugDisplay::s_dumpTypeInfoToWindow = false;
+
+static const int NUM_VISIBLE_LINES = 15;
+static const int NUM_ENTITIES = ( NUM_VISIBLE_LINES * SoundDebugDisplay::MAX_DEBUG_PAGES );
+
+static const int LEFT = 40;
+static const int TOP = 40;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundDebugDisplay::SoundDebugDisplay
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundDebugDisplay::SoundDebugDisplay( Sound::daSoundRenderingManager* soundMgr ) :
+ m_renderMgr( soundMgr )
+{
+ int i;
+ const char* sectionName = "Sound Info";
+
+ //
+ // Register the watcher variables
+ //
+ radDbgWatchAddBoolean( &s_isVisible, "Set Visibility", sectionName, 0, 0 );
+ radDbgWatchAddBoolean( &s_dumpToWindow, "Dump To Window", sectionName, 0, 0 );
+ radDbgWatchAddUnsignedInt( &s_page, "Select Page", sectionName, 0, 0, 0, MAX_DEBUG_PAGES - 1 );
+ radDbgWatchAddInt( &s_leftOffset, "Left Position", sectionName, 0, 0, -1000, 1000 );
+ radDbgWatchAddInt( &s_topOffset, "Top Position", sectionName, 0, 0, -1000, 1000 );
+ radDbgWatchAddInt( &s_red, "Text - Red", sectionName, 0, 0, 0, 255 );
+ radDbgWatchAddInt( &s_green, "Text - Green", sectionName, 0, 0, 0, 255 );
+ radDbgWatchAddInt( &s_blue, "Text - Blue", sectionName, 0, 0, 0, 255 );
+ radDbgWatchAddFloat( &s_radius, "Name Display Radius", sectionName, 0, 0, 1.0f, 10.0f );
+#ifdef RAD_DEBUG
+ // RadScript only provides this capability in debug
+ radDbgWatchAddBoolean( &s_dumpTypeInfoToWindow, "Dump Type Info To Window", sectionName );
+#endif
+
+ for( i = 0; i < MAX_DEBUG_PAGES; i++ )
+ {
+ m_debugPages[i] = NULL;
+ }
+}
+
+//==============================================================================
+// SoundDebugDisplay::~SoundDebugDisplay
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundDebugDisplay::~SoundDebugDisplay()
+{
+ radDbgWatchDelete( &s_isVisible );
+ radDbgWatchDelete( &s_dumpToWindow );
+ radDbgWatchDelete( &s_page );
+ radDbgWatchDelete( &s_leftOffset );
+ radDbgWatchDelete( &s_topOffset );
+ radDbgWatchDelete( &s_red );
+ radDbgWatchDelete( &s_green );
+ radDbgWatchDelete( &s_blue );
+ radDbgWatchDelete( &s_radius );
+#ifdef RAD_DEBUG
+ radDbgWatchDelete( &s_dumpTypeInfoToWindow );
+#endif
+}
+
+//=============================================================================
+// SoundDebugDisplay::RegisterPage
+//=============================================================================
+// Description: Register a debug page for display
+//
+// Parameters: page - page to register
+//
+// Return: void
+//
+//=============================================================================
+void SoundDebugDisplay::RegisterPage( SoundDebugPage* page )
+{
+ int i;
+
+ for( i = 0; i < MAX_DEBUG_PAGES; i++ )
+ {
+ if( m_debugPages[i] == NULL )
+ {
+ m_debugPages[i] = page;
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// SoundDebugDisplay::DeregisterPage
+//=============================================================================
+// Description: Deregister a debug page for display
+//
+// Parameters: page - page to deregister
+//
+// Return: void
+//
+//=============================================================================
+void SoundDebugDisplay::DeregisterPage( SoundDebugPage* page )
+{
+ int i;
+
+ for( i = 0; i < MAX_DEBUG_PAGES; i++ )
+ {
+ if( m_debugPages[i] == page )
+ {
+ m_debugPages[i] = NULL;
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// SoundDebugDisplay::Render
+//=============================================================================
+// Description: Draw the sound debug info
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundDebugDisplay::Render()
+{
+ if ( Sound::daSoundRenderingManager::GetInstance( ) )
+ {
+ Sound::daSoundRenderingManager::GetInstance( )->Render( );
+ }
+
+#ifndef RAD_RELEASE
+ Avatar* theAvatar;
+ rmt::Vector position;
+ rmt::Vector* positionPtr = NULL;
+ int i;
+ tColour stringColour;
+
+ if( s_dumpTypeInfoToWindow )
+ {
+ s_dumpTypeInfoToWindow = false;
+#ifdef RADSCRIPT_DEBUG
+ ::radTypeInfoSystemGet()->DebugDump();
+#endif
+ }
+
+ if( !s_isVisible )
+ {
+ return;
+ }
+
+ //
+ // The new, good way
+ //
+ if( s_page > 1 )
+ {
+ stringColour = tColour(s_red, s_green, s_blue);
+
+ for( i = 0; i < MAX_DEBUG_PAGES; i++ )
+ {
+ if( ( m_debugPages[i] != NULL )
+ && ( m_debugPages[i]->GetPage() == s_page ) )
+ {
+ m_debugPages[i]->Render( LEFT + s_leftOffset, TOP + s_topOffset,
+ stringColour, s_dumpToWindow );
+ break;
+ }
+ }
+ }
+ else
+ {
+ //
+ // The old, bad way
+ //
+
+ //
+ // Get the avatar position
+ //
+ theAvatar = GetAvatarManager()->GetAvatarForPlayer( 0 );
+ if( theAvatar != NULL )
+ {
+ //
+ // Presumably we're in game if we get here
+ //
+ theAvatar->GetPosition( position );
+ positionPtr = &position;
+ }
+
+ if( s_page == 0 )
+ {
+ renderPositionAndHeapInfo( positionPtr );
+ }
+ else
+ {
+ renderNearbyObjectNames( positionPtr );
+ }
+ }
+#endif
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+void SoundDebugDisplay::renderPositionAndHeapInfo( rmt::Vector* position )
+{
+#ifndef RAD_RELEASE
+ char buffy[128];
+ tColour stringColour = tColour(s_red, s_green, s_blue);
+ IRadSoundHalSystem::Stats radSoundStats;
+
+ //
+ // Display the avatar position
+ //
+ if( position != NULL )
+ {
+ sprintf( buffy, "Avatar posn: %f %f %f", position->x, position->y, position->z );
+ renderTextLine( buffy, LEFT, TOP, stringColour );
+ }
+
+ //
+ // Display the radSound memory stats
+ //
+ strcpy( buffy, "RadSound stats:" );
+ renderTextLine( buffy, LEFT, TOP + 20, stringColour );
+
+ ::radSoundHalSystemGet()->GetStats( &radSoundStats );
+ sprintf( buffy, "Buffers: %d Voices: %d/%d PosVoices: %d/%d",
+ radSoundStats.m_NumBuffers,
+ radSoundStats.m_NumVoicesPlaying,
+ radSoundStats.m_NumVoices,
+ radSoundStats.m_NumPosVoicesPlaying,
+ radSoundStats.m_NumPosVoices );
+ renderTextLine( buffy, LEFT, TOP + 40, stringColour );
+
+ sprintf( buffy, "Buffer memory used: %d Effects memory used: %d",
+ radSoundStats.m_BufferMemoryUsed,
+ radSoundStats.m_EffectsMemoryUsed );
+ renderTextLine( buffy, LEFT, TOP + 60, stringColour );
+
+ sprintf( buffy, "Sound memory free: %d",
+ radSoundStats.m_TotalFreeSoundMemory );
+ renderTextLine( buffy, LEFT, TOP + 80, stringColour );
+
+ sprintf( buffy, "Sound renderer stats:" );
+ renderTextLine( buffy, LEFT, TOP + 120, stringColour );
+
+ sprintf( buffy, "Clip players used: %d", m_renderMgr->GetPlayerManager()->GetNumUsedClipPlayers() );
+ renderTextLine( buffy, LEFT, TOP + 140, stringColour );
+
+ sprintf( buffy, "Stream players used: %d", m_renderMgr->GetPlayerManager()->GetNumUsedStreamPlayers() );
+ renderTextLine( buffy, LEFT, TOP + 160, stringColour );
+
+ s_dumpToWindow = false;
+#endif
+}
+
+void SoundDebugDisplay::renderNearbyObjectNames( rmt::Vector* position )
+{
+#ifndef RAD_RELEASE
+ char buffy[128];
+ tColour stringColour = tColour(s_red, s_green, s_blue);
+ const char* noSound = "NO SOUND";
+ ReserveArray<StaticPhysDSG*> statics;
+ ReserveArray<DynaPhysDSG*> dynamics;
+ ReserveArray<AnimCollisionEntityDSG*> animatics;
+ CollisionEntityDSG* collEntityArray[NUM_ENTITIES];
+ int arrayIndex = 0;
+ int i;
+
+ if( position == NULL )
+ {
+ //
+ // No character to find nearby objects for, draw nothing
+ //
+ return;
+ }
+
+ //
+ // Get the intersect goodness
+ //
+ GetIntersectManager()->FindStaticPhysElems( *position, s_radius, statics );
+ GetIntersectManager()->FindDynaPhysElems( *position, s_radius, dynamics );
+ GetIntersectManager()->FindAnimPhysElems( *position, s_radius, animatics );
+
+ //
+ // Populate the entity array. Simplifies the code slightly
+ // to do it this way. This is debug stuff, doesn't need to be
+ // pretty.
+ //
+ for( i = 0; i < statics.mUseSize; i++ )
+ {
+ if( arrayIndex >= NUM_ENTITIES )
+ {
+ break;
+ }
+ collEntityArray[arrayIndex] = statics[i];
+ ++arrayIndex;
+ }
+ for( i = 0; i < dynamics.mUseSize; i++ )
+ {
+ if( arrayIndex >= NUM_ENTITIES )
+ {
+ break;
+ }
+ collEntityArray[arrayIndex] = dynamics[i];
+ ++arrayIndex;
+ }
+ for( i = 0; i < animatics.mUseSize; i++ )
+ {
+ if( arrayIndex >= NUM_ENTITIES )
+ {
+ break;
+ }
+ collEntityArray[arrayIndex] = animatics[i];
+ ++arrayIndex;
+ }
+
+ //
+ // Fill the rest of the array with NULLs
+ //
+ for( i = arrayIndex; i < NUM_ENTITIES; i++ )
+ {
+ collEntityArray[i] = NULL;
+ }
+
+ int startIndex = (s_page - 1) * NUM_VISIBLE_LINES;
+ int endIndex = startIndex + NUM_VISIBLE_LINES;
+
+ for( i = startIndex; i < endIndex; ++i )
+ {
+
+ if( collEntityArray[i] == NULL )
+ {
+ break;
+ }
+
+ if( collEntityArray[i]->GetCollisionAttributes() == NULL )
+ {
+ sprintf( buffy, "%-32s\t%-32s", collEntityArray[i]->GetName(), noSound );
+ }
+ else
+ {
+ sprintf( buffy, "%-32s\t%-32s", collEntityArray[i]->GetName(),
+ collEntityArray[i]->GetCollisionAttributes()->GetSound() );
+ }
+
+ renderTextLine( buffy, LEFT, TOP + ((i % NUM_VISIBLE_LINES)*20), stringColour );
+ }
+
+ s_dumpToWindow = false;
+#endif
+}
+
+void SoundDebugDisplay::renderTextLine( const char* text, int leftPosn,
+ int topPosn, tColour& colour )
+{
+ p3d::pddi->DrawString( text, leftPosn + s_leftOffset, topPosn + s_topOffset, colour );
+
+ if ( s_dumpToWindow )
+ {
+ rDebugString( text );
+ }
+}
diff --git a/game/code/sound/sounddebug/sounddebugdisplay.h b/game/code/sound/sounddebug/sounddebugdisplay.h
new file mode 100644
index 0000000..170f5f1
--- /dev/null
+++ b/game/code/sound/sounddebug/sounddebugdisplay.h
@@ -0,0 +1,86 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddebugdisplay.h
+//
+// Description: Declaration for the SoundDebugDisplay class, used for
+// printing debugging/tuning information on screen
+//
+// History: 10/26/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDDEBUGDISPLAY_H
+#define SOUNDDEBUGDISPLAY_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radmath/radmath.hpp>
+
+//========================================
+// Forward References
+//========================================
+class SoundDebugPage;
+
+namespace Sound
+{
+ class daSoundRenderingManager;
+}
+
+
+//=============================================================================
+//
+// Synopsis: SoundDebugDisplay
+//
+//=============================================================================
+
+class SoundDebugDisplay
+{
+ public:
+ SoundDebugDisplay( Sound::daSoundRenderingManager* renderMgr );
+ virtual ~SoundDebugDisplay();
+
+ void Render();
+
+ void RegisterPage( SoundDebugPage* page );
+ void DeregisterPage( SoundDebugPage* page );
+
+ static const int MAX_DEBUG_PAGES = 5;
+
+ //
+ // Watcher tunables
+ //
+ static bool s_isVisible;
+ static int s_red;
+ static int s_green;
+ static int s_blue;
+ // Text position
+ static int s_leftOffset;
+ static int s_topOffset;
+ // Displayed page
+ static unsigned int s_page;
+ static bool s_dumpToWindow;
+ // Name display radius
+ static float s_radius;
+ // Type info
+ static bool s_dumpTypeInfoToWindow;
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundDebugDisplay( const SoundDebugDisplay& original );
+ SoundDebugDisplay& operator=( const SoundDebugDisplay& rhs );
+
+ void renderPositionAndHeapInfo( rmt::Vector* position );
+ void renderNearbyObjectNames( rmt::Vector* position );
+
+ void renderTextLine( const char* text, int leftPosn, int topPosn, tColour& colour );
+
+ SoundDebugPage* m_debugPages[MAX_DEBUG_PAGES];
+
+ Sound::daSoundRenderingManager* m_renderMgr;
+};
+
+
+#endif // SOUNDDEBUGDISPLAY_H
+
diff --git a/game/code/sound/sounddebug/sounddebugpage.cpp b/game/code/sound/sounddebug/sounddebugpage.cpp
new file mode 100644
index 0000000..70aee13
--- /dev/null
+++ b/game/code/sound/sounddebug/sounddebugpage.cpp
@@ -0,0 +1,161 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddebugpage.cpp
+//
+// Description: Implementation of SoundDebugPage class, which is used for
+// displaying a chunk of debug info in Watcher (or whatever
+// our display mechanism happens to be)
+//
+// History: 11/22/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <p3d/utility.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/sounddebug/sounddebugpage.h>
+
+#include <sound/sounddebug/sounddebugdisplay.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundDebugPage::SoundDebugPage
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundDebugPage::SoundDebugPage() :
+ m_pageNum( 0 ),
+ m_displayMaster( NULL )
+{
+ //
+ // Presumably, we're saving full initialization for later.
+ //
+
+#ifndef SOUND_DEBUG_INFO_ENABLED
+ //
+ // Don't want to build these in release, so make it die horribly.
+ //
+ rReleaseAssertMsg( false, "Oops, shouldn't be storing sound debug info in release" );
+#endif
+}
+
+//==============================================================================
+// SoundDebugPage::SoundDebugPage
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: pageNum - page we'll display info on in Watcher's SoundInfo.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundDebugPage::SoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master ) :
+m_pageNum( pageNum ),
+m_displayMaster( master )
+{
+#ifndef SOUND_DEBUG_INFO_ENABLED
+ //
+ // Don't want to build these in release, so make it die horribly.
+ //
+ rReleaseAssertMsg( false, "Oops, shouldn't be storing sound debug info in release" );
+#endif
+
+ //
+ // Tell debug display master about our existence
+ //
+ master->RegisterPage( this );
+}
+
+//==============================================================================
+// SoundDebugPage::~SoundDebugPage
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundDebugPage::~SoundDebugPage()
+{
+ m_displayMaster->DeregisterPage( this );
+}
+
+//=============================================================================
+// SoundDebugPage::LazyInitialization
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( unsigned int pageNum, SoundDebugDisplay* master )
+//
+// Return: void
+//
+//=============================================================================
+void SoundDebugPage::LazyInitialization( unsigned int pageNum, SoundDebugDisplay* master )
+{
+ m_pageNum = pageNum;
+ m_displayMaster = master;
+
+ m_displayMaster->RegisterPage( this );
+}
+
+//=============================================================================
+// SoundDebugPage::Render
+//=============================================================================
+// Description: Draw our debug info. This relies on subclasses providing the
+// info and telling us how many lines to draw
+//
+// Parameters: leftPosn - leftmost horizontal position to write text to
+// topPosn - topmost vertical position to write text to
+// colour - colour of pddi text to use
+// dumpToWindow - also write text as debug string if true
+//
+// Return: void
+//
+//=============================================================================
+void SoundDebugPage::Render( int leftPosn, int topPosn, tColour& colour, bool dumpToWindow )
+{
+ int i;
+ char lineBuffer[255];
+ int numLines = getNumLines();
+
+ for( i = 0; i < numLines; i++ )
+ {
+ fillLineBuffer( i, lineBuffer );
+
+ p3d::pddi->DrawString( lineBuffer, leftPosn, topPosn + (i * 20), colour );
+
+ if ( dumpToWindow )
+ {
+ rDebugString( lineBuffer );
+ }
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/sounddebug/sounddebugpage.h b/game/code/sound/sounddebug/sounddebugpage.h
new file mode 100644
index 0000000..088f14d
--- /dev/null
+++ b/game/code/sound/sounddebug/sounddebugpage.h
@@ -0,0 +1,67 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddebugpage.h
+//
+// Description: Declaration of SoundDebugPage class, which is used for displaying
+// a chunk of debug info in Watcher (or whatever our display
+// mechanism happens to be)
+//
+// History: 11/22/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDDEBUGPAGE_H
+#define SOUNDDEBUGPAGE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <p3d/p3dtypes.hpp>
+
+//========================================
+// Forward References
+//========================================
+class SoundDebugDisplay;
+
+#ifndef RAD_RELEASE
+#define SOUND_DEBUG_INFO_ENABLED
+#endif
+
+//=============================================================================
+//
+// Synopsis: SoundDebugPage
+//
+//=============================================================================
+
+class SoundDebugPage
+{
+ public:
+ SoundDebugPage();
+ SoundDebugPage( unsigned int pageNum, SoundDebugDisplay* master );
+ virtual ~SoundDebugPage();
+
+ void LazyInitialization( unsigned int pageNum, SoundDebugDisplay* master );
+
+ unsigned int GetPage() { return( m_pageNum ); }
+
+ void Render( int leftPosn, int topPosn, tColour& colour, bool dumpToWindow );
+
+ protected:
+
+ virtual void fillLineBuffer( int lineNum, char* buffer ) = 0;
+ virtual int getNumLines() = 0;
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundDebugPage( const SoundDebugPage& original );
+ SoundDebugPage& operator=( const SoundDebugPage& rhs );
+
+ unsigned int m_pageNum;
+
+ SoundDebugDisplay* m_displayMaster;
+};
+
+
+#endif // SOUNDDEBUGPAGE_H
+
diff --git a/game/code/sound/soundfx/allsoundfx.cpp b/game/code/sound/soundfx/allsoundfx.cpp
new file mode 100644
index 0000000..4ee5e0b
--- /dev/null
+++ b/game/code/sound/soundfx/allsoundfx.cpp
@@ -0,0 +1,14 @@
+#include <sound/soundfx/soundeffectplayer.cpp>
+#include <sound/soundfx/soundfxfrontendlogic.cpp>
+#include <sound/soundfx/soundfxgameplaylogic.cpp>
+#include <sound/soundfx/soundfxlogic.cpp>
+#include <sound/soundfx/soundfxpauselogic.cpp>
+#include <sound/soundfx/reverbcontroller.cpp>
+#include <sound/soundfx/reverbsettings.cpp>
+#include <sound/soundfx/positionalsoundsettings.cpp>
+
+#ifdef RAD_PS2
+#include <sound/soundfx/ps2reverbcontroller.cpp>
+#else
+#include <sound/soundfx/gcreverbcontroller.cpp>
+#endif \ No newline at end of file
diff --git a/game/code/sound/soundfx/gcreverbcontroller.cpp b/game/code/sound/soundfx/gcreverbcontroller.cpp
new file mode 100644
index 0000000..4b6336a
--- /dev/null
+++ b/game/code/sound/soundfx/gcreverbcontroller.cpp
@@ -0,0 +1,108 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: gcreverbcontroller.cpp
+//
+// Description: Implementation for the GCReverbController class, which provides
+// the GC-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radsound_gcn.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/gcreverbcontroller.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// GCReverbController::GCReverbController
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+GCReverbController::GCReverbController()
+{
+ m_reverbInterface = ::radSoundEffectStdReverbGcnCreate( GMA_PERSISTENT );
+
+ registerReverbEffect( m_reverbInterface );
+}
+
+//==============================================================================
+// GCReverbController::~GCReverbController
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+GCReverbController::~GCReverbController()
+{
+ m_reverbInterface->Release();
+ m_reverbInterface = NULL;
+}
+
+//=============================================================================
+// GCReverbController::SetReverbOn
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void GCReverbController::SetReverbOn( reverbSettings* settings )
+{
+ SetReverbGain( settings->GetGain() );
+ m_reverbInterface->SetPreDelay( settings->GetGCPreDelay() );
+ m_reverbInterface->SetReverbTime( settings->GetGCReverbTime() );
+ m_reverbInterface->SetColoration( settings->GetGCColoration() );
+ m_reverbInterface->SetDamping( settings->GetGCDamping() );
+}
+
+//=============================================================================
+// GCReverbController::SetReverbOff
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void GCReverbController::SetReverbOff()
+{
+ SetReverbGain( 0.0f );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundfx/gcreverbcontroller.h b/game/code/sound/soundfx/gcreverbcontroller.h
new file mode 100644
index 0000000..3e1e101
--- /dev/null
+++ b/game/code/sound/soundfx/gcreverbcontroller.h
@@ -0,0 +1,54 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: gcreverbcontroller.h
+//
+// Description: Declaration for the GCReverbController class, which provides
+// the GC-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef GCREVERBCONTROLLER_H
+#define GCREVERBCONTROLLER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/reverbcontroller.h>
+
+//========================================
+// Forward References
+//========================================
+struct IRadSoundEffectStdReverbGcn;
+
+//=============================================================================
+//
+// Synopsis: GCReverbController
+//
+//=============================================================================
+
+class GCReverbController : public ReverbController
+{
+ public:
+ GCReverbController();
+ virtual ~GCReverbController();
+
+ void SetReverbOn( reverbSettings* settings );
+ void SetReverbOff();
+
+ private:
+ //Prevent wasteful constructor creation.
+ GCReverbController( const GCReverbController& original );
+ GCReverbController& operator=( const GCReverbController& rhs );
+
+ //
+ // Radsound's GC reverb interface
+ //
+ IRadSoundEffectStdReverbGcn* m_reverbInterface;
+};
+
+
+#endif // GCREVERBCONTROLLER_H
+
diff --git a/game/code/sound/soundfx/ipositionalsoundsettings.h b/game/code/sound/soundfx/ipositionalsoundsettings.h
new file mode 100644
index 0000000..3989621
--- /dev/null
+++ b/game/code/sound/soundfx/ipositionalsoundsettings.h
@@ -0,0 +1,59 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: ipositionalsoundsettings.h
+//
+// Description: RadScript interface for positional sound settings
+//
+// History: 12/20/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef IPOSITIONALSOUNDSETTINGS_H
+#define IPOSITIONALSOUNDSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: IPositionalSoundSettings
+//
+//=============================================================================
+
+class IPositionalSoundSettings : public IRefCount
+{
+ //
+ // Name of sound resource to play
+ //
+ virtual void SetClipName( const char* clipName ) = 0;
+
+ //
+ // Distance at which volume is maxed
+ //
+ virtual void SetMinDistance( float min ) = 0;
+
+ //
+ // Distance at which volume reaches zero
+ //
+ virtual void SetMaxDistance( float max ) = 0;
+
+ //
+ // Probability of sound playing
+ //
+ virtual void SetPlaybackProbability( float prob ) = 0;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //IPOSITIONALSOUNDSETTINGS_H
diff --git a/game/code/sound/soundfx/ireverbsettings.h b/game/code/sound/soundfx/ireverbsettings.h
new file mode 100644
index 0000000..c1288f3
--- /dev/null
+++ b/game/code/sound/soundfx/ireverbsettings.h
@@ -0,0 +1,73 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: ireverbsettings.h
+//
+// Description: Declaration for IReverbSettings class, which is the interface
+// visible in RadTuner for creating and storing a set of reverb
+// parameters.
+//
+// History: 11/3/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef IREVERBSETTINGS_H
+#define IREVERBSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: IReverbSettings
+//
+//=============================================================================
+
+struct IReverbSettings : public IRefCount
+{
+ virtual void SetGain( float gain ) = 0;
+ virtual void SetFadeInTime( float milliseconds ) = 0;
+ virtual void SetFadeOutTime( float milliseconds ) = 0;
+
+ //
+ // See radsound_<platform name>.hpp for details on this stuff
+ //
+ virtual void SetXboxRoom( int mBvalue ) = 0;
+ virtual void SetXboxRoomHF( int mBvalue ) = 0;
+ virtual void SetXboxRoomRolloffFactor( float value ) = 0;
+ virtual void SetXboxDecayTime( float value ) = 0;
+ virtual void SetXboxDecayHFRatio( float value ) = 0;
+ virtual void SetXboxReflections( int mBvalue ) = 0;
+ virtual void SetXboxReflectionsDelay( float value ) = 0;
+ virtual void SetXboxReverb( int mBvalue ) = 0;
+ virtual void SetXboxReverbDelay( float value ) = 0;
+ virtual void SetXboxDiffusion( float value ) = 0;
+ virtual void SetXboxDensity( float value ) = 0;
+ virtual void SetXboxHFReference( float value ) = 0;
+
+ // No RadTuner interface for enumerations as far as I know, so
+ // we'll have to cast whatever integer we get here
+ virtual void SetPS2ReverbMode( int mode ) = 0;
+
+ virtual void SetPS2Delay( float delayTime ) = 0;
+ virtual void SetPS2Feedback( float feedback ) = 0;
+
+ virtual void SetGCPreDelay( float milliseconds ) = 0;
+ virtual void SetGCReverbTime( float milliseconds ) = 0;
+ virtual void SetGCColoration( float coloration ) = 0;
+ virtual void SetGCDamping( float damping ) = 0;
+
+ // Must be defined for all platforms cause of the script.
+ virtual void SetWinEnvironmentDiffusion( float diffusion ) = 0;
+ virtual void SetWinAirAbsorptionHF( float value ) = 0;
+};
+
+
+#endif // IREVERBSETTINGS_H
+
diff --git a/game/code/sound/soundfx/positionalsoundsettings.cpp b/game/code/sound/soundfx/positionalsoundsettings.cpp
new file mode 100644
index 0000000..670bf9b
--- /dev/null
+++ b/game/code/sound/soundfx/positionalsoundsettings.cpp
@@ -0,0 +1,180 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: positionalsoundsettings.cpp
+//
+// Description: Implement positionalSoundSettings
+//
+// History: 12/20/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <string.h>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/positionalsoundsettings.h>
+
+#include <memory/srrmemory.h>
+
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//
+// Initialially the list is empty
+//
+positionalSoundSettings* radLinkedClass< positionalSoundSettings >::s_pLinkedClassHead = NULL;
+positionalSoundSettings* radLinkedClass< positionalSoundSettings >::s_pLinkedClassTail = NULL;
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// positionalSoundSettings::positionalSoundSettings
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+positionalSoundSettings::positionalSoundSettings() :
+ radRefCount( 0 ),
+ m_clipName( NULL ),
+ m_minDist( 10.0f ),
+ m_maxDist( 100.0f ),
+ m_playProbability( 1.0f )
+{
+}
+
+//=============================================================================
+// positionalSoundSettings::~positionalSoundSettings
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+positionalSoundSettings::~positionalSoundSettings()
+{
+ delete m_clipName;
+}
+
+//=============================================================================
+// positionalSoundSettings::SetClipName
+//=============================================================================
+// Description: Set name of the sound resource to be played at this position
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void positionalSoundSettings::SetClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ m_clipName = new(GMA_PERSISTENT) char[strlen(clipName)+1];
+ strcpy( m_clipName, clipName );
+}
+
+//=============================================================================
+// positionalSoundSettings::SetMinDistance
+//=============================================================================
+// Description: Set distance at which volume is maxed (kinda counterintuitive,
+// but that seems to be the convention)
+//
+// Parameters: min - distance to set
+//
+// Return: void
+//
+//=============================================================================
+void positionalSoundSettings::SetMinDistance( float min )
+{
+ rAssert( min >= 0.0f );
+
+ m_minDist = min;
+}
+
+//=============================================================================
+// positionalSoundSettings::SetMaxDistance
+//=============================================================================
+// Description: Set the distance at which the volume reaches zero
+//
+// Parameters: max - distance to set
+//
+// Return: void
+//
+//=============================================================================
+void positionalSoundSettings::SetMaxDistance( float max )
+{
+ rAssert( max >= 0.0f );
+
+ m_maxDist = max;
+}
+
+//=============================================================================
+// positionalSoundSettings::SetPlaybackProbability
+//=============================================================================
+// Description: Set probability that sound will be played when we enter
+// the trigger volume
+//
+// Parameters: prob - probability on scale of 0.0 to 1.0
+//
+// Return: void
+//
+//=============================================================================
+void positionalSoundSettings::SetPlaybackProbability( float prob )
+{
+ rAssert( prob >= 0.0f );
+ rAssert( prob <= 1.0f );
+
+ m_playProbability = prob;
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
+
+//******************************************************************************
+// Factory functions
+//******************************************************************************
+
+//==============================================================================
+// PositionalSettingsObjCreate
+//==============================================================================
+// Description: Factory function for creating positionalSoundSettings objects.
+// Called by RadScript.
+//
+// Parameters: ppParametersObj - Address of ptr to new object
+// allocator - FTT pool to allocate object within
+//
+// Return: N/A.
+//
+//==============================================================================
+void PositionalSettingsObjCreate
+(
+ IPositionalSoundSettings** ppParametersObj,
+ radMemoryAllocator allocator
+)
+{
+ rAssert( ppParametersObj != NULL );
+ (*ppParametersObj) = new ( allocator ) positionalSoundSettings( );
+ (*ppParametersObj)->AddRef( );
+}
diff --git a/game/code/sound/soundfx/positionalsoundsettings.h b/game/code/sound/soundfx/positionalsoundsettings.h
new file mode 100644
index 0000000..8174598
--- /dev/null
+++ b/game/code/sound/soundfx/positionalsoundsettings.h
@@ -0,0 +1,80 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: positionalsoundsettings.h
+//
+// Description: Declaration of object encapsulating positional sound settings
+//
+// History: 12/20/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef POSITIONALSOUNDSETTINGS_H
+#define POSITIONALSOUNDSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radlinkedclass.hpp>
+
+#include <sound/soundfx/ipositionalsoundsettings.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: positionalSoundSettings
+//
+//=============================================================================
+
+class positionalSoundSettings: public IPositionalSoundSettings,
+ public radLinkedClass< positionalSoundSettings >,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "positionalSoundSettings" );
+ positionalSoundSettings();
+ virtual ~positionalSoundSettings();
+
+ void SetClipName( const char* clipName );
+ const char* GetClipName() { return( m_clipName ); }
+
+ void SetMinDistance( float min );
+ float GetMinDistance() { return( m_minDist ); }
+
+ void SetMaxDistance( float max );
+ float GetMaxDistance() { return( m_maxDist ); }
+
+ void SetPlaybackProbability( float prob );
+ float GetPlaybackProbability() { return( m_playProbability ); }
+
+ private:
+ //Prevent wasteful constructor creation.
+ positionalSoundSettings( const positionalSoundSettings& positionalsoundsettings );
+ positionalSoundSettings& operator=( const positionalSoundSettings& positionalsoundsettings );
+
+ //
+ // Settings
+ //
+ char* m_clipName;
+ float m_minDist;
+ float m_maxDist;
+ float m_playProbability;
+};
+
+//=============================================================================
+// Factory Functions
+//=============================================================================
+
+//
+// Create a positionalSoundSettings object
+//
+void PositionalSettingsObjCreate
+(
+ IPositionalSoundSettings** ppSettings,
+ radMemoryAllocator allocator
+);
+
+#endif //POSITIONALSOUNDSETTINGS_H
diff --git a/game/code/sound/soundfx/ps2reverbcontroller.cpp b/game/code/sound/soundfx/ps2reverbcontroller.cpp
new file mode 100644
index 0000000..cf88160
--- /dev/null
+++ b/game/code/sound/soundfx/ps2reverbcontroller.cpp
@@ -0,0 +1,124 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: ps2reverbcontroller.cpp
+//
+// Description: Implementation for the PS2ReverbController class, which provides
+// the PS2-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radsound_ps2.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/ps2reverbcontroller.h>
+
+#include <sound/soundfx/reverbsettings.h>
+
+#include <memory/srrmemory.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// PS2ReverbController::PS2ReverbController
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+PS2ReverbController::PS2ReverbController()
+{
+ m_reverbInterface = ::radSoundCreateEffectPs2( GMA_PERSISTENT );
+
+ //
+ // Wheee!!!!
+ //
+ m_reverbInterface->SetMode( IRadSoundEffectPs2::Off );
+
+ registerReverbEffect( m_reverbInterface );
+}
+
+//==============================================================================
+// PS2ReverbController::~PS2ReverbController
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+PS2ReverbController::~PS2ReverbController()
+{
+ m_reverbInterface->Release();
+ m_reverbInterface = NULL;
+}
+
+//=============================================================================
+// PS2ReverbController::SetReverbOn
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void PS2ReverbController::SetReverbOn( reverbSettings* settings )
+{
+ if( settings != NULL )
+ {
+ m_reverbInterface->SetMode( static_cast<IRadSoundEffectPs2::Mode>(settings->GetPS2ReverbMode()) );
+ m_reverbInterface->SetGain( settings->GetGain() );
+ m_reverbInterface->SetDelay( settings->GetPS2Delay() );
+ m_reverbInterface->SetFeedback( settings->GetPS2Feedback() );
+
+ prepareFadeSettings( settings->GetGain(), settings->GetFadeInTime(),
+ settings->GetFadeOutTime() );
+ }
+ else
+ {
+ rReleaseString( "Settings is NULL\n" );
+ }
+}
+
+//=============================================================================
+// PS2ReverbController::SetReverbOff
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void PS2ReverbController::SetReverbOff()
+{
+ startFadeOut();
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundfx/ps2reverbcontroller.h b/game/code/sound/soundfx/ps2reverbcontroller.h
new file mode 100644
index 0000000..d756bc2
--- /dev/null
+++ b/game/code/sound/soundfx/ps2reverbcontroller.h
@@ -0,0 +1,54 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: ps2reverbcontroller.h
+//
+// Description: Declaration for the PS2ReverbController class, which provides
+// the PS2-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef PS2REVERBCONTROLLER_H
+#define PS2REVERBCONTROLLER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/reverbcontroller.h>
+
+//========================================
+// Forward References
+//========================================
+struct IRadSoundEffectPs2;
+
+//=============================================================================
+//
+// Synopsis: PS2ReverbController
+//
+//=============================================================================
+
+class PS2ReverbController : public ReverbController
+{
+ public:
+ PS2ReverbController();
+ virtual ~PS2ReverbController();
+
+ void SetReverbOn( reverbSettings* settings );
+ void SetReverbOff();
+
+ private:
+ //Prevent wasteful constructor creation.
+ PS2ReverbController( const PS2ReverbController& original );
+ PS2ReverbController& operator=( const PS2ReverbController& rhs );
+
+ //
+ // Radsound's PS2 reverb interface
+ //
+ IRadSoundEffectPs2* m_reverbInterface;
+};
+
+
+#endif // PS2REVERBCONTROLLER_H
+
diff --git a/game/code/sound/soundfx/reverbcontroller.cpp b/game/code/sound/soundfx/reverbcontroller.cpp
new file mode 100644
index 0000000..672d542
--- /dev/null
+++ b/game/code/sound/soundfx/reverbcontroller.cpp
@@ -0,0 +1,410 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: reverbcontroller.cpp
+//
+// Description: Implementation for ReverbController, which turns reverb on
+// and off and sets control values.
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radsound_hal.hpp>
+#include <radnamespace.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/reverbcontroller.h>
+
+#include <sound/soundfx/reverbsettings.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <events/eventmanager.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// ReverbController::ReverbController
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+ReverbController::ReverbController() :
+ m_targetGain( 0.0f ),
+ m_currentGain( 0.0f ),
+ m_fadeInMultiplier( 1.0f ),
+ m_fadeOutMultiplier( 1.0f ),
+ m_lastReverb( NULL ),
+ m_queuedReverb( NULL )
+{
+ unsigned int event;
+ EventManager* eventMgr = GetEventManager();
+
+ rAssert( eventMgr != NULL );
+
+ //
+ // Register all of the ambience events
+ //
+ for( event = EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_CITY;
+ event < EVENT_LOCATOR + LocatorEvent::PARKED_BIRDS;
+ ++event )
+ {
+ eventMgr->AddListener( this, static_cast<EventEnum>(event) );
+ }
+ eventMgr->AddListener(this, EVENT_MISSION_RESET);
+ eventMgr->AddListener(this, EVENT_MISSION_CHARACTER_RESET);
+
+ // bmc -- add registering of extra ambient sound events (placeholder and otherwise)
+ for( event = EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_COUNTRY_NIGHT;
+ event <= EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER9;
+ ++event )
+ {
+ eventMgr->AddListener( this, static_cast<EventEnum>(event) );
+ }
+
+ for( event = EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_SEASIDE_NIGHT;
+ event <= EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PLACEHOLDER16;
+ ++event )
+ {
+ eventMgr->AddListener( this, static_cast<EventEnum>(event) );
+ }
+ // bmc
+
+
+}
+
+//==============================================================================
+// ReverbController::~ReverbController
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+ReverbController::~ReverbController()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// ReverbController::SetReverbGain
+//=============================================================================
+// Description: Set the gain on the entire reverb system
+//
+// Parameters: gain - 0 to 1 gain value
+//
+// Return: None
+//
+//=============================================================================
+void ReverbController::SetReverbGain( float gain )
+{
+ ::radSoundHalSystemGet()->SetAuxGain( REVERB_AUX_EFFECT_NUMBER, gain );
+}
+
+//=============================================================================
+// ReverbController::HandleEvent
+//=============================================================================
+// Description: Listen for events that will cause us to switch reverb modes
+// on and off
+//
+// Parameters: id - event ID
+// pEventData - user data, unused
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::HandleEvent( EventEnum id, void* pEventData )
+{
+ reverbSettings* settingsObj = NULL;
+ reverbSettings* oldSettings = m_lastReverb;
+
+ switch( id )
+ {
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_ROOM_1:
+ settingsObj = getReverbSettings( "pproom1" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_ROOM_2:
+ settingsObj = getReverbSettings( "pproom2" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_ROOM_3:
+ settingsObj = getReverbSettings( "pproom3" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_TUNNEL_1:
+ settingsObj = getReverbSettings( "PP_tunnel_01" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_PP_TUNNEL_2:
+ settingsObj = getReverbSettings( "PP_tunnel_02" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_BURNS_TUNNEL:
+ settingsObj = getReverbSettings( "burns_tunnel" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_MANSION_INTERIOR:
+ settingsObj = getReverbSettings( "mansion_interior" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_SEWERS:
+ settingsObj = getReverbSettings( "sewers" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_STONE_CUTTER_TUNNEL:
+ settingsObj = getReverbSettings( "stonecuttertunnel" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_STONE_CUTTER_HALL:
+ settingsObj = getReverbSettings( "stonecutterhall" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_STADIUM_TUNNEL:
+ settingsObj = getReverbSettings( "stadiumtunnel" );
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::AMBIENT_SOUND_KRUSTYLU_EXTERIOR:
+ settingsObj = getReverbSettings( "krustylu" );
+ break;
+
+ default:
+ //
+ // This should be triggered by any ambient sound trigger that
+ // isn't mapped to reverb above
+ //
+ SetReverbOff();
+ m_lastReverb = NULL;
+ break;
+ }
+
+ if( settingsObj != NULL )
+ {
+ //
+ // No sense in switching to something we're already doing. That only
+ // seems to lead to unnecessary clicks on PS2 anyway.
+ //
+ if( settingsObj != oldSettings )
+ {
+ if( m_currentGain > 0.0f )
+ {
+ //
+ // We can't do a sudden switch without hearing popping. Queue up this
+ // switch to occur after we fade out
+ //
+ prepareFadeSettings( 0.0f, settingsObj->GetFadeInTime(), settingsObj->GetFadeOutTime() );
+ m_queuedReverb = m_lastReverb;
+ }
+ else
+ {
+ SetReverbOn( settingsObj );
+ }
+ }
+ }
+}
+
+//=============================================================================
+// ReverbController::ServiceOncePerFrame
+//=============================================================================
+// Description: Handle the fading in and fading out of reverb
+//
+// Parameters: elapsedTime - elapsed time since last update
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::ServiceOncePerFrame( unsigned int elapsedTime )
+{
+ if( m_currentGain == m_targetGain )
+ {
+ if( ( m_targetGain == 0.0f )
+ && ( m_queuedReverb != NULL ) )
+ {
+ //
+ // We're done fading out, now we can make the switch and fade
+ // back in
+ //
+ SetReverbOn( m_queuedReverb );
+ m_queuedReverb = NULL;
+ }
+
+ return;
+ }
+ else if( m_currentGain < m_targetGain )
+ {
+ m_currentGain += ( elapsedTime * m_fadeInMultiplier );
+ if( m_currentGain > m_targetGain )
+ {
+ m_currentGain = m_targetGain;
+ }
+ }
+ else
+ {
+ m_currentGain -= ( elapsedTime * m_fadeOutMultiplier );
+ if( m_currentGain < m_targetGain )
+ {
+ m_currentGain = m_targetGain;
+ }
+ }
+
+ SetReverbGain( m_currentGain );
+}
+
+//=============================================================================
+// ReverbController::PauseReverb
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::PauseReverb()
+{
+ if( m_lastReverb != NULL )
+ {
+ SetReverbOff();
+ }
+}
+
+//=============================================================================
+// ReverbController::UnpauseReverb
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::UnpauseReverb()
+{
+ if( m_lastReverb != NULL )
+ {
+ SetReverbOn( m_lastReverb );
+ }
+}
+
+//******************************************************************************
+//
+// Protected Member Functions
+//
+//******************************************************************************
+
+void ReverbController::registerReverbEffect( IRadSoundHalEffect* reverbEffect )
+{
+ ::radSoundHalSystemGet()->SetAuxEffect( REVERB_AUX_EFFECT_NUMBER, reverbEffect );
+ ::radSoundHalSystemGet()->SetAuxGain( REVERB_AUX_EFFECT_NUMBER, 0.0f );
+
+ Sound::daSoundRenderingManagerGet()->GetTheListener()->SetEnvironmentAuxSend( REVERB_AUX_EFFECT_NUMBER );
+ Sound::daSoundRenderingManagerGet()->GetTheListener()->SetEnvEffectsEnabled( true );
+}
+
+//=============================================================================
+// ReverbController::prepareFadeSettings
+//=============================================================================
+// Description: Set up the member values for fading reverb in and out
+//
+// Parameters: targetGain - gain value to gradually move to
+// fadeInTime - time in seconds for the fade, assuming we're
+// going from 0.0 to 1.0
+// fadeOutTime - similar to fadeInTime
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::prepareFadeSettings( float targetGain, float fadeInTime, float fadeOutTime )
+{
+ m_targetGain = targetGain;
+
+ m_fadeInMultiplier = fadeInTime;
+ if( m_fadeInMultiplier == 0.0f )
+ {
+ m_fadeInMultiplier = 1.0f;
+ }
+ else
+ {
+ m_fadeInMultiplier = 1.0f / m_fadeInMultiplier;
+ }
+ m_fadeOutMultiplier = fadeOutTime;
+ if( m_fadeOutMultiplier == 0.0f )
+ {
+ m_fadeOutMultiplier = 1.0f;
+ }
+ else
+ {
+ m_fadeOutMultiplier = 1.0f / m_fadeInMultiplier;
+ }
+}
+
+//=============================================================================
+// ReverbController::startFadeOut
+//=============================================================================
+// Description: Set up for the gradual reverb fadeout
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void ReverbController::startFadeOut()
+{
+ m_targetGain = 0.0f;
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// ReverbController::getReverbSettings
+//=============================================================================
+// Description: Retrieve the object containing a group of reverb settings
+//
+// Parameters: objName - name of reverbSettings object to find
+//
+// Return: void
+//
+//=============================================================================
+reverbSettings* ReverbController::getReverbSettings( const char* objName )
+{
+ IRadNameSpace* nameSpace;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ if ( objName != NULL )
+ {
+ rTunePrintf( "\n\nAUDIO: Reverb Settings: [%s]\n\n\n", objName );
+ }
+
+ m_lastReverb = static_cast<reverbSettings*>(nameSpace->GetInstance( objName ));
+
+ return( m_lastReverb );
+} \ No newline at end of file
diff --git a/game/code/sound/soundfx/reverbcontroller.h b/game/code/sound/soundfx/reverbcontroller.h
new file mode 100644
index 0000000..d3bc037
--- /dev/null
+++ b/game/code/sound/soundfx/reverbcontroller.h
@@ -0,0 +1,83 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: reverbcontroller.h
+//
+// Description: Declaration for the ReverbController class, which turns reverb
+// on and off and applies the required control values.
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef REVERBCONTROLLER_H
+#define REVERBCONTROLLER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+struct IRadSoundHalEffect;
+class reverbSettings;
+
+//=============================================================================
+//
+// Synopsis: ReverbController
+//
+//=============================================================================
+
+class ReverbController : public EventListener
+{
+ public:
+ ReverbController();
+ virtual ~ReverbController();
+
+ void SetReverbGain( float gain );
+
+ virtual void SetReverbOn( reverbSettings* settings ) = 0;
+ virtual void SetReverbOff() = 0;
+
+ virtual void PauseReverb();
+ virtual void UnpauseReverb();
+
+ //
+ // EventListener interface
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ void ServiceOncePerFrame( unsigned int elapsedTime );
+
+ protected:
+ static const int REVERB_AUX_EFFECT_NUMBER = 0;
+
+ void registerReverbEffect( IRadSoundHalEffect* reverbEffect );
+ void prepareFadeSettings( float targetGain, float fadeInTime, float fadeOutTime );
+ void startFadeOut();
+
+ private:
+ //Prevent wasteful constructor creation.
+ ReverbController( const ReverbController& original );
+ ReverbController& operator=( const ReverbController& rhs );
+
+ reverbSettings* getReverbSettings( const char* objName );
+
+ //
+ // Used for gradual changes in reverb
+ //
+ float m_targetGain;
+ float m_currentGain;
+ float m_fadeInMultiplier;
+ float m_fadeOutMultiplier;
+
+ reverbSettings* m_lastReverb;
+ reverbSettings* m_queuedReverb;
+};
+
+
+#endif // REVERBCONTROLLER_H
+
diff --git a/game/code/sound/soundfx/reverbsettings.cpp b/game/code/sound/soundfx/reverbsettings.cpp
new file mode 100644
index 0000000..d44c200
--- /dev/null
+++ b/game/code/sound/soundfx/reverbsettings.cpp
@@ -0,0 +1,133 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: reverbsettings.cpp
+//
+// Description: Definition for the reverbSettings class, which stores sets
+// of reverb parameters to be applied whenever we want that
+// reverby sound thing happening. NOTE: lower-case "r" needed
+// to make RadScript happy.
+//
+// History: 11/5/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/reverbsettings.h>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Initialially the list is empty
+//
+reverbSettings* radLinkedClass< reverbSettings >::s_pLinkedClassHead = NULL;
+reverbSettings* radLinkedClass< reverbSettings >::s_pLinkedClassTail = NULL;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// reverbSettings::reverbSettings
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+reverbSettings::reverbSettings() :
+ radRefCount( 0 ),
+
+ m_gain( 0.0f ),
+ m_fadeInTime( 0.0f ),
+ m_fadeOutTime( 0.0f ),
+
+ m_xboxRoom( 0 ),
+ m_xboxRoomHF( 0 ),
+ m_xboxRoomRolloff( 0.0f ),
+ m_xboxDecay( 0.0f ),
+ m_xboxDecayHFRatio( 0.0f ),
+ m_xboxReflections( 0 ),
+ m_xboxReflectionsDelay( 0.0f ),
+ m_xboxReverb( 0 ),
+ m_xboxReverbDelay( 0.0f ),
+ m_xboxDiffusion( 0.0f ),
+ m_xboxDensity( 0.0f ),
+ m_xboxHFReference( 0.0f ),
+
+ m_ps2ReverbMode( 0 ),
+ m_ps2Delay( 0.0f ),
+ m_ps2Feedback( 0.0f ),
+
+ m_gcPreDelay( 0.0f ),
+ m_gcReverbTime( 0.0f ),
+ m_gcColoration( 0.0f ),
+ m_gcDamping( 0.0f ),
+
+ m_winEnvironmentDiffusion( 1.0f ),
+ m_winAirAbsorptionHF( -5.0f )
+{
+}
+
+//==============================================================================
+// reverbSettings::~reverbSettings
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+reverbSettings::~reverbSettings()
+{
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//******************************************************************************
+// Factory functions
+//******************************************************************************
+
+//==============================================================================
+// ReverbSettingsObjCreate
+//==============================================================================
+// Description: Factory function for creating reverbSettings objects.
+// Called by RadScript.
+//
+// Parameters: ppSettings - Address of ptr to new object
+// allocator - FTT pool to allocate object within
+//
+// Return: N/A.
+//
+//==============================================================================
+void ReverbSettingsObjCreate
+(
+ IReverbSettings** ppSettings,
+ radMemoryAllocator allocator
+)
+{
+ rAssert( ppSettings != NULL );
+ (*ppSettings) = new ( allocator ) reverbSettings( );
+ (*ppSettings)->AddRef( );
+}
+
diff --git a/game/code/sound/soundfx/reverbsettings.h b/game/code/sound/soundfx/reverbsettings.h
new file mode 100644
index 0000000..8ea3bbe
--- /dev/null
+++ b/game/code/sound/soundfx/reverbsettings.h
@@ -0,0 +1,158 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: reverbsettings.h
+//
+// Description: Declaration for the reverbSettings class, which stores sets
+// of reverb parameters to be applied whenever we want that
+// reverby sound thing happening. NOTE: lower-case "r" needed
+// to make RadScript happy.
+//
+// History: 11/5/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef REVERBSETTINGS_H
+#define REVERBSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/soundfx/ireverbsettings.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: reverbSettings
+//
+//=============================================================================
+
+class reverbSettings : public IReverbSettings,
+ public radLinkedClass< reverbSettings >,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "reverbSettings" );
+
+ reverbSettings();
+ virtual ~reverbSettings();
+
+ void SetGain( float gain ) { m_gain = gain; }
+ float GetGain() { return( m_gain ); }
+ void SetFadeInTime( float milliseconds ) { m_fadeInTime = milliseconds; }
+ float GetFadeInTime() { return( m_fadeInTime ); }
+ void SetFadeOutTime( float milliseconds ) { m_fadeOutTime = milliseconds; }
+ float GetFadeOutTime() { return( m_fadeOutTime ); }
+
+ //
+ // See radsound_<platform name>.hpp for details on this stuff
+ //
+ void SetXboxRoom( int mBvalue ) { m_xboxRoom = mBvalue; }
+ int GetXboxRoom() { return( m_xboxRoom ); }
+ void SetXboxRoomHF( int mBvalue ) { m_xboxRoomHF = mBvalue; }
+ int GetXboxRoomHF() { return( m_xboxRoomHF ); }
+ void SetXboxRoomRolloffFactor( float value ) { m_xboxRoomRolloff = value; }
+ float GetXboxRoomRolloffFactor() { return( m_xboxRoomRolloff ); }
+ void SetXboxDecayTime( float value ) { m_xboxDecay = value; }
+ float GetXboxDecayTime() { return( m_xboxDecay ); }
+ void SetXboxDecayHFRatio( float value ) { m_xboxDecayHFRatio = value; }
+ float GetXboxDecayHFRatio() { return( m_xboxDecayHFRatio ); }
+ void SetXboxReflections( int mBvalue ) { m_xboxReflections = mBvalue; }
+ int GetXboxReflections() { return( m_xboxReflections ); }
+ void SetXboxReflectionsDelay( float value ) { m_xboxReflectionsDelay = value; }
+ float GetXboxReflectionsDelay() { return( m_xboxReflectionsDelay ); }
+ void SetXboxReverb( int mBvalue ) { m_xboxReverb = mBvalue; }
+ int GetXboxReverb() { return( m_xboxReverb ); }
+ void SetXboxReverbDelay( float value ) { m_xboxReverbDelay = value; }
+ float GetXboxReverbDelay() { return( m_xboxReverbDelay ); }
+ void SetXboxDiffusion( float value ) { m_xboxDiffusion = value; }
+ float GetXboxDiffusion() { return( m_xboxDiffusion ); }
+ void SetXboxDensity( float value ) { m_xboxDensity = value; }
+ float GetXboxDensity() { return( m_xboxDensity ); }
+ void SetXboxHFReference( float value ) { m_xboxHFReference = value; }
+ float GetXboxHFReference() { return( m_xboxHFReference ); }
+
+ // No RadTuner interface for enumerations as far as I know, so
+ // we'll have to cast whatever integer we get here
+ void SetPS2ReverbMode( int mode ) { m_ps2ReverbMode = mode; }
+ int GetPS2ReverbMode() { return( m_ps2ReverbMode ); }
+
+ void SetPS2Delay( float delayTime ) { m_ps2Delay = delayTime; }
+ float GetPS2Delay() { return( m_ps2Delay ); }
+ void SetPS2Feedback( float feedback ) { m_ps2Feedback = feedback; }
+ float GetPS2Feedback() { return( m_ps2Feedback ); }
+
+ void SetGCPreDelay( float milliseconds ) { m_gcPreDelay = milliseconds; }
+ float GetGCPreDelay() { return( m_gcPreDelay ); }
+ void SetGCReverbTime( float milliseconds ) { m_gcReverbTime = milliseconds; }
+ float GetGCReverbTime() { return( m_gcReverbTime ); }
+ void SetGCColoration( float coloration ) { m_gcColoration = coloration; }
+ float GetGCColoration() { return( m_gcColoration ); }
+ void SetGCDamping( float damping ) { m_gcDamping = damping; }
+ float GetGCDamping() { return( m_gcDamping ); }
+
+ // Must be defined for all platforms cause of the script.
+ void SetWinEnvironmentDiffusion( float diffusion ) { m_winEnvironmentDiffusion = diffusion; }
+ float GetWinEnvironmentDiffusion() const { return m_winEnvironmentDiffusion; }
+ void SetWinAirAbsorptionHF( float value ) { m_winAirAbsorptionHF = value; }
+ float GetWinAirAbsorptionHF() const { return m_winAirAbsorptionHF; }
+
+ private:
+ //Prevent wasteful constructor creation.
+ reverbSettings( const reverbSettings& original );
+ reverbSettings& operator=( const reverbSettings& rhs );
+
+ //
+ // Reverb parameters
+ //
+ float m_gain;
+ float m_fadeInTime;
+ float m_fadeOutTime;
+
+ int m_xboxRoom;
+ int m_xboxRoomHF;
+ float m_xboxRoomRolloff;
+ float m_xboxDecay;
+ float m_xboxDecayHFRatio;
+ int m_xboxReflections;
+ float m_xboxReflectionsDelay;
+ int m_xboxReverb;
+ float m_xboxReverbDelay;
+ float m_xboxDiffusion;
+ float m_xboxDensity;
+ float m_xboxHFReference;
+
+ int m_ps2ReverbMode;
+ float m_ps2Delay;
+ float m_ps2Feedback;
+
+ float m_gcPreDelay;
+ float m_gcReverbTime;
+ float m_gcColoration;
+ float m_gcDamping;
+
+ float m_winEnvironmentDiffusion;
+ float m_winAirAbsorptionHF;
+};
+
+//=============================================================================
+// Factory Functions
+//=============================================================================
+
+//
+// Create a reverbSettings object
+//
+void ReverbSettingsObjCreate
+(
+ IReverbSettings** ppSettings,
+ radMemoryAllocator allocator
+);
+
+#endif // REVERBSETTINGS_H
+
diff --git a/game/code/sound/soundfx/soundeffectplayer.cpp b/game/code/sound/soundfx/soundeffectplayer.cpp
new file mode 100644
index 0000000..5847956
--- /dev/null
+++ b/game/code/sound/soundfx/soundeffectplayer.cpp
@@ -0,0 +1,249 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundeffectplayer.cpp
+//
+// Description: Implement SoundEffectPlayer, which switches between
+// the objects that direct the soundfx logic for various game
+// states
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/soundeffectplayer.h>
+
+#include <sound/soundfx/soundfxfrontendlogic.h>
+#include <sound/soundfx/soundfxgameplaylogic.h>
+#include <sound/soundfx/soundfxpauselogic.h>
+
+#ifdef RAD_XBOX
+#include <sound/soundfx/xboxreverbcontroller.h>
+#elif RAD_WIN32
+#include <sound/soundfx/win32reverbcontroller.h>
+#elif RAD_PS2
+#include <sound/soundfx/ps2reverbcontroller.h>
+#else
+#include <sound/soundfx/gcreverbcontroller.h>
+#endif
+
+#include <memory/srrmemory.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundEffectPlayer::SoundEffectPlayer
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundEffectPlayer::SoundEffectPlayer() :
+ m_reverbController( NULL ),
+ m_currentState( FXSTATE_INVALID )
+{
+ unsigned int i;
+
+ for( i = 0; i < FXSTATE_MAX_STATES; i++ )
+ {
+ m_logicObjects[i] = NULL;
+ }
+
+ initialize();
+}
+
+//==============================================================================
+// SoundEffectPlayer::~SoundEffectPlayer
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundEffectPlayer::~SoundEffectPlayer()
+{
+ unsigned int i;
+
+ for( i = 0; i < FXSTATE_MAX_STATES; i++ )
+ {
+ if( m_logicObjects[i] != NULL )
+ {
+ delete m_logicObjects[i];
+ }
+ }
+
+ delete m_reverbController;
+}
+
+//=============================================================================
+// SoundEffectPlayer::ServiceOncePerFrame
+//=============================================================================
+// Description: Positional sound servicing
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::ServiceOncePerFrame( unsigned int elapsedTime )
+{
+ if( m_currentState != FXSTATE_INVALID )
+ {
+ m_logicObjects[m_currentState]->ServiceOncePerFrame( elapsedTime );
+ }
+
+ m_reverbController->ServiceOncePerFrame( elapsedTime );
+}
+
+void SoundEffectPlayer::OnPauseStart()
+{
+ m_reverbController->PauseReverb();
+}
+
+void SoundEffectPlayer::OnPauseEnd()
+{
+ m_reverbController->UnpauseReverb();
+}
+
+//=============================================================================
+// SoundEffectPlayer::PlayCarOptionStinger
+//=============================================================================
+// Description: The following four functions play stinger sounds for the
+// level settings in the options menu
+//
+// Parameters: trim - trim setting to play it at
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::PlayCarOptionStinger( float trim )
+{
+ playStinger( "car_stinger", trim );
+}
+
+void SoundEffectPlayer::PlayDialogOptionStinger( float trim )
+{
+ playStinger( "dialog_stinger", trim );
+}
+
+void SoundEffectPlayer::PlayMusicOptionStinger( float trim )
+{
+ playStinger( "music_stinger", trim );
+}
+
+void SoundEffectPlayer::PlaySfxOptionStinger( float trim )
+{
+ playStinger( "sfx_stinger", trim );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SoundEffectPlayer::initialize
+//=============================================================================
+// Description: Create the sound FX logic objects during initialization
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::initialize()
+{
+ m_logicObjects[FXSTATE_FRONTEND] = new(GMA_PERSISTENT) SoundFXFrontEndLogic();
+ m_logicObjects[FXSTATE_GAMEPLAY] = new(GMA_PERSISTENT) SoundFXGameplayLogic();
+ m_logicObjects[FXSTATE_PAUSED] = new(GMA_PERSISTENT) SoundFXPauseLogic();
+
+#ifdef RAD_PS2
+ m_reverbController = new(GMA_PERSISTENT) PS2ReverbController();
+#elif RAD_XBOX
+ m_reverbController = new(GMA_PERSISTENT) XboxReverbController();
+#elif RAD_WIN32
+ m_reverbController = new(GMA_PERSISTENT) Win32ReverbController();
+#else
+ m_reverbController = new(GMA_PERSISTENT) GCReverbController();
+#endif
+}
+
+//=============================================================================
+// SoundEffectPlayer::setSFXState
+//=============================================================================
+// Description: Switch to a new sound FX state
+//
+// Parameters: newState - state to be switched to
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::setSFXState( SFXState newState )
+{
+ rAssert( newState < FXSTATE_MAX_STATES );
+
+ if( m_currentState != FXSTATE_INVALID )
+ {
+ m_logicObjects[m_currentState]->UnregisterEventListeners();
+ }
+
+ m_currentState = newState;
+ m_logicObjects[m_currentState]->RegisterEventListeners();
+}
+
+//=============================================================================
+// SoundEffectPlayer::doCleanup
+//=============================================================================
+// Description: Shut down anything that might be playing
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::doCleanup()
+{
+ m_logicObjects[m_currentState]->Cleanup();
+
+ m_reverbController->SetReverbOff();
+}
+
+//=============================================================================
+// SoundEffectPlayer::playStinger
+//=============================================================================
+// Description: Play the given stinger resource at the specified trim
+//
+// Parameters: stingerName - name of sound resource for stinger
+// trim - volume to play it at
+//
+// Return: void
+//
+//=============================================================================
+void SoundEffectPlayer::playStinger( const char* stingerName, float trim )
+{
+ m_stingerPlayer.PlaySound( stingerName );
+ m_stingerPlayer.SetTrim( trim );
+}
diff --git a/game/code/sound/soundfx/soundeffectplayer.h b/game/code/sound/soundfx/soundeffectplayer.h
new file mode 100644
index 0000000..3985a97
--- /dev/null
+++ b/game/code/sound/soundfx/soundeffectplayer.h
@@ -0,0 +1,122 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundeffectplayer.h
+//
+// Description: Declaration for SoundEffectPlayer class, which switches between
+// the objects that direct the soundfx logic for various game
+// states
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDEFFECTPLAYER_H
+#define SOUNDEFFECTPLAYER_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <sound/simpsonssoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+
+class SoundFXLogic;
+class ReverbController;
+
+//=============================================================================
+//
+// Synopsis: SoundEffectPlayer
+//
+//=============================================================================
+
+class SoundEffectPlayer
+{
+ public:
+ SoundEffectPlayer();
+ virtual ~SoundEffectPlayer();
+
+ //
+ // Start playing front end sounds
+ //
+ void OnFrontEndStart() { setSFXState( FXSTATE_FRONTEND ); }
+
+ //
+ // Start playing gameplay sounds
+ //
+ void OnGameplayStart() { setSFXState( FXSTATE_GAMEPLAY ); }
+ void OnGameplayEnd() { doCleanup(); }
+
+ void OnPauseStart();
+ void OnPauseEnd();
+
+ void ServiceOncePerFrame( unsigned int elapsedTime );
+
+ void PlayCarOptionStinger( float trim );
+ void PlayDialogOptionStinger( float trim );
+ void PlayMusicOptionStinger( float trim );
+ void PlaySfxOptionStinger( float trim );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundEffectPlayer( const SoundEffectPlayer& original );
+ SoundEffectPlayer& operator=( const SoundEffectPlayer& rhs );
+
+ void initialize();
+
+ //
+ // Game states in which sound effects are played
+ //
+ enum SFXState
+ {
+ FXSTATE_FRONTEND,
+ FXSTATE_GAMEPLAY,
+ FXSTATE_PAUSED,
+
+ FXSTATE_MAX_STATES,
+
+ FXSTATE_INVALID
+ };
+
+ //
+ // Set a new SFX state
+ //
+ void setSFXState( SFXState newState );
+
+ //
+ // Shut down anything that might still be playing
+ //
+ void doCleanup();
+
+ //
+ // Play a stinger (duh)
+ //
+ void playStinger( const char* stingerName, float trim );
+
+ //
+ // FX logic objects, one for each state
+ //
+ SoundFXLogic* m_logicObjects[FXSTATE_MAX_STATES];
+
+ //
+ // Reverb controller
+ //
+ ReverbController* m_reverbController;
+
+ //
+ // Current SFX state
+ //
+ SFXState m_currentState;
+
+ //
+ // Options menu stinger player
+ //
+ SimpsonsSoundPlayer m_stingerPlayer;
+};
+
+
+#endif // SOUNDEFFECTPLAYER_H
+
diff --git a/game/code/sound/soundfx/soundfxfrontendlogic.cpp b/game/code/sound/soundfx/soundfxfrontendlogic.cpp
new file mode 100644
index 0000000..d2a07aa
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxfrontendlogic.cpp
@@ -0,0 +1,137 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxfrontendlogic.cpp
+//
+// Description: Implements the SoundFXFrontEndLogic class, which handles
+// the translation of events into sound effects for the front
+// end.
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/soundfxfrontendlogic.h>
+
+#include <sound/soundmanager.h>
+
+#include <events/eventmanager.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundFXFrontEndLogic::SoundFXFrontEndLogic
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXFrontEndLogic::SoundFXFrontEndLogic()
+{
+}
+
+//==============================================================================
+// SoundFXFrontEndLogic::~SoundFXFrontEndLogic
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXFrontEndLogic::~SoundFXFrontEndLogic()
+{
+}
+
+//=============================================================================
+// SoundFXFrontEndLogic::RegisterEventListeners
+//=============================================================================
+// Description: Register as listener of sound effect events with Event Manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXFrontEndLogic::RegisterEventListeners()
+{
+ GetEventManager()->AddListener( this, EVENT_FE_MENU_SELECT );
+ GetEventManager()->AddListener( this, EVENT_FE_MENU_BACK );
+ GetEventManager()->AddListener( this, EVENT_FE_MENU_UPORDOWN );
+ GetEventManager()->AddListener( this, EVENT_FE_CHEAT_SUCCESS );
+ GetEventManager()->AddListener( this, EVENT_FE_CHEAT_FAILURE );
+ GetEventManager()->AddListener( this, EVENT_FE_CREDITS_NEW_LINE );
+}
+
+//=============================================================================
+// SoundFXFrontEndLogic::HandleEvent
+//=============================================================================
+// Description: Play sound effects in response to events
+//
+// Parameters: id - Sound effect event identifier
+// pEventData - Currently unused
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXFrontEndLogic::HandleEvent( EventEnum id, void* pEventData )
+{
+ switch( id )
+ {
+ case EVENT_FE_MENU_SELECT:
+ playSFXSound( "accept", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_MENU_BACK:
+ playSFXSound( "back", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_MENU_UPORDOWN:
+ playSFXSound( "scroll", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CHEAT_SUCCESS:
+ playSFXSound( "cheat_success", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CHEAT_FAILURE:
+ playSFXSound( "cheat_fail", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CREDITS_NEW_LINE:
+ playCreditLine( reinterpret_cast<int>(pEventData) );
+ break;
+
+ default:
+ rAssertMsg( false, "Huh? Unexpected sound FX event\n" );
+ break;
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
diff --git a/game/code/sound/soundfx/soundfxfrontendlogic.h b/game/code/sound/soundfx/soundfxfrontendlogic.h
new file mode 100644
index 0000000..eebe139
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxfrontendlogic.h
@@ -0,0 +1,50 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxfrontendlogic.h
+//
+// Description: Declaration for the SoundFXFrontEndLogic class, which handles
+// the translation of events into sound effects for the front
+// end.
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDFXFRONTENDLOGIC_H
+#define SOUNDFXFRONTENDLOGIC_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/soundfxlogic.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: SoundFXFrontEndLogic
+//
+//=============================================================================
+
+class SoundFXFrontEndLogic : public SoundFXLogic
+{
+ public:
+ SoundFXFrontEndLogic();
+ virtual ~SoundFXFrontEndLogic();
+
+ void RegisterEventListeners();
+
+ virtual void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundFXFrontEndLogic( const SoundFXFrontEndLogic& original );
+ SoundFXFrontEndLogic& operator=( const SoundFXFrontEndLogic& rhs );
+};
+
+
+#endif // SOUNDFXFRONTENDLOGIC_H
+
diff --git a/game/code/sound/soundfx/soundfxgameplaylogic.cpp b/game/code/sound/soundfx/soundfxgameplaylogic.cpp
new file mode 100644
index 0000000..20b995e
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxgameplaylogic.cpp
@@ -0,0 +1,1212 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxgameplaylogic.cpp
+//
+// Description: Implements the SoundFXGameplayLogic class, which handles
+// the translation of events into sound effects for the game
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radnamespace.hpp>
+#include <radtime.hpp>
+#include <radsound_hal.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/soundfxgameplaylogic.h>
+
+#include <sound/soundmanager.h>
+#include <sound/soundcollisiondata.h>
+#include <sound/soundfx/positionalsoundsettings.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <sound/avatar/carsoundparameters.h>
+#include <sound/tuning/globalsettings.h>
+
+#include <events/eventmanager.h>
+#include <meta/scriptlocator.h>
+#include <worldsim/physicsairef.h>
+#include <worldsim/character/character.h>
+#include <worldsim/vehiclecentral.h>
+#include <worldsim/avatarmanager.h>
+#include <mission/gameplaymanager.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// These are compared against the collision impulse value, which is 0 - 1.
+//
+
+static const float ARBITRARY_IMPULSE_THRESHOLD = 0.01f;
+
+// Above this value, send big crash event to dialog system
+static const float ARBITRARY_BIG_CRASH_THRESHOLD = 0.15f;
+
+// These values determine whether to play small, medium, or big crash
+// sounds for vehicles
+static const float ARBITRARY_VEHICLE_MEDIUM_CRASH_THRESHOLD = 0.15f;
+static const float ARBITRARY_VEHICLE_BIG_CRASH_THRESHOLD = 0.25f;
+
+static const char* s_hydrantSprayName = "hydrant_spray";
+
+//
+// Arbitrary value. If a collision occurs between the avatar vehicle
+// and an object, where the difference between their distances is greater
+// than this, then the avatar hit a wall or something, so don't average
+// the positions.
+//
+static const float POSITIONAL_COLLISION_MAX_DISTANCE_SQR = 100.0f;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundFXGameplayLogic::SoundFXGameplayLogic
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXGameplayLogic::SoundFXGameplayLogic() :
+ m_collisionMinMax( NULL ),
+ m_coinCounter( 0 ),
+ m_lastRonkTime( 0 ),
+ m_globalSettings( NULL )
+{
+}
+
+//==============================================================================
+// SoundFXGameplayLogic::~SoundFXGameplayLogic
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXGameplayLogic::~SoundFXGameplayLogic()
+{
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::RegisterEventListeners
+//=============================================================================
+// Description: Register as listener of sound effect events with Event Manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::RegisterEventListeners()
+{
+ EventManager* eventMgr = GetEventManager();
+
+ eventMgr->AddListener( this, EVENT_COLLISION );
+ eventMgr->AddListener( this, EVENT_FOOTSTEP );
+ eventMgr->AddListener( this, EVENT_BIG_RED_SWITCH_PRESSED );
+ eventMgr->AddListener( this, EVENT_JUMP_TAKEOFF );
+ eventMgr->AddListener( this, EVENT_JUMP_LANDING );
+ eventMgr->AddListener( this, EVENT_POSITIONAL_SOUND_TRIGGER_HIT );
+ eventMgr->AddListener( this, EVENT_GETINTOVEHICLE_START );
+ eventMgr->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
+ eventMgr->AddListener( this, EVENT_FE_MENU_SELECT );
+ eventMgr->AddListener( this, EVENT_FE_MENU_UPORDOWN );
+ eventMgr->AddListener( this, EVENT_FE_MENU_BACK );
+ eventMgr->AddListener( this, EVENT_COLLECTED_COINS );
+ eventMgr->AddListener( this, EVENT_LOST_COINS );
+ eventMgr->AddListener( this, EVENT_SPAWNED_COINS );
+ eventMgr->AddListener( this, EVENT_PHONE_BOOTH_BUSY );
+ eventMgr->AddListener( this, EVENT_PLAYER_CAR_HIT_NPC );
+ eventMgr->AddListener( this, EVENT_BIG_BOOM_SOUND );
+ eventMgr->AddListener( this, EVENT_CARD_COLLECTED );
+ eventMgr->AddListener( this, EVENT_COLLECTED_WRENCH );
+ eventMgr->AddListener( this, EVENT_VEHICLE_SUSPENSION_BOTTOMED_OUT );
+ eventMgr->AddListener( this, EVENT_MISSION_COLLECTIBLE_PICKED_UP );
+ eventMgr->AddListener( this, EVENT_KICK_NPC );
+ eventMgr->AddListener( this, EVENT_OBJECT_KICKED );
+ eventMgr->AddListener( this, EVENT_WASP_BULLET_FIRED );
+ eventMgr->AddListener( this, EVENT_WASP_BULLET_MISSED );
+ eventMgr->AddListener( this, EVENT_WASP_BULLET_HIT_CHARACTER_STYLIZED_VIOLENCE_FOLLOWS );
+ eventMgr->AddListener( this, EVENT_START_ANIMATION_SOUND );
+ eventMgr->AddListener( this, EVENT_MISSION_SUCCESS );
+ eventMgr->AddListener( this, EVENT_STAGE_COMPLETE );
+ eventMgr->AddListener( this, EVENT_HIT_AND_RUN_CAUGHT );
+ eventMgr->AddListener( this, EVENT_HIT_AND_RUN_METER_THROB );
+ eventMgr->AddListener( this, EVENT_SHOW_MISSION_OBJECTIVE );
+ eventMgr->AddListener( this, EVENT_PLAY_BIRD_SOUND );
+ eventMgr->AddListener( this, static_cast<EventEnum>(EVENT_LOCATOR + LocatorEvent::BOUNCEPAD) );
+ eventMgr->AddListener( this, EVENT_FE_PAUSE_MENU_END );
+ eventMgr->AddListener( this, EVENT_FE_PAUSE_MENU_START );
+ eventMgr->AddListener( this, EVENT_FE_CANCEL );
+ eventMgr->AddListener( this, EVENT_FE_CONTINUE );
+ eventMgr->AddListener( this, EVENT_FE_LOCKED_OUT );
+ eventMgr->AddListener( this, EVENT_BARREL_BLOWED_UP );
+ eventMgr->AddListener( this, EVENT_FE_CREDITS_NEW_LINE );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::HandleEvent
+//=============================================================================
+// Description: Play sound effects in response to events
+//
+// Parameters: id - Sound effect event identifier
+// pEventData - Currently unused
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::HandleEvent( EventEnum id, void* pEventData )
+{
+ Vehicle* vehiclePtr;
+ unsigned int ronkTime;
+ const char* soundName;
+ RenderEnums::LevelEnum level;
+ AnimSoundData* animData;
+
+ switch( id )
+ {
+ case EVENT_COLLISION:
+ handleCollisionEvent( static_cast<SoundCollisionData*>(pEventData) );
+ break;
+
+ case EVENT_FOOTSTEP:
+ handleFootstepEvent( static_cast<Character*>(pEventData) );
+ break;
+
+ case EVENT_JUMP_TAKEOFF:
+ playSFXSound( "jump", false );
+ break;
+
+ case EVENT_JUMP_LANDING:
+ //
+ // TEMPORARY: we need a surface-sensitive solution
+ //
+ playSFXSound( "feet_concrete_jump", false );
+ break;
+
+ case EVENT_BIG_RED_SWITCH_PRESSED:
+ handleSwitchEvent();
+ break;
+
+ case EVENT_POSITIONAL_SOUND_TRIGGER_HIT:
+ playPositionalSound( static_cast<ScriptLocator*>(pEventData) );
+ break;
+
+ case EVENT_GETINTOVEHICLE_START:
+ case EVENT_GETOUTOFVEHICLE_END:
+ playCarDoorSound( id, static_cast<Character*>(pEventData) );
+ break;
+
+ case EVENT_FE_MENU_SELECT:
+ playSFXSound( "accept", false, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+ case EVENT_FE_MENU_UPORDOWN:
+ playSFXSound( "scroll", false, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+ case EVENT_FE_MENU_BACK:
+ playSFXSound( "back", false, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+ case EVENT_FE_LOCKED_OUT:
+ playSFXSound( "locked_out", false );
+ break;
+
+ case EVENT_COLLECTED_COINS:
+ playCoinCollectSound();
+ break;
+
+ case EVENT_SPAWNED_COINS:
+ //
+ // Should this do anything?
+ //
+ break;
+
+ case EVENT_LOST_COINS:
+ playSFXSound( "coin_lose", true );
+ break;
+
+ case EVENT_PHONE_BOOTH_BUSY:
+ playSFXSound( "phonebusy", false );
+ break;
+
+ case EVENT_PLAYER_CAR_HIT_NPC:
+ {
+ //
+ // Set up special collision data for the collision code, because
+ // it won't be getting a collision event. I like saying "collision".
+ //
+ SoundCollisionData collData( 0.0f, static_cast<CollisionEntityDSG*>(pEventData), NULL );
+
+ handleCollisionEvent( &collData );
+ }
+ break;
+
+ case EVENT_KICK_NPC:
+ playSFXSound( "car_hit_pedestrian", true );
+ break;
+
+ case EVENT_OBJECT_KICKED:
+ handleObjectKick( static_cast<CollisionEntityDSG*>(pEventData) );
+ break;
+
+ case EVENT_BIG_BOOM_SOUND:
+ vehiclePtr = static_cast<Vehicle*>(pEventData);
+ rAssert( vehiclePtr != NULL );
+ if( vehiclePtr->mVehicleType == VT_USER )
+ {
+ playSFXSound( "generic_car_explode", false );
+ }
+ break;
+
+ case EVENT_BARREL_BLOWED_UP:
+ playSFXSound( "generic_car_explode", false );
+ break;
+
+ case EVENT_CARD_COLLECTED:
+ //
+ // Only play card sound effect in car, the music system
+ // handles it when on foot
+ //
+ if( GetAvatarManager()->GetAvatarForPlayer( 0 )->IsInCar() )
+ {
+ playSFXSound( "card_collect", false );
+ }
+ break;
+
+ case EVENT_COLLECTED_WRENCH:
+ playSFXSound( "wrench_collect", false );
+ break;
+
+ case EVENT_VEHICLE_SUSPENSION_BOTTOMED_OUT:
+ //
+ // Play only if we haven't played the last one within a half-second.
+ // Use a simple timestamp to determine this.
+ //
+ ronkTime = ::radTimeGetMilliseconds();
+ if( ( ronkTime < m_lastRonkTime )
+ || ( ( ronkTime - m_lastRonkTime ) > 500 ) )
+ {
+ m_lastRonkTime = ronkTime;
+ playSFXSound( "suspension_ronks", true );
+ }
+ break;
+
+ case EVENT_MISSION_COLLECTIBLE_PICKED_UP:
+ handleCollection();
+ break;
+
+ case EVENT_WASP_BULLET_FIRED:
+ playSFXSound( "wasp_lasers", true );
+ break;
+
+ case EVENT_WASP_BULLET_MISSED:
+ playSFXSound( "laser_miss", true );
+ break;
+
+ case EVENT_WASP_BULLET_HIT_CHARACTER_STYLIZED_VIOLENCE_FOLLOWS:
+ playSFXSound( "character_zapped", true );
+ break;
+
+ case EVENT_START_ANIMATION_SOUND:
+ animData = static_cast<AnimSoundData*>( pEventData );
+ soundName = animData->soundName;
+ if( ( soundName != NULL ) && ( animData->animJoint == NULL ) )
+ {
+ playSFXSound( soundName, false );
+ }
+ break;
+
+ case EVENT_MISSION_SUCCESS:
+ playSFXSound( "mission_complete", false );
+ break;
+
+ case EVENT_STAGE_COMPLETE:
+ playSFXSound( "stage_complete", false );
+ break;
+
+ case EVENT_HIT_AND_RUN_CAUGHT:
+ playSFXSound( "busted", false );
+ break;
+
+ case EVENT_HIT_AND_RUN_METER_THROB:
+ playSFXSound( "rage_warning", false );
+ break;
+
+ case EVENT_SHOW_MISSION_OBJECTIVE:
+ playSFXSound( "pop_up", true );
+ break;
+
+ case EVENT_PLAY_BIRD_SOUND:
+ //
+ // Pick the correct bird effect for the level
+ //
+ level = GetGameplayManager()->GetCurrentLevelIndex();
+ if( ( level == RenderEnums::L2 )
+ || ( level == RenderEnums::L5 ) )
+ {
+ playSFXSound( "pigeon_takeoff", false );
+ }
+ else if( ( level == RenderEnums::L3 )
+ || ( level == RenderEnums::L6 ) )
+ {
+ playSFXSound( "gull_takeoff", false );
+ }
+ break;
+
+ case EVENT_LOCATOR + LocatorEvent::BOUNCEPAD :
+ playSFXSound( "trampoline", true );
+ break;
+
+ case EVENT_FE_PAUSE_MENU_START:
+ playSFXSound( "pause_on", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_PAUSE_MENU_END:
+ playSFXSound( "pause_off", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CONTINUE:
+ playSFXSound( "continue", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CANCEL:
+ playSFXSound( "cancel", true, false, NULL, GetSoundManager()->GetSfxVolume() );
+ break;
+
+ case EVENT_FE_CREDITS_NEW_LINE:
+ playCreditLine( reinterpret_cast<int>(pEventData) );
+ break;
+
+ default:
+ rAssertMsg( false, "Unexpected event received in SoundFXGameplayLogic\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::OnPlaybackComplete
+//=============================================================================
+// Description: No longer used, now that tutorial lines are played through
+// the dialog system
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::OnPlaybackComplete()
+{
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::Cleanup
+//=============================================================================
+// Description: Called on gameplay exit. Use this to shut down any
+// positional sounds that might be playing.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::Cleanup()
+{
+ int i;
+
+ for( i = 0; i < s_numPositionalSounds; i++ )
+ {
+ if( m_positionalSounds[i].IsInUse() )
+ {
+ m_positionalSounds[i].Stop();
+ }
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SoundFXGameplayLogic::getGlobalSettings
+//=============================================================================
+// Description: Initialize the member pointer to the global settings object
+// if not done yet, and return it
+//
+// Parameters: None
+//
+// Return: pointer to globalSettings object
+//
+//=============================================================================
+globalSettings* SoundFXGameplayLogic::getGlobalSettings()
+{
+ IRadNameSpace* nameSpace;
+
+ if( m_globalSettings == NULL )
+ {
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ m_globalSettings = static_cast<globalSettings*>(nameSpace->GetInstance( "tuner" ));
+ rAssert( m_globalSettings != NULL );
+ }
+
+ return( m_globalSettings );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::handleCollisionEvent
+//=============================================================================
+// Description: Play a collision sound appropriate for this event, unless we've
+// already received an event for this collision. A typical collision
+// throws a lot of duplicate events, apparently, so we gotta screen
+// 'em out.
+//
+// Parameters: collisionData - data we need pertaining to the collision, passed
+// through the event mechanism
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::handleCollisionEvent( SoundCollisionData* collisionData )
+{
+ int i;
+
+ //
+ // FOR NOW: filter out collisions that don't involve the user's car. Later,
+ // we might want to do AI-car collisions within a certain radius or
+ // something
+ //
+
+ //TODO (Cary): I think that this should search the avatar manager for each vehicle in the
+ //collision pair (or always take A so that vehicles don't get doubled events) and test to
+ //see if the vehicle is user controlled. The code as it is only sends events for player 0
+ //and won't work for multiplayer.
+ Vehicle* pVehicle = GetAvatarManager()->GetAvatarForPlayer( 0 )->GetVehicle();
+
+ if( !pVehicle )
+ {
+ return;
+ }
+
+ //
+ // See if we're already playing a sound for this collision, or if all collision
+ // players are in use. If so, exit
+ //
+ for( i = 0; i < s_numCollisionSounds; i++ )
+ {
+ if( m_collisionSounds[i].soundPlayer.IsInUse() )
+ {
+ if( collisionPairMatches( i, collisionData->collObjA, collisionData->collObjB ) )
+ {
+ // Collision sound already being played, do nothing
+ return;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if( i == s_numCollisionSounds )
+ {
+ //
+ // All players are being used
+ //
+ return;
+ }
+
+ CollisionAttributes* attributes;
+ CollisionEntityDSG* collEntities[2];
+ const char* vehicleCrashName = NULL;
+ const char* nonVehicleCrashName = NULL;
+ CollisionEntityDSG* hydrantObject = NULL;
+ bool hydrantHit = false;
+ EventEnum minorCrash = EVENT_MINOR_VEHICLE_CRASH;
+ EventEnum bigCrash = EVENT_BIG_VEHICLE_CRASH;
+ Vehicle* collisionVehicle = NULL;
+ CollisionEntityDSG* otherEntity = NULL;
+ rmt::Vector diffVector;
+ rmt::Vector avatarPosition;
+ rmt::Vector* vectorPtr = NULL;
+ bool avatarVehicleInvolved = false;
+
+ collEntities[0] = collisionData->collObjA;
+ collEntities[1] = collisionData->collObjB;
+
+ //
+ // NOTE: this code assumes that we have at most one vehicle and one non-vehicle
+ // in the collision pair. If we have two non-vehicles, one is lost. Eh.
+ //
+ for( i = 0; i < 2; i++ )
+ {
+ //
+ // If the DSG object is NULL, one of the objects is a fence or something.
+ // Ignore and move on.
+ //
+ if( collEntities[i] != NULL )
+ {
+ if( collEntities[i]->GetAIRef() == PhysicsAIRef::redBrickVehicle )
+ {
+ //
+ // Vehicle, play smashy sound
+ //
+ if( collisionData->mIntensity > ARBITRARY_VEHICLE_BIG_CRASH_THRESHOLD )
+ {
+ vehicleCrashName = "large_car_crash";
+ }
+ else if( collisionData->mIntensity > ARBITRARY_VEHICLE_MEDIUM_CRASH_THRESHOLD )
+ {
+ vehicleCrashName = "medium_car_crash";
+ }
+ else
+ {
+ vehicleCrashName = "small_car_crash";
+ }
+
+ collisionVehicle = static_cast<Vehicle*>( collEntities[i] );
+
+ if( collEntities[i] == pVehicle )
+ {
+ //
+ // Collision involves the user vehicle, store the other
+ // entity
+ //
+ if( i == 0 )
+ {
+ otherEntity = collEntities[1];
+ }
+ else
+ {
+ otherEntity = collEntities[0];
+ }
+
+ avatarVehicleInvolved = true;
+ }
+ }
+ else
+ {
+ //
+ // Non-vehicle, get attributes
+ //
+ attributes = collEntities[i]->GetCollisionAttributes();
+ if( attributes == NULL )
+ {
+ //
+ // No attributes. Character, I assume? It'd be nice if the
+ // Character class filled this in. Something to try.
+ //
+ nonVehicleCrashName = "car_hit_pedestrian";
+ }
+ else
+ {
+ nonVehicleCrashName = attributes->GetSound();
+
+ //
+ // Stinky special case
+ //
+ if( attributes->GetBreakable() == BreakablesEnum::eHydrantBreaking )
+ {
+ hydrantHit = true;
+ hydrantObject = collEntities[i];
+ }
+ }
+
+ //
+ // This eliminates vehicle-on-vehicle collision, so don't use that
+ // type of event for the dialog system
+ //
+ minorCrash = EVENT_MINOR_CRASH;
+ bigCrash = EVENT_BIG_CRASH;
+ }
+ }
+ else
+ {
+ //
+ // This eliminates vehicle-on-vehicle collision, so don't use that
+ // type of event for the dialog system
+ //
+ minorCrash = EVENT_MINOR_CRASH;
+ bigCrash = EVENT_BIG_CRASH;
+ }
+ }
+
+
+ //
+ // Based on how hard the crash is, pass on an event that the dialog
+ // system can use (Q: is this the best place for this? If other
+ // game components start using it, this should be moved).
+ //
+ if( avatarVehicleInvolved )
+ {
+ if( collisionData->mIntensity < ARBITRARY_BIG_CRASH_THRESHOLD )
+ {
+ if( collisionData->mIntensity >= ARBITRARY_IMPULSE_THRESHOLD )
+ {
+ if( minorCrash == EVENT_MINOR_CRASH )
+ {
+ //
+ // Can't be vehicle-on-vehicle
+ //
+ collisionVehicle = NULL;
+ }
+ GetEventManager()->TriggerEvent( minorCrash, collisionVehicle );
+ }
+ }
+ else
+ {
+ if( bigCrash == EVENT_BIG_CRASH )
+ {
+ //
+ // Isn't vehicle-on-vehicle
+ //
+ collisionVehicle = NULL;
+ }
+ GetEventManager()->TriggerEvent( bigCrash, collisionVehicle );
+ }
+ }
+
+ //
+ // Play the collision sound if we've got a player free
+ //
+ rAssert( collisionData->mIntensity >= 0.0f );
+ rAssert( collisionData->mIntensity <= 1.0f );
+
+ //
+ // Check whether the colliding entities are really far apart. If so,
+ // then the player has hit a wall or something, so don't bother averaging
+ // the distances between them, just play at the avatar position
+ //
+ if( otherEntity != NULL )
+ {
+ pVehicle->GetPosition( &avatarPosition );
+ otherEntity->GetPosition( &diffVector );
+ diffVector -= avatarPosition;
+
+ if( diffVector.MagnitudeSqr() > POSITIONAL_COLLISION_MAX_DISTANCE_SQR )
+ {
+ vectorPtr = &avatarPosition;
+ }
+ }
+
+ //
+ // Play the sounds in free players (or kill something
+ // if they're all in use)
+ //
+ if( vehicleCrashName != NULL )
+ {
+ startCollisionPlayer( vehicleCrashName, collisionData->collObjA, collisionData->collObjB, vectorPtr );
+ }
+ if( nonVehicleCrashName != NULL )
+ {
+ startCollisionPlayer( nonVehicleCrashName, collisionData->collObjA, collisionData->collObjB, vectorPtr );
+
+ //
+ // Stinky fire hydrant hack.
+ //
+ if( hydrantHit )
+ {
+ rAssert( hydrantObject != NULL );
+ startCollisionPlayer( s_hydrantSprayName, hydrantObject, NULL, NULL );
+ }
+ }
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::handleObjectKick
+//=============================================================================
+// Description: Play a sound for an object that gets kicked
+//
+// Parameters: collObject - kicked object
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::handleObjectKick( CollisionEntityDSG* collObject )
+{
+ CollisionAttributes* attributes;
+ const char* soundName;
+
+ attributes = collObject->GetCollisionAttributes();
+ if( attributes != NULL )
+ {
+ soundName = attributes->GetSound();
+
+ //
+ // Cheat: don't play this positionally because I'd have to work around
+ // the double-play filter because of the stinky fire hydrant. Hope
+ // that's okay
+ //
+ playSFXSound( soundName, true );
+
+ //
+ // More hydrant hack
+ //
+ if( attributes->GetBreakable() == BreakablesEnum::eHydrantBreaking )
+ {
+ startCollisionPlayer( s_hydrantSprayName, collObject, NULL, NULL );
+ }
+ }
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::collisionPairMatches
+//=============================================================================
+// Description: Check for match between parameters and collision pair at
+// given index
+//
+// Parameters: index - index into m_collisionSource that we're matching against
+// firstObj, secondObj - collision objects to match with
+//
+// Return: true if matching, false otherwise
+//
+//=============================================================================
+bool SoundFXGameplayLogic::collisionPairMatches( int index, void* firstObj, void* secondObj )
+{
+ PositionalSFXPlayer* storedPair;
+
+ rAssert( index < s_numCollisionSounds );
+
+ storedPair = &(m_collisionSounds[index]);
+
+ return( ( ( storedPair->collObjA == firstObj ) &&
+ ( storedPair->collObjB == secondObj ) )
+
+ ||
+
+ ( ( storedPair->collObjA == secondObj ) &&
+ ( storedPair->collObjB == firstObj ) ) );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::startCollisionPlayer
+//=============================================================================
+// Description: Find a free positional sound player (or stop one if necessary)
+// and play the sound and store the collision pair
+//
+// Parameters: soundName - name of sound resource to play
+// objA - first colliding object
+// objB - second colliding object
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::startCollisionPlayer( const char* soundName,
+ CollisionEntityDSG* objA,
+ CollisionEntityDSG* objB,
+ rmt::Vector* positionPtr )
+{
+ int index;
+ rmt::Vector posnA;
+ rmt::Vector posnB;
+ rmt::Vector average;
+ rmt::Vector vectorToListener;
+ radSoundVector rsListenerPosition;
+ rmt::Vector listenerPosition;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ IRadSoundHalListener* theListener;
+
+
+ //
+ // Look for a free player first
+ //
+ for( index = 0; index < s_numCollisionSounds; index++ )
+ {
+ if( !(m_collisionSounds[index].soundPlayer.IsInUse()) )
+ {
+ break;
+ }
+ }
+
+ //
+ // If all are in use, stop one. Arbitrarily, use the one
+ // at the start of the list, since it's most likely to have
+ // been playing the longest. No need to get cute.
+ //
+ if( index >= s_numCollisionSounds )
+ {
+ index = 0;
+ m_collisionSounds[0].soundPlayer.Stop();
+
+ rWarningMsg( false, "Collision sound dropped for lack of players\n" );
+ }
+
+ //
+ // Store the collision pair
+ //
+ m_collisionSounds[index].collObjA = objA;
+ m_collisionSounds[index].collObjB = objB;
+
+ //
+ // Play the sound halfway between the positions of the
+ // colliding objects (if two objects are used)
+ //
+ if( positionPtr != NULL )
+ {
+ average = *positionPtr;
+ }
+ else if( objA == NULL )
+ {
+ objB->GetPosition( &average );
+ }
+ else if( objB == NULL )
+ {
+ objA->GetPosition( &average );
+ }
+ else
+ {
+ objA->GetPosition( &posnA );
+ objB->GetPosition( &posnB );
+ average.Add( posnA, posnB );
+ average *= 0.5f;
+ }
+
+ if( GetGameplayManager()->IsSuperSprint() )
+ {
+ //
+ // Hoo boy. Big stinky hack coming up. The problem is that sounds are
+ // positional, and the camera is a very long ways away in the bonus game.
+ // Fudge the position to make the collisions suitably close.
+ //
+ theListener = ::radSoundHalListenerGet( );
+ rAssert( theListener != NULL );
+
+ theListener->GetPosition( &rsListenerPosition );
+ listenerPosition.Set( rsListenerPosition.m_x, rsListenerPosition.m_y, rsListenerPosition.m_z );
+ vectorToListener = average - listenerPosition;
+ vectorToListener.Scale( 0.01f, 0.01f, 0.01f );
+ average = listenerPosition + vectorToListener;
+ }
+
+ if( m_collisionMinMax == NULL )
+ {
+ //
+ // Lazy initialization. Grab the positional characteristics for collision sounds
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( "collision_sounds" );
+ rAssert( nameSpaceObj != NULL );
+ m_collisionMinMax = reinterpret_cast<positionalSoundSettings*>(nameSpaceObj);
+ }
+
+ m_collisionSounds[index].soundPlayer.SetPosition( average.x, average.y, average.z );
+ m_collisionSounds[index].soundPlayer.SetParameters( m_collisionMinMax );
+ m_collisionSounds[index].soundPlayer.PlaySound( soundName );
+ m_collisionSounds[index].soundPlayer.SetTrim( 1.0f );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::handleFootstepEvent
+//=============================================================================
+// Description: Plays appropriate footstep sound
+//
+// Parameters: walkingCharacter - character doing the walking
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::handleFootstepEvent( Character* walkingCharacter )
+{
+ eTerrainType terrain;
+ bool isInterior;
+ globalSettings* clipNameObj;
+ const char* name = NULL;
+
+ rAssert( walkingCharacter != NULL );
+ walkingCharacter->GetTerrainType( terrain, isInterior );
+
+ //
+ // Get the parameter object for this positional sound.
+ //
+ clipNameObj = getGlobalSettings();
+
+ if( isInterior )
+ {
+ //
+ // Use the road clip indoors
+ //
+ name = clipNameObj->GetFootstepRoadClipName();
+ }
+ else if( terrain == TT_Metal )
+ {
+ name = clipNameObj->GetFootstepMetalClipName();
+ }
+ else if( terrain == TT_Wood )
+ {
+ name = clipNameObj->GetFootstepWoodClipName();
+ }
+ else
+ {
+ name = clipNameObj->GetFootstepRoadClipName();
+ }
+
+ rAssert( name != NULL );
+
+ playSFXSound( name, true );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::handleSwitchEvent
+//=============================================================================
+// Description: Play clicking sound for big red switches
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::handleSwitchEvent()
+{
+ playSFXSound( "switch", false );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::handleCollection
+//=============================================================================
+// Description: Play the appropriate sound for picking up a collectible
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::handleCollection()
+{
+ RenderEnums::LevelEnum level;
+ int mission;
+ const char* soundName = NULL;
+
+ //
+ // We don't have a way to identify collectible types, so select a
+ // sound resource based on our level/mission
+ //
+ level = GetGameplayManager()->GetCurrentLevelIndex();
+ mission = GetGameplayManager()->GetCurrentMissionIndex();
+ switch( level )
+ {
+ case RenderEnums::L1 :
+ soundName = "level_1_pickup_sfx";
+ break;
+ case RenderEnums::L2 :
+ if( mission == 6 )
+ {
+ soundName = "monkey_collect";
+ }
+ else
+ {
+ soundName = "level_2_pickup_sfx";
+ }
+ break;
+ case RenderEnums::L3 :
+ soundName = "level_3_pickup_sfx";
+ break;
+ case RenderEnums::L4 :
+ soundName = "level_4_pickup_sfx";
+ break;
+ case RenderEnums::L5 :
+ soundName = "level_5_pickup_sfx";
+ break;
+ case RenderEnums::L6 :
+ soundName = "level_6_pickup_sfx";
+ break;
+ case RenderEnums::L7 :
+ soundName = "nuclear_waste_collect";
+ break;
+ default:
+ break;
+ }
+
+ rAssertMsg( ( soundName != NULL ), "Collection without sound effect, tell Esan\n" );
+
+ playSFXSound( soundName, true );
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::playPositionalSound
+//=============================================================================
+// Description: Plays a positional sound in the world when a positional
+// (a.k.a. script) trigger is hit
+//
+// Parameters: locator - locator for the sound
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::playPositionalSound( ScriptLocator* locator )
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ positionalSoundSettings* parameters;
+ float diceRoll;
+ float probability;
+ int i;
+ rmt::Vector locatorPosition;
+
+ rAssert( locator != NULL );
+
+ //
+ // Get the parameter object for this positional sound.
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( locator->GetKey() );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<positionalSoundSettings*>( nameSpaceObj );
+
+ if( !(locator->GetPlayerEntered()) )
+ {
+ //
+ // Player is exiting volume, not entering. If we're playing a sound
+ // already, stop it
+ //
+ for( i = 0; i < s_numPositionalSounds; i++ )
+ {
+ if( m_positionalSounds[i].IsInUse()
+ && ( m_positionalSounds[i].GetParameters() == parameters ) )
+ {
+ m_positionalSounds[i].Stop();
+ break;
+ }
+ }
+ }
+ else
+ {
+ probability = parameters->GetPlaybackProbability();
+ if( probability < 1.0f )
+ {
+ //
+ // Random play
+ //
+ diceRoll = (static_cast<float>( rand() % 100 )) / 100.0f;
+ if( diceRoll >= probability )
+ {
+ return;
+ }
+ }
+
+ //
+ // Find a player and play
+ //
+ for( i = 0; i < s_numPositionalSounds; i++ )
+ {
+ if( !(m_positionalSounds[i].IsInUse()) )
+ {
+ locator->GetLocation( &locatorPosition );
+ m_positionalSounds[i].SetPosition( locatorPosition.x,
+ locatorPosition.y,
+ locatorPosition.z );
+ m_positionalSounds[i].SetParameters( parameters );
+
+ //
+ // Don't buffer, to save IOP
+ //
+
+ m_positionalSounds[i].PlaySound( parameters->GetClipName(), NULL );
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ rDebugString( "Couldn't play missing positional sound" );
+ }
+}
+
+void SoundFXGameplayLogic::playCarDoorSound( EventEnum eventType, Character* playerCharacter )
+{
+ Vehicle* car;
+ carSoundParameters* parameters;
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ const char* clipName;
+
+ //
+ // Get name of clip
+ //
+ car = playerCharacter->GetTargetVehicle();
+ if( car != NULL )
+ {
+ //
+ // Get the car sound parameter object for this vehicle.
+ //
+ // IMPORTANT: We assume that the object in the namespace has the same
+ // name as the one in the vehicle object, which comes from the loading
+ // script for that car, I think.
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ nameSpaceObj = nameSpace->GetInstance( car->GetName() );
+ if( nameSpaceObj != NULL )
+ {
+ parameters = reinterpret_cast<carSoundParameters*>( nameSpaceObj );
+
+ if( eventType == EVENT_GETINTOVEHICLE_START )
+ {
+ clipName = parameters->GetCarDoorOpenClipName();
+ }
+ else
+ {
+ clipName = parameters->GetCarDoorCloseClipName();
+ }
+
+ if( clipName != NULL )
+ {
+ playSFXSound( clipName, false );
+ }
+ }
+ else
+ {
+ rDebugString( "Couldn't find car door sound\n" );
+ }
+ }
+}
+
+//=============================================================================
+// SoundFXGameplayLogic::playCoinCollectSound
+//=============================================================================
+// Description: Play next coin collect sound in sequence
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXGameplayLogic::playCoinCollectSound()
+{
+ float pitch;
+ unsigned int numPitches;
+ globalSettings* pitchSequence = getGlobalSettings();
+
+ pitch = pitchSequence->GetCoinPitch( m_coinCounter );
+ playSFXSound( "coin_collect_01", true, false, NULL, 1.0f, pitch );
+
+ numPitches = pitchSequence->GetNumCoinPitches();
+ if( numPitches > 0 )
+ {
+ m_coinCounter = ( m_coinCounter + 1 ) % numPitches;
+ }
+}
diff --git a/game/code/sound/soundfx/soundfxgameplaylogic.h b/game/code/sound/soundfx/soundfxgameplaylogic.h
new file mode 100644
index 0000000..cb1e5f9
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxgameplaylogic.h
@@ -0,0 +1,130 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxgameplaylogic.h
+//
+// Description: Declaration for the SoundFXGameplayLogic class, which handles
+// the translation of events into sound effects for the game
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDFXGAMEPLAYLOGIC_H
+#define SOUNDFXGAMEPLAYLOGIC_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radmath/radmath.hpp>
+
+#include <sound/soundfx/soundfxlogic.h>
+#include <sound/positionalsoundplayer.h>
+#include <events/eventenum.h>
+
+//========================================
+// Forward References
+//========================================
+
+class SoundCollisionData;
+class Character;
+class ScriptLocator;
+class CollisionEntityDSG;
+class globalSettings;
+
+//=============================================================================
+//
+// Synopsis: PositionalSFXPlayer
+//
+// Associated stuff required to play a positional collision sound
+//
+//=============================================================================
+struct PositionalSFXPlayer
+{
+ PositionalSoundPlayer soundPlayer;
+ void* collObjA;
+ void* collObjB;
+};
+
+//=============================================================================
+//
+// Synopsis: SoundFXGameplayLogic
+//
+//=============================================================================
+
+class SoundFXGameplayLogic : public SoundFXLogic
+{
+ public:
+ SoundFXGameplayLogic();
+ virtual ~SoundFXGameplayLogic();
+
+ void RegisterEventListeners();
+
+ virtual void HandleEvent( EventEnum id, void* pEventData );
+
+ //
+ // Override callback to trigger tutorial events
+ //
+ void OnPlaybackComplete();
+
+ //
+ // Virtual function to clean up positional sounds
+ //
+ void Cleanup();
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundFXGameplayLogic( const SoundFXGameplayLogic& original );
+ SoundFXGameplayLogic& operator=( const SoundFXGameplayLogic& rhs );
+
+ globalSettings* getGlobalSettings();
+
+ void handleCollisionEvent( SoundCollisionData* collisionData );
+ void handleFootstepEvent( Character* walkingCharacter );
+ void handleSwitchEvent();
+ void handleCollection();
+ void handleObjectKick( CollisionEntityDSG* collObject );
+ void playPositionalSound( ScriptLocator* locator );
+ void playCarDoorSound( EventEnum eventType, Character* playerCharacter );
+ void playCoinCollectSound();
+ void startCollisionPlayer( const char* soundName,
+ CollisionEntityDSG* objA,
+ CollisionEntityDSG* objB,
+ rmt::Vector* positionPtr );
+
+ bool collisionPairMatches( int index, void* firstObj, void* secondObj );
+
+ // Number of simultaneous positional sounds
+ static const int s_numPositionalSounds = 3;
+
+ //
+ // Positional sound objects
+ //
+ PositionalSoundPlayer m_positionalSounds[s_numPositionalSounds];
+
+ // Number of simultaneous collision sounds
+ static const int s_numCollisionSounds = 6;
+
+ //
+ // Positional collision sounds
+ //
+ PositionalSFXPlayer m_collisionSounds[s_numCollisionSounds];
+
+ positionalSoundSettings* m_collisionMinMax;
+
+ //
+ // Counter for cycling through ka-ching sounds
+ //
+ unsigned int m_coinCounter;
+
+ //
+ // Timing for suspension ronks
+ //
+ unsigned int m_lastRonkTime;
+
+ globalSettings* m_globalSettings;
+};
+
+
+#endif // SOUNDFXGAMEPLAYLOGIC_H
+
diff --git a/game/code/sound/soundfx/soundfxlogic.cpp b/game/code/sound/soundfx/soundfxlogic.cpp
new file mode 100644
index 0000000..798d061
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxlogic.cpp
@@ -0,0 +1,322 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxlogic.cpp
+//
+// Description: Implement the SoundFXLogic class, which is an abstract
+// base class for objects that translate events into sound effects
+// in the different game states
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/soundfxlogic.h>
+
+#include <events/eventmanager.h>
+#include <events/eventdata.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+struct CreditInfo
+{
+ int lineNumber;
+ radKey32 dialogName;
+};
+
+#ifdef PAL
+ const int PAL_OFFSET = +16; // due to additional VUG localization team
+#else
+ const int PAL_OFFSET = 0;
+#endif
+
+static CreditInfo s_creditDialogTable[] =
+{
+ { 7, ::radMakeKey32( "pubcredits" ) },
+ { 55, ::radMakeKey32( "foxcredits" ) },
+ { 178 + PAL_OFFSET, ::radMakeKey32( "radproducer" ) },
+ { 190 + PAL_OFFSET, ::radMakeKey32( "radlead" ) },
+ { 204 + PAL_OFFSET, ::radMakeKey32( "raddesign" ) },
+ { 221 + PAL_OFFSET, ::radMakeKey32( "radworld" ) },
+ { 230 + PAL_OFFSET, ::radMakeKey32( "radmodel" ) },
+ { 235 + PAL_OFFSET, ::radMakeKey32( "radfx" ) },
+ { 242 + PAL_OFFSET, ::radMakeKey32( "radfmvart" ) },
+ { 251 + PAL_OFFSET, ::radMakeKey32( "radfeart" ) },
+ { 260 + PAL_OFFSET, ::radMakeKey32( "radprog" ) },
+ { 279 + PAL_OFFSET, ::radMakeKey32( "radtest" ) },
+ { 289 + PAL_OFFSET, ::radMakeKey32( "radsound" ) }
+};
+
+static int s_creditDialogTableSize = sizeof( s_creditDialogTable ) / sizeof( CreditInfo );
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundFXLogic::SoundFXLogic
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXLogic::SoundFXLogic()
+{
+ unsigned int i;
+
+ for( i = 0; i < s_numSFXPlayers; i++ )
+ {
+ m_soundPlayers[i].isKillable = true;
+ }
+}
+
+//==============================================================================
+// SoundFXLogic::~SoundFXLogic
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXLogic::~SoundFXLogic()
+{
+}
+
+//=============================================================================
+// SoundFXLogic::UnregisterEventListeners
+//=============================================================================
+// Description: Unregister all events with the Event Manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::UnregisterEventListeners()
+{
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// SoundFXLogic::GetAvailableSFXPlayer
+//=============================================================================
+// Description: Find an unused SFXPlayer. Failing that, find a killable
+// SFXPlayer. Failing that, well, just fail.
+//
+// Parameters: index - Address of unsigned int, filled in with index of
+// SFXPlayer if one is available and address is non-NULL,
+// untouched otherwise
+//
+// Return: SFXPlayer pointer if one available, NULL otherwise
+//
+//=============================================================================
+SFXPlayer* SoundFXLogic::GetAvailableSFXPlayer( unsigned int* index )
+{
+ unsigned int i;
+ int lastKillable = -1;
+
+ //
+ // First, look for free players
+ //
+ for( i = 0; i < s_numSFXPlayers; i++ )
+ {
+ if( !m_soundPlayers[i].soundPlayer.IsInUse() )
+ {
+ if( index != NULL )
+ {
+ *index = i;
+ }
+ return( &(m_soundPlayers[i]) );
+ }
+ else if( m_soundPlayers[i].isKillable )
+ {
+ lastKillable = i;
+ }
+ }
+
+ //
+ // If we get this far, all players are in use. Kill a player if we can
+ //
+ if( lastKillable != -1 )
+ {
+ if( index != NULL )
+ {
+ *index = lastKillable;
+ }
+ return( &(m_soundPlayers[lastKillable]) );
+ }
+ else
+ {
+ return( NULL );
+ }
+}
+
+//=============================================================================
+// SoundFXLogic::playSFXSound
+//=============================================================================
+// Description: Searches through the list of SFXPlayers for one that's free.
+// If one isn't found, find one that's killable. If none of them
+// are killable, eh, no sound.
+//
+// Parameters: resource - name of sound resource to play
+// killable - true if sound can be killed prematurely, false otherwise
+// useCallback - true if we set callback on playback completion,
+// false otherwise
+// index - to be filled in with index of SFXPlayer used if sound
+// played and index is non-NULL
+// trim - volume to play sound at
+// pitch - pitch to play sound at
+//
+// Return: true if sound played, false otherwise
+//
+//=============================================================================
+bool SoundFXLogic::playSFXSound( const char* resource, bool killable,
+ bool useCallback, unsigned int* index,
+ float trim, float pitch )
+{
+ SFXPlayer* player;
+ bool success = false;
+ SimpsonsSoundPlayerCallback* callbackObj = NULL;
+
+ //
+ // Get a player if possible
+ //
+ player = GetAvailableSFXPlayer( index );
+
+ if( player != NULL )
+ {
+ if( player->soundPlayer.IsInUse() )
+ {
+ player->soundPlayer.Stop();
+ }
+
+ if( useCallback )
+ {
+ callbackObj = this;
+ }
+ player->soundPlayer.PlaySound( resource, callbackObj );
+ player->soundPlayer.SetTrim( trim );
+ player->soundPlayer.SetPitch( pitch );
+ player->isKillable = killable;
+
+ success = true;
+ }
+ else
+ {
+ rDebugString( "Dropped sound effect, no player available\n" );
+ }
+
+ return( success );
+}
+
+//=============================================================================
+// SoundFXLogic::ServiceOncePerFrame
+//=============================================================================
+// Description: Does nothing. Subclasses with servicing requirements need
+// to override this function
+//
+// Parameters: elapsedTime - time elapsed since last frame
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::ServiceOncePerFrame( unsigned int elapsedTime )
+{
+}
+
+//=============================================================================
+// SoundFXLogic::OnSoundReady
+//=============================================================================
+// Description: Does nothing. Needed to pull this in to get OnPlaybackComplete
+// from SimpsonsSoundPlayer.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::OnSoundReady()
+{
+}
+
+//=============================================================================
+// SoundFXLogic::OnPlaybackComplete
+//=============================================================================
+// Description: Does nothing. Subclasses with callback requirements need
+// to override this virtual function.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::OnPlaybackComplete()
+{
+}
+
+//=============================================================================
+// SoundFXLogic::Cleanup
+//=============================================================================
+// Description: Does nothing. Subclasses with stuff to clean up override
+// this virtual function.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::Cleanup()
+{
+}
+
+//******************************************************************************
+//
+// Protected Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SoundFXLogic::playCreditLine
+//=============================================================================
+// Description: Play a credits conversation
+//
+// Parameters: lineNumber - last scrolled line number in credits text
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXLogic::playCreditLine( int lineNumber )
+{
+ int i;
+ DialogEventData data;
+
+ for( i = 0; i < s_creditDialogTableSize; i++ )
+ {
+ if( lineNumber == s_creditDialogTable[i].lineNumber )
+ {
+ data.charUID1 = tEntity::MakeUID( "kang" );
+ data.charUID2 = tEntity::MakeUID( "kodos" );
+ data.dialogName = s_creditDialogTable[i].dialogName;
+
+ GetEventManager()->TriggerEvent( EVENT_IN_GAMEPLAY_CONVERSATION, static_cast<void*>(&data) );
+ }
+ }
+}
diff --git a/game/code/sound/soundfx/soundfxlogic.h b/game/code/sound/soundfx/soundfxlogic.h
new file mode 100644
index 0000000..f5735f6
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxlogic.h
@@ -0,0 +1,91 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxlogic.h
+//
+// Description: Declaration for the SoundFXLogic class, which is an abstract
+// base class for objects that translate events into sound effects
+// in the different game states
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDFXLOGIC_H
+#define SOUNDFXLOGIC_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <events/eventlistener.h>
+#include <sound/simpsonssoundplayer.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: SFXPlayer
+//
+// Structure that maps the sound player to a flag indicating whether
+// we can kill the sound effect for something higher priority
+//
+//=============================================================================
+struct SFXPlayer
+{
+ SimpsonsSoundPlayer soundPlayer;
+ bool isKillable;
+};
+
+//=============================================================================
+//
+// Synopsis: SoundFXLogic
+//
+//=============================================================================
+
+class SoundFXLogic : public EventListener,
+ public SimpsonsSoundPlayerCallback
+{
+ public:
+ SoundFXLogic();
+ virtual ~SoundFXLogic();
+
+ virtual void RegisterEventListeners() = 0;
+ void UnregisterEventListeners();
+
+ SFXPlayer* GetAvailableSFXPlayer( unsigned int* index = NULL );
+
+ virtual void ServiceOncePerFrame( unsigned int elapsedTime );
+
+ virtual void Cleanup();
+
+ //
+ // SimpsonsSoundPlayerCallback functions
+ //
+ void OnSoundReady();
+ virtual void OnPlaybackComplete();
+
+ protected:
+ // Number of SFXPlayers
+ static const unsigned int s_numSFXPlayers = 6;
+
+ //
+ // Sound players
+ //
+ SFXPlayer m_soundPlayers[s_numSFXPlayers];
+
+ bool playSFXSound( const char* resource, bool killable, bool useCallback = false,
+ unsigned int* index = NULL, float trim = 1.0f, float pitch = 1.0f );
+
+ void playCreditLine( int lineNumber );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundFXLogic( const SoundFXLogic& original );
+ SoundFXLogic& operator=( const SoundFXLogic& rhs );
+};
+
+
+#endif // SOUNDFXLOGIC_H
+
diff --git a/game/code/sound/soundfx/soundfxpauselogic.cpp b/game/code/sound/soundfx/soundfxpauselogic.cpp
new file mode 100644
index 0000000..961996a
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxpauselogic.cpp
@@ -0,0 +1,98 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxpauselogic.cpp
+//
+// Description: Implements the SoundFXPauseLogic class, which handles
+// the translation of events into sound effects for the pause
+// menu.
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/soundfxpauselogic.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundFXPauseLogic::SoundFXPauseLogic
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXPauseLogic::SoundFXPauseLogic()
+{
+}
+
+//==============================================================================
+// SoundFXPauseLogic::~SoundFXPauseLogic
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundFXPauseLogic::~SoundFXPauseLogic()
+{
+}
+
+//=============================================================================
+// SoundFXPauseLogic::RegisterEventListeners
+//=============================================================================
+// Description: Register as listener of sound effect events with Event Manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXPauseLogic::RegisterEventListeners()
+{
+}
+
+//=============================================================================
+// SoundFXPauseLogic::HandleEvent
+//=============================================================================
+// Description: Play sound effects in response to events
+//
+// Parameters: id - Sound effect event identifier
+// pEventData - Currently unused
+//
+// Return: void
+//
+//=============================================================================
+void SoundFXPauseLogic::HandleEvent( EventEnum id, void* pEventData )
+{
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundfx/soundfxpauselogic.h b/game/code/sound/soundfx/soundfxpauselogic.h
new file mode 100644
index 0000000..5cc861f
--- /dev/null
+++ b/game/code/sound/soundfx/soundfxpauselogic.h
@@ -0,0 +1,50 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundfxpauselogic.h
+//
+// Description: Declaration for the SoundFXPauseLogic class, which handles
+// the translation of events into sound effects for the pause
+// menu.
+//
+// History: 31/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDFXPAUSELOGIC_H
+#define SOUNDFXPAUSELOGIC_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/soundfxlogic.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: SoundFXPauseLogic
+//
+//=============================================================================
+
+class SoundFXPauseLogic : public SoundFXLogic
+{
+ public:
+ SoundFXPauseLogic();
+ virtual ~SoundFXPauseLogic();
+
+ void RegisterEventListeners();
+
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundFXPauseLogic( const SoundFXPauseLogic& original );
+ SoundFXPauseLogic& operator=( const SoundFXPauseLogic& rhs );
+};
+
+
+#endif // SOUNDFXPAUSELOGIC_H
+
diff --git a/game/code/sound/soundfx/win32reverbcontroller.cpp b/game/code/sound/soundfx/win32reverbcontroller.cpp
new file mode 100644
index 0000000..8876d0d
--- /dev/null
+++ b/game/code/sound/soundfx/win32reverbcontroller.cpp
@@ -0,0 +1,127 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: win32reverbcontroller.cpp
+//
+// Description: Implementation for the Win32ReverbController class, which provides
+// the Windows-specific reverb control
+//
+// History: 03/25/2003 + Created -- Ziemek
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radsound_win32.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/win32reverbcontroller.h>
+
+#include <sound/soundfx/reverbsettings.h>
+
+#include <memory/srrmemory.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// Win32ReverbController::Win32ReverbController
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Win32ReverbController::Win32ReverbController()
+{
+ m_reverbInterface = ::radSoundHalEffectEAX2ReverbCreate( GMA_PERSISTENT );
+ m_reverbInterface->AddRef();
+
+ registerReverbEffect( m_reverbInterface );
+}
+
+//==============================================================================
+// Win32ReverbController::~Win32ReverbController
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Win32ReverbController::~Win32ReverbController()
+{
+ m_reverbInterface->Release();
+ m_reverbInterface = NULL;
+}
+
+//=============================================================================
+// Win32ReverbController::SetReverbOn
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Win32ReverbController::SetReverbOn( reverbSettings* settings )
+{
+ if( settings != NULL )
+ {
+ rReleaseString( "Settings not null\n" );
+ SetReverbGain( settings->GetGain() );
+ m_reverbInterface->SetRoom( settings->GetXboxRoom() );
+ m_reverbInterface->SetRoomHF( settings->GetXboxRoomHF() );
+ m_reverbInterface->SetRoomRolloffFactor( settings->GetXboxRoomRolloffFactor() );
+ m_reverbInterface->SetDecayTime( settings->GetXboxDecayTime() );
+ m_reverbInterface->SetDecayHFRatio( settings->GetXboxDecayHFRatio() );
+ m_reverbInterface->SetReflections( settings->GetXboxReflections() );
+ m_reverbInterface->SetReflectionsDelay( settings->GetXboxReflectionsDelay() );
+ m_reverbInterface->SetReverb( settings->GetXboxReverb() );
+ m_reverbInterface->SetReverbDelay( settings->GetXboxReverbDelay() );
+ m_reverbInterface->SetEnvironmentDiffusion( settings->GetWinEnvironmentDiffusion() );
+ m_reverbInterface->SetAirAbsorptionHF( settings->GetWinAirAbsorptionHF() );
+
+ prepareFadeSettings( settings->GetGain(), settings->GetFadeInTime(),
+ settings->GetFadeOutTime() );
+ }
+}
+
+//=============================================================================
+// Win32ReverbController::SetReverbOff
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Win32ReverbController::SetReverbOff()
+{
+ startFadeOut();
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundfx/win32reverbcontroller.h b/game/code/sound/soundfx/win32reverbcontroller.h
new file mode 100644
index 0000000..055ae84
--- /dev/null
+++ b/game/code/sound/soundfx/win32reverbcontroller.h
@@ -0,0 +1,54 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: win32reverbcontroller.h
+//
+// Description: Declaration for the Win32ReverbController class, which provides
+// the Windows-specific reverb control
+//
+// History: 03/25/2003 + Created -- Ziemek
+//
+//=============================================================================
+
+#ifndef WIN32REVERBCONTROLLER_H
+#define WIN32REVERBCONTROLLER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/reverbcontroller.h>
+
+//========================================
+// Forward References
+//========================================
+struct IRadSoundHalEffectEAX2Reverb;
+
+//=============================================================================
+//
+// Synopsis: Win32ReverbController
+//
+//=============================================================================
+
+class Win32ReverbController : public ReverbController
+{
+public:
+ Win32ReverbController();
+ virtual ~Win32ReverbController();
+
+ void SetReverbOn( reverbSettings* settings );
+ void SetReverbOff();
+
+private:
+ //Prevent wasteful constructor creation.
+ Win32ReverbController( const Win32ReverbController& original );
+ Win32ReverbController& operator=( const Win32ReverbController& rhs );
+
+ //
+ // Radsound's Win32 reverb interface
+ //
+ IRadSoundHalEffectEAX2Reverb* m_reverbInterface;
+};
+
+
+#endif // WIN32REVERBCONTROLLER_H
+
diff --git a/game/code/sound/soundfx/xboxreverbcontroller.cpp b/game/code/sound/soundfx/xboxreverbcontroller.cpp
new file mode 100644
index 0000000..599aeee
--- /dev/null
+++ b/game/code/sound/soundfx/xboxreverbcontroller.cpp
@@ -0,0 +1,127 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: xboxreverbcontroller.cpp
+//
+// Description: Implementation for the XboxReverbController class, which provides
+// the Xbox-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radsound_xbox.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundfx/xboxreverbcontroller.h>
+
+#include <sound/soundfx/reverbsettings.h>
+
+#include <memory/srrmemory.h>
+
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// XboxReverbController::XboxReverbController
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+XboxReverbController::XboxReverbController()
+{
+ m_reverbInterface = ::radSoundHalEffectI3DL2ReverbXBoxCreate( GMA_PERSISTENT );
+
+ registerReverbEffect( m_reverbInterface );
+}
+
+//==============================================================================
+// XboxReverbController::~XboxReverbController
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+XboxReverbController::~XboxReverbController()
+{
+ m_reverbInterface->Release();
+ m_reverbInterface = NULL;
+}
+
+//=============================================================================
+// XboxReverbController::SetReverbOn
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void XboxReverbController::SetReverbOn( reverbSettings* settings )
+{
+ if( settings != NULL )
+ {
+ rReleaseString( "Settings not null\n" );
+ SetReverbGain( settings->GetGain() );
+ m_reverbInterface->SetRoom( settings->GetXboxRoom() );
+ m_reverbInterface->SetRoomHF( settings->GetXboxRoomHF() );
+ m_reverbInterface->SetRoomRolloffFactor( settings->GetXboxRoomRolloffFactor() );
+ m_reverbInterface->SetDecayTime( settings->GetXboxDecayTime() );
+ m_reverbInterface->SetDecayHFRatio( settings->GetXboxDecayHFRatio() );
+ m_reverbInterface->SetReflections( settings->GetXboxReflections() );
+ m_reverbInterface->SetReflectionsDelay( settings->GetXboxReflectionsDelay() );
+ m_reverbInterface->SetReverb( settings->GetXboxReverb() );
+ m_reverbInterface->SetReverbDelay( settings->GetXboxReverbDelay() );
+ m_reverbInterface->SetDiffusion( settings->GetXboxDiffusion() );
+ m_reverbInterface->SetDensity( settings->GetXboxDensity() );
+ m_reverbInterface->SetHFReference( settings->GetXboxHFReference() );
+
+ prepareFadeSettings( settings->GetGain(), settings->GetFadeInTime(),
+ settings->GetFadeOutTime() );
+ }
+}
+
+//=============================================================================
+// XboxReverbController::SetReverbOff
+//=============================================================================
+// Description: Self-explanatory
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void XboxReverbController::SetReverbOff()
+{
+ startFadeOut();
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundfx/xboxreverbcontroller.h b/game/code/sound/soundfx/xboxreverbcontroller.h
new file mode 100644
index 0000000..5ef87f3
--- /dev/null
+++ b/game/code/sound/soundfx/xboxreverbcontroller.h
@@ -0,0 +1,54 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: xboxreverbcontroller.h
+//
+// Description: Declaration for the XboxReverbController class, which provides
+// the Xbox-specific reverb control
+//
+// History: 10/28/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef XBOXREVERBCONTROLLER_H
+#define XBOXREVERBCONTROLLER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/soundfx/reverbcontroller.h>
+
+//========================================
+// Forward References
+//========================================
+struct IRadSoundHalEffectI3DL2ReverbXBox;
+
+//=============================================================================
+//
+// Synopsis: XboxReverbController
+//
+//=============================================================================
+
+class XboxReverbController : public ReverbController
+{
+ public:
+ XboxReverbController();
+ virtual ~XboxReverbController();
+
+ void SetReverbOn( reverbSettings* settings );
+ void SetReverbOff();
+
+ private:
+ //Prevent wasteful constructor creation.
+ XboxReverbController( const XboxReverbController& original );
+ XboxReverbController& operator=( const XboxReverbController& rhs );
+
+ //
+ // Radsound's Xbox reverb interface
+ //
+ IRadSoundHalEffectI3DL2ReverbXBox* m_reverbInterface;
+};
+
+
+#endif // XBOXREVERBCONTROLLER_H
+
diff --git a/game/code/sound/soundloader.cpp b/game/code/sound/soundloader.cpp
new file mode 100644
index 0000000..f0a2c64
--- /dev/null
+++ b/game/code/sound/soundloader.cpp
@@ -0,0 +1,601 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundloader.cpp
+//
+// Description: Implement SoundLoader class, which makes sure that sounds
+// required in the game are allocated and resident in sound memory
+//
+// History: 26/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <stdio.h>
+
+#include <sound/soundloader.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+
+#include <memory/srrmemory.h>
+#include <loading/loadingmanager.h>
+#include <worldsim/redbrick/vehicle.h>
+#include <constants/vehicleenum.h>
+#include <mission/gameplaymanager.h>
+#include <events/eventmanager.h>
+#include <worldsim/character/character.h>
+
+#include <radscript.hpp>
+
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Names of sound clusters. Used so that the loading manager can tell us
+// when it's our turn to loading something. Should correspond to SoundClusterName
+// enumeration
+//
+static const char* s_clusterNames[] =
+{
+ "permanent",
+ "frontend",
+ "ingame",
+ "suburbs",
+ "downtown",
+ "seaside",
+ "level1",
+ "level2",
+ "level3",
+ "level4",
+ "level5",
+ "level6",
+ "level7",
+ "minigame",
+ "huh?",
+ "apu",
+ "bart",
+ "homer",
+ "lisa",
+ "marge",
+ "bart_v",
+ "apu_v",
+ "snake_v",
+ "homer_v",
+ "famil_v",
+ "gramp_v",
+ "cletu_v",
+ "wiggu_v",
+ "empty1",
+ "marge_v",
+ "empty2",
+ "empty3",
+ "smith_v",
+ "empty4",
+ "empty5",
+ "empty6",
+ "zombi_v",
+ "empty7",
+ "empty8",
+ "cVan",
+ "compactA",
+ "comic_v",
+ "skinn_v",
+ "cCola",
+ "cSedan",
+ "cPolice",
+ "cCellA",
+ "cCellB",
+ "cCellC",
+ "cCellD",
+ "minivanA_v",
+ "pickupA",
+ "taxiA_v",
+ "sportsA",
+ "sportsB",
+ "SUVA",
+ "wagonA",
+ "hbike_v",
+ "burns_v",
+ "honor_v",
+ "cArmor",
+ "cCurator",
+ "cHears",
+ "cKlimo",
+ "cLimo",
+ "cNerd",
+ "frink_v",
+ "cMilk",
+ "cDonut",
+ "bbman_v",
+ "bookb_v",
+ "carhom_v",
+ "elect_v",
+ "fone_v",
+ "gramR_v",
+ "moe_v",
+ "mrplo_v",
+ "otto_v",
+ "plowk_v",
+ "scorp_v",
+ "willi_v",
+ "sedanA",
+ "sedanB",
+ "cBlbart",
+ "cCube",
+ "cDuff",
+ "cNonup",
+ "lisa_v",
+ "krust_v",
+ "coffin",
+ "hallo",
+ "ship",
+ "witchcar",
+ "huska",
+ "atv_v",
+ "dune_v",
+ "hype_v",
+ "knigh_v",
+ "mono_v",
+ "oblit_v",
+ "rocke_v",
+ "ambul",
+ "burnsarm",
+ "fishtruc",
+ "garbage",
+ "icecream",
+ "istruck",
+ "nuctruck",
+ "pizza",
+ "schoolbu",
+ "votetruc",
+ "glastruc",
+ "cfire_v",
+ "cBone",
+ "redbrick"
+};
+
+static const int NumScriptNames = sizeof( s_clusterNames ) / sizeof( const char* );
+
+//
+// Indices of character namespaces for each level.
+//
+// TODO: I don't like these tables, there must be a more data-driven way to do
+// this.
+// 0 == Apu
+// 1 == Bart
+// 2 == Homer
+// 3 == Lisa
+// 4 == Marge
+//
+static unsigned int s_charNamespaceIndices[] = { 2, 1, 3, 4, 0, 1, 2, 0 };
+
+static VehicleEnum::VehicleID s_carIndices[] = { VehicleEnum::FAMIL_V,
+ VehicleEnum::HONOR_V,
+ VehicleEnum::LISA_V,
+ VehicleEnum::MARGE_V,
+ VehicleEnum::APU_V,
+ VehicleEnum::BART_V,
+ VehicleEnum::HOMER_V,
+ VehicleEnum::FAMIL_V,
+};
+
+static unsigned int s_levelIndices[] = { 0, 1, 2, 0, 1, 2, 0, 0 };
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundLoader::SoundLoader
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundLoader::SoundLoader() :
+ m_currentCluster( SC_ALWAYS_LOADED )
+{
+ unsigned int i;
+ SoundClusterName clusterIndex;
+ Sound::daSoundRenderingManager* renderingMgr = Sound::daSoundRenderingManagerGet();
+
+ for( i = 0; i < SC_MAX_CLUSTERS; i++ )
+ {
+ m_clusterList[i] = NULL;
+ }
+
+ for( clusterIndex = SC_ALWAYS_LOADED;
+ clusterIndex < SC_CHAR_APU;
+ clusterIndex = static_cast<SoundClusterName>( clusterIndex + 1 ) )
+ {
+ m_clusterList[clusterIndex] =
+ new(GMA_PERSISTENT) SoundCluster( clusterIndex,
+ renderingMgr->GetSoundNamespace() );
+ }
+
+ for( clusterIndex = SC_CHAR_APU;
+ clusterIndex < SC_CAR_BASE;
+ clusterIndex = static_cast<SoundClusterName>( clusterIndex + 1 ) )
+ {
+ m_clusterList[clusterIndex] =
+ new(GMA_PERSISTENT) SoundCluster( clusterIndex,
+ renderingMgr->GetCharacterNamespace( clusterIndex - SC_CHAR_APU ) );
+ }
+
+ for( clusterIndex = SC_CAR_BASE;
+ clusterIndex < SC_MAX_CLUSTERS;
+ clusterIndex = static_cast<SoundClusterName>( clusterIndex + 1 ) )
+ {
+ m_clusterList[clusterIndex] =
+ new(GMA_PERSISTENT) SoundCluster( clusterIndex,
+ renderingMgr->GetSoundNamespace() );
+ }
+
+ //
+ // Register event listeners
+ //
+ GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_START );
+}
+
+//==============================================================================
+// SoundLoader::~SoundLoader
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundLoader::~SoundLoader()
+{
+ unsigned int i;
+
+ for( i = 0; i < SC_MAX_CLUSTERS; i++ )
+ {
+ if( m_clusterList[i] != NULL )
+ {
+ m_clusterList[i]->Release();
+ }
+ }
+
+ GetEventManager()->RemoveAll( this );
+}
+
+//=============================================================================
+// SoundLoader::LevelLoad
+//=============================================================================
+// Description: Loads the sound cluster for a particular level
+//
+// Parameters: RenderEnums::LevelEnum level -
+// enumeration indicating the level whose sound cluster
+// is to be loaded
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::LevelLoad( RenderEnums::LevelEnum level )
+{
+ IRadNameSpace* charNamespace;
+ unsigned int levelNum;
+
+ clusterUnload( SC_FRONTEND );
+
+ queueLoad( SC_INGAME );
+
+ if( GetGameplayManager()->IsSuperSprint() )
+ {
+ queueLoad( SC_MINIGAME );
+ }
+ else
+ {
+ rAssert( level <= RenderEnums::numLevels );
+ levelNum = static_cast<unsigned int>(level);
+
+ queueLoad( static_cast<SoundClusterName>( SC_LEVEL_SUBURBS + s_levelIndices[levelNum] ) );
+ queueLoad( static_cast<SoundClusterName>( SC_CHAR_APU + s_charNamespaceIndices[levelNum] ) );
+ queueLoad( static_cast<SoundClusterName>( SC_CAR_BASE + s_carIndices[levelNum] ) );
+ queueLoad( static_cast<SoundClusterName>( SC_LEVEL1 + levelNum ) );
+
+ charNamespace = m_clusterList[SC_CHAR_APU + s_charNamespaceIndices[level]]->GetMyNamespace();
+ rAssert( charNamespace != NULL );
+
+ //
+ // We need to do this for RadTuner, since we've got duplicate names and
+ // it won't necessarily find the correct character otherwise
+ //
+ charNamespace->MoveToFront();
+ }
+}
+
+//=============================================================================
+// SoundLoader::LevelUnload
+//=============================================================================
+// Description: Unloads the sound cluster for a particular level
+//
+// Parameters: RenderEnums::LevelEnum level -
+// enumeration indicating the level whose sound cluster
+// is to be unloaded
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::LevelUnload( bool goingToFe )
+{
+ SoundClusterName clusterIndex;
+
+ //
+ // Unload everything that's not permanent
+ //
+ for( clusterIndex = SC_INGAME;
+ clusterIndex < SC_MAX_CLUSTERS;
+ clusterIndex = static_cast<SoundClusterName>( clusterIndex + 1 ) )
+ {
+ if( m_clusterList[clusterIndex]->IsLoaded() )
+ {
+ clusterUnload( clusterIndex );
+ }
+ }
+
+ if( goingToFe )
+ {
+ queueLoad( SC_FRONTEND );
+ }
+}
+
+//=============================================================================
+// SoundLoader::MissionLoad
+//=============================================================================
+// Description: Loads the sound cluster for a particular mission
+//
+// Parameters: RenderEnums::MissionEnum mission -
+// enumeration indicating the mission whose sound cluster
+// is to be loaded
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::MissionLoad( RenderEnums::MissionEnum mission )
+{
+}
+
+//=============================================================================
+// SoundLoader::MissionUnload
+//=============================================================================
+// Description: Unloads the sound cluster for a particular mission
+//
+// Parameters: RenderEnums::MissionEnum mission -
+// enumeration indicating the mission whose sound cluster
+// is to be unloaded
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::MissionUnload( RenderEnums::MissionEnum mission )
+{
+}
+
+void SoundLoader::LoadCarSound( Vehicle* theCar, bool unloadOtherCars )
+{
+ rAssert( theCar );
+
+ SoundClusterName clusterIndex;
+ SoundClusterName newCarCluster = static_cast<SoundClusterName>(SC_CAR_BASE + theCar->mVehicleID);
+ bool validCar = ( SC_CAR_BASE + theCar->mVehicleID ) < NumScriptNames;
+
+ rAssertMsg( validCar, "A new vehicle has been added that the sound system does not have a script for. Tell Esan.\n" );
+
+ //
+ // Have we loaded this car already?
+ //
+ if( !validCar || m_clusterList[newCarCluster]->IsLoaded() )
+ {
+ return;
+ }
+
+ //
+ // Unload the existing car sound
+ //
+ if( unloadOtherCars )
+ {
+ for( clusterIndex = SC_CAR_BASE;
+ clusterIndex < SC_MAX_CLUSTERS;
+ clusterIndex = static_cast<SoundClusterName>( clusterIndex + 1 ) )
+ {
+ if( m_clusterList[clusterIndex]->IsLoaded() )
+ {
+ clusterUnload( clusterIndex );
+ }
+ }
+ }
+
+ //
+ // Load the new car
+ //
+ queueLoad( newCarCluster );
+}
+
+//=============================================================================
+// SoundLoader::IsSoundLoaded
+//=============================================================================
+// Description: Indicate whether a particular sound resource has been loaded
+//
+// Parameters: soundKey - hashed name of the sound resource to look for
+//
+// Return: true if loaded, falsed otherwise
+//
+//=============================================================================
+bool SoundLoader::IsSoundLoaded( Sound::daResourceKey soundKey )
+{
+ unsigned int i;
+
+ for( i = 0; i < SC_MAX_CLUSTERS; i++ )
+ {
+ if( ( m_clusterList[i] != NULL ) && ( m_clusterList[i]->ContainsResource( soundKey ) ) )
+ {
+ return( m_clusterList[i]->IsLoaded() );
+ }
+ }
+
+ return( false );
+}
+
+//=============================================================================
+// SoundLoader::LoadClusterByName
+//=============================================================================
+// Description: Given a cluster name from the loading manager, load the
+// desired cluster
+//
+// Parameters: clusterName - text name for the cluster
+// callbackObj - loading file handler to notify on completion
+//
+// Return: true if cluster already loaded, false otherwise
+//
+//=============================================================================
+bool SoundLoader::LoadClusterByName( const char* clusterName, SoundFileHandler* callbackObj )
+{
+ const char* shortName;
+ unsigned int i;
+
+ // Strip out the "sound:" prefix
+ rAssert( strlen( clusterName ) > 6 );
+ shortName = &(clusterName[6]);
+
+ //
+ // Find the matching cluster name
+ //
+ for( i = 0; i < SC_MAX_CLUSTERS; i++ )
+ {
+ if( strcmp( shortName, s_clusterNames[i] ) == 0 )
+ {
+ return( clusterLoad( static_cast<SoundClusterName>( i ), callbackObj ) );
+ }
+ }
+
+ //
+ // If we get here, cluster not found
+ //
+ rAssert( false );
+ return( false );
+}
+
+//=============================================================================
+// SoundLoader::HandleEvent
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( EventEnum id, void* pEventData )
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::HandleEvent( EventEnum id, void* pEventData )
+{
+ Character* theCharacter;
+ Vehicle* theCar;
+
+ switch( id )
+ {
+ case EVENT_GETINTOVEHICLE_START:
+ //
+ // Make sure we've got the correct car sound for this vehicle
+ //
+ theCharacter = static_cast<Character*>(pEventData);
+ rAssert( theCharacter != NULL );
+ theCar = theCharacter->GetTargetVehicle();
+ rAssert( theCar != NULL );
+
+ LoadCarSound( theCar, true );
+ break;
+
+ default:
+ rAssert( false );
+ break;
+ }
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// SoundLoader::queueLoad
+//=============================================================================
+// Description: Queue a cluster load with the loading manager
+//
+// Parameters: cluster - name of cluster to queue
+//
+// Return: void
+//
+//=============================================================================
+void SoundLoader::queueLoad( SoundClusterName cluster )
+{
+ char fakeFilename[50];
+
+ //
+ // Create a pseudo filename that we'll give to the loading manager.
+ // Content doesn't really matter, we'll just throw it out when the
+ // loading manager passes it back
+ //
+ if( cluster >= NumScriptNames )
+ {
+ //
+ // Just load Bart for now
+ //
+ cluster = SC_CAR_BASE;
+ }
+
+ sprintf( fakeFilename, "sound:%s", s_clusterNames[cluster] );
+ GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, fakeFilename, GMA_LEVEL_AUDIO );
+}
+
+//=============================================================================
+// SoundLoader::clusterLoad
+//=============================================================================
+// Description: Find the specified sound cluster and direct it to load sounds
+//
+// Parameters: SoundClusterName name - specifies which cluster to load
+//
+// Return: false if cluster not yet loaded, true otherwise
+//
+//=============================================================================
+bool SoundLoader::clusterLoad( SoundClusterName name, SoundFileHandler* callbackObj )
+{
+ bool loaded;
+
+ rAssert( name < SC_MAX_CLUSTERS );
+
+ loaded = m_clusterList[name]->IsLoaded();
+ if( !loaded )
+ {
+ m_clusterList[name]->LoadSounds( callbackObj );
+ }
+
+ return( loaded );
+}
+
+void SoundLoader::clusterUnload( SoundClusterName name )
+{
+ rAssert( name < SC_MAX_CLUSTERS );
+ if( m_clusterList[name]->IsLoaded() )
+ {
+ m_clusterList[name]->UnloadSounds();
+ }
+} \ No newline at end of file
diff --git a/game/code/sound/soundloader.h b/game/code/sound/soundloader.h
new file mode 100644
index 0000000..fad45fe
--- /dev/null
+++ b/game/code/sound/soundloader.h
@@ -0,0 +1,98 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundloader.h
+//
+// Description: Declaration for the SoundLoader class, used to manage the loading
+// and unloading of sound clips and streams.
+//
+// History: 25/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDLOADER_H
+#define SOUNDLOADER_H
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <render/Enums/RenderEnums.h>
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundclusternameenum.h>
+#include <sound/soundcluster.h>
+#include <events/eventlistener.h>
+
+//========================================
+// Forward References
+//========================================
+
+class SoundFileHandler;
+class Vehicle;
+
+//=============================================================================
+//
+// Synopsis: SoundLoader class declaration
+//
+//=============================================================================
+
+class SoundLoader : public EventListener
+{
+ public:
+ SoundLoader();
+ virtual ~SoundLoader();
+
+ bool LoadClusterByName( const char* clusterName, SoundFileHandler* callbackObj );
+
+ void LoadPermanentSounds() { queueLoad( SC_ALWAYS_LOADED ); }
+
+ void LevelLoad( RenderEnums::LevelEnum level );
+ void LevelUnload( bool goingToFe );
+
+ void MissionLoad( RenderEnums::MissionEnum mission );
+ void MissionUnload( RenderEnums::MissionEnum mission );
+
+ void LoadFrontEnd() { queueLoad( SC_FRONTEND ); }
+ void UnloadFrontEnd() { clusterUnload( SC_FRONTEND ); }
+
+ void LoadCarSound( Vehicle* theCar, bool unloadOtherCars );
+
+ bool IsSoundLoaded( Sound::daResourceKey soundKey );
+
+ void SetCurrentCluster( SoundClusterName cluster )
+ { rAssert( cluster != SC_MAX_CLUSTERS ); m_currentCluster = cluster; }
+ bool AddResourceToCurrentCluster( const char* resourceName )
+ { return( m_clusterList[m_currentCluster]->AddResource( resourceName ) ); }
+
+ //
+ // EventListener functions
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundLoader( const SoundLoader& original );
+ SoundLoader& operator=( const SoundLoader& rhs );
+
+ //
+ // Queue a load with the loading manager
+ //
+ void queueLoad( SoundClusterName cluster );
+
+ bool clusterLoad( SoundClusterName name, SoundFileHandler* callbackObj = NULL );
+ void clusterUnload( SoundClusterName name );
+
+ //
+ // List of clusters, each holding list of loadable sounds
+ //
+ SoundCluster* m_clusterList[SC_MAX_CLUSTERS];
+
+ //
+ // Cluster that any created sound resources will be added to
+ //
+ SoundClusterName m_currentCluster;
+};
+
+
+#endif // SOUNDLOADER_H
+
diff --git a/game/code/sound/soundmanager.cpp b/game/code/sound/soundmanager.cpp
new file mode 100644
index 0000000..5fea9cc
--- /dev/null
+++ b/game/code/sound/soundmanager.cpp
@@ -0,0 +1,2193 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundmanager.cpp
+//
+// Description: Manager interface that the other game components use to
+// interact with sound.
+//
+// History: 01/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <radfactory.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundmanager.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundnucleus.hpp>
+
+#include <sound/music/musicplayer.h>
+#include <sound/dialog/dialogcoordinator.h>
+#include <sound/dialog/dialogline.h>
+#include <sound/tuning/globalsettings.h>
+#include <sound/soundfx/soundeffectplayer.h>
+#include <sound/soundfx/reverbsettings.h>
+#include <sound/soundfx/positionalsoundsettings.h>
+#include <sound/movingpositional/movingsoundmanager.h>
+#include <sound/sounddebug/sounddebugdisplay.h>
+
+#include <loading/loadingmanager.h>
+#include <loading/soundfilehandler.h>
+
+#include <memory/srrmemory.h>
+#include <mission/gameplaymanager.h>
+#include <events/eventmanager.h>
+#include <data/gamedatamanager.h>
+#include <interiors/interiormanager.h>
+#include <gameflow/gameflow.h>
+#include <worldsim/avatarmanager.h>
+
+#include <string.h>
+
+#ifdef RAD_GAMECUBE
+#include <dolphin/os.h>
+#endif
+
+#ifdef RAD_WIN32
+#include <data/config/gameconfigmanager.h>
+#endif
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+// Static pointer to instance of singleton.
+SoundManager* SoundManager::spInstance = NULL;
+
+//
+// Sound file extensions
+//
+const char* RADSCRIPT_TYPE_INFO_FILE = "typ";
+const char* RADSCRIPT_SCRIPT_FILE = "spt";
+const char* RADMUSIC_SCRIPT_FILE = "rms";
+
+//
+// Sound mode flags, necessary because it's too late in the project
+// to turn the boolean used to save the sound mode into an enumeration.
+// Doh.
+//
+static const int SOUND_MODE_STEREO_FLAG = 1;
+static const int SOUND_MODE_SURROUND_FLAG = 1 << 1;
+
+static unsigned int gLastServiceTime;
+static unsigned int gLastServiceOncePerFrameTime;
+
+static const unsigned int BAD_SERVICE_TIME = 100;
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundManager::CreateInstance
+//==============================================================================
+//
+// Description: Creates the SoundManager.
+//
+// Parameters: None.
+//
+// Return: Pointer to the SoundManager.
+//
+// Constraints: This is a singleton so only one instance is allowed.
+//
+//==============================================================================
+SoundManager* SoundManager::CreateInstance( bool muteSound, bool noMusic,
+ bool noEffects, bool noDialogue )
+{
+ MEMTRACK_PUSH_GROUP( "Sound" );
+
+ rAssert( spInstance == NULL );
+
+ spInstance = new(GMA_PERSISTENT) SoundManager( muteSound, noMusic, noEffects, noDialogue );
+ rAssert( spInstance );
+
+ spInstance->initialize();
+
+ MEMTRACK_POP_GROUP( "Sound" );
+
+ return spInstance;
+}
+
+//==============================================================================
+// SoundManager::GetInstance
+//==============================================================================
+//
+// Description: - Access point for the SoundManager singleton.
+//
+// Parameters: None.
+//
+// Return: Pointer to the SoundManager.
+//
+// Constraints: This is a singleton so only one instance is allowed.
+//
+//==============================================================================
+SoundManager* SoundManager::GetInstance()
+{
+ rAssert( spInstance != NULL );
+
+ return spInstance;
+}
+
+
+//==============================================================================
+// SoundManager::DestroyInstance
+//==============================================================================
+//
+// Description: Destroy the SoundManager.
+//
+// Parameters: None.
+//
+// Return: None.
+//
+//==============================================================================
+void SoundManager::DestroyInstance()
+{
+ rAssert( spInstance != NULL );
+
+ delete( GMA_PERSISTENT, spInstance );
+ spInstance = NULL;
+}
+
+//==============================================================================
+// SoundManager::Update
+//==============================================================================
+//
+// Description: Update the sound renderer. This should be done as frequently
+// as possible.
+//
+// Parameters: None.
+//
+// Return: None.
+//
+//==============================================================================
+void SoundManager::Update()
+{
+ unsigned int now = radTimeGetMilliseconds( );
+ unsigned int dif = now - gLastServiceTime;
+
+ if ( dif > BAD_SERVICE_TIME )
+ {
+ #ifndef RAD_DEBUG
+ rReleasePrintf( "\nAUDIO: Detected Service Lag:[%d]ms -- this could cause skipping\n\n", dif );
+ #endif
+ }
+
+ gLastServiceTime = now;
+
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_musicPlayer->Service();
+
+ rAssert( m_pSoundRenderMgr != NULL );
+ m_pSoundRenderMgr->Service();
+}
+
+//==============================================================================
+// SoundManager::UpdateOncePerFrame
+//==============================================================================
+//
+// Description: Update the sound renderer's expensive, can-do-once-per-frame
+// stuff (e.g. positional sound info).
+//
+// Parameters: None.
+//
+// Return: None.
+//
+//==============================================================================
+void SoundManager::UpdateOncePerFrame( unsigned int elapsedTime, ContextEnum context, bool useContext, bool isPausedForErrors )
+{
+
+ unsigned int now = radTimeGetMilliseconds( );
+ unsigned int dif = now - gLastServiceOncePerFrameTime;
+
+ if ( dif > BAD_SERVICE_TIME )
+ {
+ #ifndef RAD_DEBUG
+ rReleasePrintf( "\nAUDIO: Detected ServiceOpf Lag:[%d]ms -- this could cause skipping\n\n", dif );
+ #endif
+ }
+
+ gLastServiceOncePerFrameTime = now;
+
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+ m_pSoundRenderMgr->ServiceOncePerFrame( elapsedTime );
+ m_soundFXPlayer->ServiceOncePerFrame( elapsedTime );
+ m_movingSoundManager->ServiceOncePerFrame();
+
+ if( !isPausedForErrors )
+ {
+ //
+ // If we've paused the players, don't update this thing because it could
+ // start up new sounds
+ //
+ m_avatarSoundPlayer.UpdateOncePerFrame( elapsedTime );
+ }
+
+ //
+ // No point in updating listener position more than once per frame
+ //
+ if( useContext )
+ {
+ m_listener.Update( context );
+ }
+
+ //
+ // The dialog queue timer list isn't that time-sensitive, once per frame
+ // should be fine
+ //
+ if( m_dialogCoordinator != NULL )
+ {
+ m_dialogCoordinator->ServiceOncePerFrame();
+ }
+}
+
+//=============================================================================
+// SoundManager::HandleEvent
+//=============================================================================
+// Description: Handle any events that the underlying systems won't do
+// during mute.
+//
+// Parameters: id - ID of event to be handled
+// pEventData - user data for event
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::HandleEvent( EventEnum id, void* pEventData )
+{
+ switch( id )
+ {
+ case EVENT_CONVERSATION_SKIP:
+ //
+ // We only get this in mute mode. Nothing to stop, signal that we're done
+ //
+ GetEventManager()->TriggerEvent( EVENT_CONVERSATION_DONE );
+ break;
+ case EVENT_CONVERSATION_START:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_LETTERBOX, NULL, false );
+ break;
+ case EVENT_CONVERSATION_DONE:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_LETTERBOX, NULL, true );
+ break;
+ case EVENT_GETINTOVEHICLE_END:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_ONFOOT, NULL, true );
+ break;
+ case EVENT_GETOUTOFVEHICLE_END:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_ONFOOT, NULL, false );
+ break;
+ case EVENT_ENTER_INTERIOR_START:
+ case EVENT_EXIT_INTERIOR_START:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_JUST_MUSIC, NULL, false );
+ break;
+ case EVENT_ENTER_INTERIOR_END:
+ case EVENT_EXIT_INTERIOR_END:
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_JUST_MUSIC, NULL, true );
+ break;
+
+ case EVENT_MISSION_RESET:
+ //
+ // D'oh! Problem: if you fail a mission just as you're trying to go into an interior, you never
+ // get the enter/exit_interior_end event. However, we will be getting a mission reset in this
+ // case, so bring up the volume just in case.
+ //
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_JUST_MUSIC, NULL, true );
+
+ //
+ // Fall through to case below
+ //
+
+ case EVENT_CHARACTER_POS_RESET:
+ case EVENT_VEHICLE_DESTROYED_SYNC_SOUND:
+ if( GetAvatarManager()->GetAvatarForPlayer( 0 )->IsInCar() )
+ {
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_ONFOOT, NULL, true );
+ }
+ else
+ {
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_ONFOOT, NULL, false );
+ }
+ break;
+
+ case EVENT_FE_MENU_SELECT:
+ playStartupAcceptSound();
+ break;
+
+ case EVENT_FE_MENU_UPORDOWN:
+ playStartupScrollSound();
+ break;
+
+ default:
+ rAssertMsg( false, "Huh? SoundManager getting events it shouldn't\n" );
+ break;
+ }
+}
+
+//=============================================================================
+// SoundManager::OnBootupStart
+//=============================================================================
+// Description: Called when bootup context started
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnBootupStart()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ //
+ // Load the RadScript and RadMusic files
+ //
+ m_pSoundRenderMgr->QueueCementFileRegistration();
+ m_musicPlayer->QueueRadmusicScriptLoad();
+ m_pSoundRenderMgr->QueueRadscriptFileLoads();
+
+ //
+ // Load front end sounds
+ //
+ m_soundLoader->LoadFrontEnd();
+}
+
+//=============================================================================
+// SoundManager::OnBootupComplete
+//=============================================================================
+// Description: Initialize the dialog system once the scripts are known to
+// have been loaded
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnBootupComplete()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ dumpStartupSounds();
+
+ // Set up the tuner
+ m_pSoundRenderMgr->GetTuner()->PostScriptLoadInitialize();
+
+ //
+ // If the sound levels haven't been auto-loaded, set them now
+ //
+ if( !( GetGameDataManager()->IsGameLoaded() ) )
+ {
+ ResetData();
+ }
+ else
+ {
+ //
+ // Hack! If we've loaded sound volumes before we had the scripts loaded,
+ // then we wouldn't have been able to calculate the ambience volumes properly.
+ // Fix those up now.
+ //
+ SetAmbienceVolume( GetCalculatedAmbienceVolume() );
+ }
+}
+
+//=============================================================================
+// SoundManager::QueueLevelSoundLoads
+//=============================================================================
+// Description: Prepare to load level-related sound through the loading manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::QueueLevelSoundLoads()
+{
+ RenderEnums::LevelEnum level;
+
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ level = GetGameplayManager()->GetCurrentLevelIndex();
+ m_soundLoader->LevelLoad( level );
+ m_musicPlayer->QueueMusicLevelLoad( level );
+}
+
+//=============================================================================
+// SoundManager::ResetDucking
+//=============================================================================
+// Description: Bring all the volume levels back up
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::ResetDucking()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+ m_pSoundRenderMgr->GetTuner()->ResetDuck();
+}
+
+//=============================================================================
+// SoundManager::OnFrontEndStart
+//=============================================================================
+// Description: To be called when front end starts, so we can do initialization
+// stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnFrontEndStart()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ //
+ // Start loading the permanent, always-in-memory stuff
+ //
+ m_soundLoader->LoadPermanentSounds();
+
+ m_musicPlayer->OnFrontEndStart();
+ m_soundFXPlayer->OnFrontEndStart();
+}
+
+//=============================================================================
+// SoundManager::OnFrontEndEnd
+//=============================================================================
+// Description: To be called when front end ends, so we can do destruction
+// stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnFrontEndEnd()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_musicPlayer->OnFrontEndFinish();
+}
+
+//=============================================================================
+// SoundManager::OnGameplayStart
+//=============================================================================
+// Description: To be called when gameplay starts, so we can do initialization
+// stuff
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnGameplayStart()
+{
+ bool playerInCar;
+
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ //
+ // Pass on start notice
+ //
+ playerInCar = m_avatarSoundPlayer.OnBeginGameplay();
+ m_musicPlayer->OnGameplayStart( playerInCar );
+ m_soundFXPlayer->OnGameplayStart();
+
+ //
+ // Assume we're starting gameplay on foot, except for minigame. Start the ducking
+ //
+ if( GetGameplayManager()->IsSuperSprint() )
+ {
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_MINIGAME, NULL, false );
+ }
+ else
+ {
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_ONFOOT, NULL, false );
+ }
+}
+
+//=============================================================================
+// SoundManager::OnGameplayEnd
+//=============================================================================
+// Description: To be called when gameplay ends, so we can do destruction
+// stuff
+//
+// Parameters: goingToFE - indicates whether we're exiting gameplay to go
+// to the front end (as opposed to loading a different
+// level)
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnGameplayEnd( bool goingToFE )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_avatarSoundPlayer.OnEndGameplay();
+ m_musicPlayer->OnGameplayFinish();
+ m_dialogCoordinator->OnGameplayEnd();
+ m_soundFXPlayer->OnGameplayEnd();
+
+ m_soundLoader->LevelUnload( goingToFE );
+ m_musicPlayer->UnloadRadmusicScript();
+
+ //
+ // Set up for the front end
+ //
+ if( goingToFE )
+ {
+ m_musicPlayer->QueueMusicLevelLoad( RenderEnums::L3 );
+ }
+}
+
+//=============================================================================
+// SoundManager::OnPauseStart
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnPauseStart()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_PAUSE, NULL, false );
+
+ m_musicPlayer->OnPauseStart();
+ m_dialogCoordinator->OnPauseStart();
+ m_soundFXPlayer->OnPauseStart();
+ m_NISPlayer->PauseAllNISPlayers();
+
+ GetEventManager()->TriggerEvent( EVENT_FE_PAUSE_MENU_START );
+}
+
+//=============================================================================
+// SoundManager::OnPauseEnd
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnPauseEnd()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_PAUSE, NULL, true );
+
+ m_musicPlayer->OnPauseEnd();
+ m_dialogCoordinator->OnPauseEnd();
+ m_soundFXPlayer->OnPauseEnd();
+ m_NISPlayer->ContinueAllNISPlayers();
+
+ GetEventManager()->TriggerEvent( EVENT_FE_PAUSE_MENU_END );
+}
+
+//=============================================================================
+// SoundManager::OnStoreScreenStart
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnStoreScreenStart( bool playMusic )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_STORE, NULL, false );
+
+ if( playMusic )
+ {
+ m_musicPlayer->OnStoreStart();
+ }
+}
+
+//=============================================================================
+// SoundManager::OnStoreScreenEnd
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnStoreScreenEnd()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_STORE, NULL, true );
+
+ m_musicPlayer->OnStoreEnd();
+}
+
+//=============================================================================
+// SoundManager::DuckEverythingButMusicBegin
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::DuckEverythingButMusicBegin( bool playMuzak )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_JUST_MUSIC, NULL, false );
+
+ if( playMuzak )
+ {
+ m_musicPlayer->OnStoreStart();
+ }
+}
+
+//=============================================================================
+// SoundManager::DuckEverythingButMusicEnd
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::DuckEverythingButMusicEnd( bool playMuzak )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_JUST_MUSIC, NULL, true );
+
+ if( playMuzak )
+ {
+ m_musicPlayer->OnStoreEnd();
+ }
+}
+
+//=============================================================================
+// SoundManager::OnMissionBriefingStart
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnMissionBriefingStart()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_MISSION, NULL, false );
+ m_NISPlayer->PauseAllNISPlayers();
+}
+
+//=============================================================================
+// SoundManager::OnMissionBriefingEnd
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::OnMissionBriefingEnd()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_MISSION, NULL, true );
+ m_NISPlayer->ContinueAllNISPlayers();
+}
+
+//=============================================================================
+// SoundManager::DuckForInGameCredits
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::DuckForInGameCredits()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_pSoundRenderMgr->GetTuner()->ActivateSituationalDuck( NULL, Sound::DUCK_SIT_CREDITS, NULL, false );
+}
+
+//=============================================================================
+// SoundManager::LoadSoundFile
+//=============================================================================
+// Description: Pass on the file loading directive to the appropriate subsystem,
+// with callback object for the sake of the loading manager
+//
+// Parameters: filename - name of file to load
+// callbackObj - callback into loading system when complete
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::LoadSoundFile( const char* filename, SoundFileHandler* callbackObj )
+{
+ char fileExtension[4];
+ int length = strlen( filename );
+
+ //
+ // Determine the appropriate sound subsystem by the file extension
+ //
+ rAssert( length > 4 );
+ if( filename[length - 4] == '.' )
+ {
+ strcpy( fileExtension, &(filename[strlen(filename) - 3]) );
+
+ if( strcmp( fileExtension, RADSCRIPT_TYPE_INFO_FILE ) == 0 )
+ {
+ m_pSoundRenderMgr->LoadTypeInfoFile( filename, callbackObj );
+ }
+ else if( strcmp( fileExtension, RADSCRIPT_SCRIPT_FILE ) == 0 )
+ {
+ m_pSoundRenderMgr->LoadScriptFile( filename, callbackObj );
+ }
+ else if( strcmp( fileExtension, RADMUSIC_SCRIPT_FILE ) == 0 )
+ {
+ m_musicPlayer->LoadRadmusicScript( filename, callbackObj );
+ }
+ else
+ {
+ //
+ // Oops, don't recognize that type
+ //
+ rAssert( false );
+ }
+ }
+ else
+ {
+ //
+ // No file extension, must be a sound cluster name
+ //
+ if( m_soundLoader->LoadClusterByName( filename, callbackObj ) )
+ {
+ //
+ // LoadClusterByName indicated that the cluster was already loaded,
+ // so call the callback
+ //
+ callbackObj->LoadCompleted();
+ }
+ }
+}
+
+//=============================================================================
+// SoundManager::LoadCarSound
+//=============================================================================
+// Description: Load car sound. Duh.
+//
+// Parameters: theCar - vehicle whose sound is to be loaded
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::LoadCarSound( Vehicle* theCar, bool unloadOtherCars )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_soundLoader->LoadCarSound( theCar, unloadOtherCars );
+}
+
+//=============================================================================
+// SoundManager::GetMasterVolume
+//=============================================================================
+// Description: Get master volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetMasterVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetMasterVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetMasterVolume
+//=============================================================================
+// Description: Set master volume
+//
+// Parameters: volume - new master volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetMasterVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetMasterVolume( volume );
+
+ //
+ // Stinky special cases. This must be fixed.
+ //
+ /*if ( m_musicPlayer )
+ {
+ m_musicPlayer->SetVolume( volume * m_pSoundRenderMgr->GetTuner()->GetMusicVolume() );
+ m_musicPlayer->SetAmbienceVolume( volume * m_pSoundRenderMgr->GetTuner()->GetAmbienceVolume() );
+ }*/
+}
+
+//=============================================================================
+// SoundManager::GetSfxVolume
+//=============================================================================
+// Description: Get sound effect volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetSfxVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetSfxVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetSfxVolume
+//=============================================================================
+// Description: Set sound effect volume
+//
+// Parameters: volume - new sound effect volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetSfxVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetSfxVolume( volume );
+}
+
+//=============================================================================
+// SoundManager::GetCarVolume
+//=============================================================================
+// Description: Get sound effect volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetCarVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetCarVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetCarVolume
+//=============================================================================
+// Description: Set sound effect volume
+//
+// Parameters: volume - new sound effect volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetCarVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetCarVolume( volume );
+}
+
+//=============================================================================
+// SoundManager::GetMusicVolume
+//=============================================================================
+// Description: Get music volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetMusicVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ //rAssert( m_musicPlayer->GetVolume() == m_pSoundRenderMgr->GetTuner()->GetMusicVolume() );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetMusicVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetMusicVolume
+//=============================================================================
+// Description: Set music volume
+//
+// Parameters: volume - new music volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetMusicVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetMusicVolume( volume );
+
+ //
+ // Sadly, we have to deal with the music player outside of the tuner. The
+ // daSound layer doesn't do our interactive music, so volume is controlled
+ // separately.
+ //
+ //rAssert( m_musicPlayer != NULL );
+ //m_musicPlayer->SetVolume( volume * m_pSoundRenderMgr->GetTuner()->GetMasterVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetMusicVolumeWithoutTuner
+//=============================================================================
+// Description: Set music volume without affecting the tuner's internally
+// stored volume setting
+//
+// Parameters: volume - new music volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetMusicVolumeWithoutTuner( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_musicPlayer != NULL );
+ m_musicPlayer->SetVolume( volume * m_pSoundRenderMgr->GetTuner()->GetMasterVolume() );
+}
+
+//=============================================================================
+// SoundManager::GetAmbienceVolume
+//=============================================================================
+// Description: Get ambience volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetAmbienceVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+#ifdef RAD_WIN32
+ m_musicPlayer->SetAmbienceVolume( m_pSoundRenderMgr->GetTuner()->GetAmbienceVolume() );
+#endif
+
+ rAssert( m_musicPlayer->GetAmbienceVolume() == m_pSoundRenderMgr->GetTuner()->GetAmbienceVolume() );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetAmbienceVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetAmbienceVolume
+//=============================================================================
+// Description: Set ambience volume
+//
+// Parameters: volume - new music volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetAmbienceVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetAmbienceVolume( volume );
+
+ //
+ // Sadly, we have to deal with the ambience player outside of the tuner. The
+ // daSound layer doesn't do our interactive music, so volume is controlled
+ // separately.
+ //
+ rAssert( m_musicPlayer != NULL );
+ m_musicPlayer->SetAmbienceVolume( volume * m_pSoundRenderMgr->GetTuner()->GetMasterVolume() );
+}
+
+//=============================================================================
+// SoundManager::SetAmbienceVolumeWithoutTuner
+//=============================================================================
+// Description: Set ambience volume without affecting the tuner's internally
+// stored volume setting
+//
+// Parameters: volume - new music volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetAmbienceVolumeWithoutTuner( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_musicPlayer != NULL );
+ m_musicPlayer->SetAmbienceVolume( volume * m_pSoundRenderMgr->GetTuner()->GetMasterVolume() );
+}
+
+//=============================================================================
+// SoundManager::GetCalculatedAmbienceVolume
+//=============================================================================
+// Description: Hack!! Used to figure out what the ambience volume should
+// be based on the sfx volume, to tie it to the effect slider.
+//
+// Parameters: None
+//
+// Return: float
+//
+//=============================================================================
+float SoundManager::GetCalculatedAmbienceVolume()
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ globalSettings* settings;
+ float ratio;
+ float newVolume;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ if(!nameSpace)
+ {
+ return( -1.0f );
+ }
+ nameSpaceObj = nameSpace->GetInstance( "tuner" );
+ if(!nameSpaceObj)
+ {
+ return( -1.0f );
+ }
+
+ settings = static_cast<globalSettings*>( nameSpaceObj );
+ ratio = GetSfxVolume() / settings->GetSfxVolume();
+
+ newVolume = ratio * settings->GetAmbienceVolume();
+ if( newVolume < 0.0f )
+ {
+ newVolume = 0.0f;
+ }
+ else if( newVolume > 1.0f )
+ {
+ newVolume = 1.0f;
+ }
+
+ return( newVolume );
+}
+
+//=============================================================================
+// SoundManager::GetDialogueVolume
+//=============================================================================
+// Description: Get dialogue volume
+//
+// Parameters: None
+//
+// Return: Volume setting from 0.0f to 1.0f
+//
+//=============================================================================
+float SoundManager::GetDialogueVolume()
+{
+ if( m_isMuted )
+ {
+ return( 0.0f );
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ return( m_pSoundRenderMgr->GetTuner()->GetDialogueVolume() );
+}
+
+//=============================================================================
+// SoundManager::DebugRender
+//=============================================================================
+// Description: Display the sound debug info
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::DebugRender()
+{
+ m_debugDisplay->Render();
+}
+
+//=============================================================================
+// SoundManager::SetDialogueVolume
+//=============================================================================
+// Description: Set dialogue volume
+//
+// Parameters: volume - new dialog volume
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetDialogueVolume( float volume )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->GetTuner()->SetDialogueVolume( volume );
+}
+
+//=============================================================================
+// SoundManager::PlayCarOptionMenuStinger
+//=============================================================================
+// Description: Play option menu sound for car slider
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::PlayCarOptionMenuStinger()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_soundFXPlayer->PlayCarOptionStinger( GetCarVolume() );
+}
+
+//=============================================================================
+// SoundManager::PlayDialogueOptionMenuStinger
+//=============================================================================
+// Description: Play option menu sound for dialogue slider
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::PlayDialogueOptionMenuStinger()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_soundFXPlayer->PlayDialogOptionStinger( GetDialogueVolume() );
+}
+
+//=============================================================================
+// SoundManager::PlayMusicOptionMenuStinger
+//=============================================================================
+// Description: Play option menu sound for music slider
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::PlayMusicOptionMenuStinger()
+{
+ //
+ // Music is special. We're already playing music in the front end,
+ // so we don't need to play a stinger there. We need it in game,
+ // though.
+ //
+ if( m_isMuted || ( GetGameFlow()->GetCurrentContext() == CONTEXT_FRONTEND ) )
+ {
+ return;
+ }
+
+ m_soundFXPlayer->PlayMusicOptionStinger( GetMusicVolume() );
+}
+
+//=============================================================================
+// SoundManager::PlaySfxOptionMenuStinger
+//=============================================================================
+// Description: Play option menu sound for sfx slider
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::PlaySfxOptionMenuStinger()
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_soundFXPlayer->PlaySfxOptionStinger( GetSfxVolume() );
+}
+
+void SoundManager::LoadNISSound( radKey32 NISSoundID, NISSoundLoadedCallback* callback )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_NISPlayer->LoadNISSound( NISSoundID, callback );
+}
+
+void SoundManager::PlayNISSound( radKey32 NISSoundID, rmt::Box3D* boundingBox, NISSoundPlaybackCompleteCallback* callback )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_NISPlayer->PlayNISSound( NISSoundID, boundingBox, callback );
+}
+
+void SoundManager::StopAndDumpNISSound( radKey32 NISSoundID )
+{
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_NISPlayer->StopAndDumpNISSound( NISSoundID );
+}
+
+//=============================================================================
+// SoundManager::StopForMovie
+//=============================================================================
+// Description: To be called when we want to stop the action for an FMV
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::StopForMovie()
+{
+ if ( !m_stoppedForMovie )
+ {
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ //
+ // Shut the works down
+ //
+ m_musicPlayer->StopForMovie();
+ GetInteriorManager()->UnloadGagSounds();
+ m_pSoundRenderMgr->GetPlayerManager()->PausePlayers();
+ m_stoppedForMovie = true;
+ }
+}
+
+//=============================================================================
+// SoundManager::ResumeAfterMovie
+//=============================================================================
+// Description: Call this to start everything up again after an FMV
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::ResumeAfterMovie()
+{
+ if ( m_stoppedForMovie )
+ {
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ m_musicPlayer->ResumeAfterMovie();
+ m_pSoundRenderMgr->GetPlayerManager()->ContinuePlayers();
+ m_stoppedForMovie = false;
+ }
+}
+
+//=============================================================================
+// SoundManager::IsStoppedForMovie
+//=============================================================================
+
+bool SoundManager::IsStoppedForMovie()
+{
+ if( m_isMuted )
+ {
+ return true;
+ }
+ else
+ {
+ return ( m_stoppedForMovie
+ && m_musicPlayer->IsStoppedForMovie()
+ && m_pSoundRenderMgr->GetPlayerManager()->AreAllPlayersStopped() );
+ }
+}
+
+//=============================================================================
+// SoundManager::MuteNISPlayers
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::MuteNISPlayers()
+{
+ m_pSoundRenderMgr->GetTuner()->MuteNIS();
+}
+
+//=============================================================================
+// SoundManager::UnmuteNISPlayers
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::UnmuteNISPlayers()
+{
+ m_pSoundRenderMgr->GetTuner()->UnmuteNIS();
+}
+
+//=============================================================================
+// SoundManager::RestartSupersprintMusic
+//=============================================================================
+// Description: Give the supersprint music a kick
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::RestartSupersprintMusic()
+{
+ m_musicPlayer->RestartSupersprintMusic();
+}
+
+//=============================================================================
+// SoundManager::GetBeatValue
+//=============================================================================
+// Description: Pass on the beat from the music player
+//
+// Parameters: None
+//
+// Return: float from 0.0f to 4.0f
+//
+//=============================================================================
+float SoundManager::GetBeatValue()
+{
+ rAssert( m_musicPlayer != NULL );
+
+ return( m_musicPlayer->GetBeatValue() );
+}
+
+//=============================================================================
+// SoundManager::IsFoodCharacter
+//=============================================================================
+// Description: Determine whether this character gets Askfood lines or
+// Idlereply
+//
+// Parameters: theGuy - ambient character being talked to
+//
+// Return: true for Askfood, false for Idlereply
+//
+//=============================================================================
+bool SoundManager::IsFoodCharacter( Character* theGuy )
+{
+ return( DialogLine::IsFoodCharacter( theGuy ) );
+}
+
+//=============================================================================
+// SoundManager::SetDialogueLanguage
+//=============================================================================
+// Description: Switch the current cement file for dialogue to match the
+// given language.
+//
+// Parameters: language - new language to use
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SetDialogueLanguage( Scrooby::XLLanguage language )
+{
+ // TODO: Commented out to get PAL working for alpha. It's basically a no-op anyway until we get localized dialogue. --jdy
+ m_pSoundRenderMgr->SetLanguage( language );
+}
+
+//=============================================================================
+// SoundManager::LoadData
+//=============================================================================
+// Description: Load sound settings (from saved game file).
+//
+// Parameters:
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::LoadData( const GameDataByte* dataBuffer, unsigned int numBytes )
+{
+ SoundSettings soundSettings;
+ SoundMode loadedSoundMode;
+ float calculatedAmbienceVolume;
+
+#ifdef RAD_WIN32 // temp
+ return;
+#endif
+
+ memcpy( &soundSettings, dataBuffer, sizeof( soundSettings ) );
+
+ this->SetMusicVolume( soundSettings.musicVolume );
+ this->SetSfxVolume( soundSettings.sfxVolume );
+ this->SetCarVolume( soundSettings.carVolume );
+
+ calculatedAmbienceVolume = GetCalculatedAmbienceVolume();
+ //
+ // If the volume returned is less than zero, we haven't initialized
+ // the scripts yet. This will get taken care of in OnBootupComplete(),
+ // then.
+ //
+ if( calculatedAmbienceVolume >= 0.0f )
+ {
+ SetAmbienceVolume( GetCalculatedAmbienceVolume() );
+ }
+
+ //
+ // Hack! Hack! Hack! Hack!
+ //
+ // This is horrible. I'm not allowed to change the save structure, because we're
+ // too close to final. I can't cast that bool to an enumeration, because the PS2
+ // changes its size in release. The Xbox compiler won't let me set bit flags on
+ // booleans. So, I'm going to use the dialogue volume to signal stereo/mono by
+ // adding 100 to the volume to signal mono. I feel dirty.
+ //
+ if( soundSettings.dialogVolume >= 100.0f )
+ {
+ this->SetDialogueVolume( soundSettings.dialogVolume - 100.0f );
+ loadedSoundMode = SOUND_MONO;
+ }
+ else
+ {
+ this->SetDialogueVolume( soundSettings.dialogVolume );
+ if( soundSettings.isSurround )
+ {
+ loadedSoundMode = SOUND_SURROUND;
+ }
+ else
+ {
+ loadedSoundMode = SOUND_STEREO;
+ }
+ }
+
+#ifdef RAD_GAMECUBE
+ //
+ // GameCube's IPL needs to override the loaded settings, sadly
+ //
+ u32 GCSoundMode = OSGetSoundMode();
+ if( GCSoundMode == OS_SOUND_MODE_MONO )
+ {
+ //
+ // IPL says mono, we go mono
+ //
+ loadedSoundMode = SOUND_MONO;
+ }
+ else
+ {
+ if( loadedSoundMode == SOUND_MONO )
+ {
+ //
+ // IPL says stereo, we go stereo. Since the saved game had said
+ // mono, we need to choose a sub-sound mode. We'll go with ProLogic.
+ //
+ loadedSoundMode = SOUND_SURROUND;
+ }
+ }
+
+#endif
+
+ this->SetSoundMode( loadedSoundMode );
+}
+
+//=============================================================================
+// SoundManager::SaveData
+//=============================================================================
+// Description: Save sound settings (to saved game file).
+//
+// Parameters:
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::SaveData( GameDataByte* dataBuffer, unsigned int numBytes )
+{
+ SoundMode mode;
+ SoundSettings soundSettings;
+
+ soundSettings.musicVolume = this->GetMusicVolume();
+ soundSettings.sfxVolume = this->GetSfxVolume();
+ soundSettings.carVolume = this->GetCarVolume();
+ soundSettings.dialogVolume = this->GetDialogueVolume();
+
+ mode = this->GetSoundMode();
+ if( mode == SOUND_MONO )
+ {
+ //
+ // Horrible stinky hack explained in LoadData()
+ //
+ soundSettings.dialogVolume += 100.0f;
+ soundSettings.isSurround = false;
+ }
+ else if( mode == SOUND_STEREO )
+ {
+ soundSettings.isSurround = false;
+ }
+ else
+ {
+ soundSettings.isSurround = true;
+ }
+
+ memcpy( dataBuffer, &soundSettings, sizeof( soundSettings ) );
+}
+
+//=============================================================================
+// SoundManager::ResetData
+//=============================================================================
+// Description: Reset sound settings to defaults.
+//
+// Parameters:
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::ResetData()
+{
+ if( GetGameDataManager()->IsGameLoaded() )
+ {
+ // since sound settings can be changed in the FE, we should
+ // never reset to defaults if a game is already loaded
+ //
+ return;
+ }
+
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ globalSettings* settings;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( "tuner" );
+ rAssert( nameSpaceObj != NULL );
+
+ settings = static_cast<globalSettings*>( nameSpaceObj );
+
+ SetSfxVolume( settings->GetSfxVolume() );
+ SetMusicVolume( settings->GetMusicVolume() );
+ SetAmbienceVolume( settings->GetAmbienceVolume() );
+ SetDialogueVolume( settings->GetDialogueVolume() );
+ SetCarVolume( settings->GetCarVolume() );
+
+ //
+ // Sound mode. For GameCube, get it from the IPL (Initial Program
+ // Loader, the thingy you get when you start up a GameCube without
+ // a disc). For PS2 and Xbox, default to stereo (RadSound ignores
+ // this stuff for Xbox anyway, since these settings are supposed
+ // to be changed from the dashboard).
+ //
+#ifdef RAD_GAMECUBE
+ u32 GCSoundMode = OSGetSoundMode();
+ if( GCSoundMode == OS_SOUND_MODE_MONO )
+ {
+ SetSoundMode( SOUND_MONO );
+ }
+ else
+ {
+ SetSoundMode( SOUND_SURROUND );
+ }
+#else
+ SetSoundMode( SOUND_SURROUND );
+#endif
+}
+
+#ifdef RAD_WIN32
+//=============================================================================
+// SoundManager::GetConfigName
+//=============================================================================
+// Description: Returns the name of the sound manager's config
+//
+// Parameters: n/a
+//
+// Returns:
+//
+//=============================================================================
+
+const char* SoundManager::GetConfigName() const
+{
+ return "Sound";
+}
+
+//=============================================================================
+// SoundManager::GetNumProperties
+//=============================================================================
+// Description: Returns the number of config properties
+//
+// Parameters: n/a
+//
+// Returns:
+//
+//=============================================================================
+
+int SoundManager::GetNumProperties() const
+{
+ return 5;
+}
+
+//=============================================================================
+// SoundManager::LoadDefaults
+//=============================================================================
+// Description: Loads the default configuration for the sound manager.
+//
+// Parameters: n/a
+//
+// Returns:
+//
+//=============================================================================
+
+void SoundManager::LoadDefaults()
+{
+ IRadNameSpace* nameSpace;
+ IRefCount* nameSpaceObj;
+ globalSettings* settings;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+ nameSpaceObj = nameSpace->GetInstance( "tuner" );
+ rAssert( nameSpaceObj != NULL );
+
+ settings = static_cast<globalSettings*>( nameSpaceObj );
+
+ SetSfxVolume( settings->GetSfxVolume() );
+ SetMusicVolume( settings->GetMusicVolume() );
+ SetAmbienceVolume( settings->GetAmbienceVolume() );
+ SetDialogueVolume( settings->GetDialogueVolume() );
+ SetCarVolume( settings->GetCarVolume() );
+}
+
+//=============================================================================
+// SoundManager::LoadConfig
+//=============================================================================
+// Description: Loads the manager's configuration
+//
+// Parameters: n/a
+//
+// Returns:
+//
+//=============================================================================
+
+void SoundManager::LoadConfig( ConfigString& config )
+{
+ char property[ ConfigString::MaxLength ];
+ char value[ ConfigString::MaxLength ];
+
+ while ( config.ReadProperty( property, value ) )
+ {
+ if( _stricmp( property, "sfx" ) == 0 )
+ {
+ float val = (float) atof( value );
+ if( val >= 0 && val <= 1 )
+ {
+ SetSfxVolume( val );
+ }
+ }
+ else if( _stricmp( property, "music" ) == 0 )
+ {
+ float val = (float) atof( value );
+ if( val >= 0 && val <= 1 )
+ {
+ SetMusicVolume( val );
+ }
+ }
+ else if( _stricmp( property, "ambience" ) == 0 )
+ {
+ float val = (float) atof( value );
+ if( val >= 0 && val <= 1 )
+ {
+ SetAmbienceVolume( val );
+ }
+ }
+ else if( _stricmp( property, "dialogue" ) == 0 )
+ {
+ float val = (float) atof( value );
+ if( val >= 0 && val <= 1 )
+ {
+ SetDialogueVolume( val );
+ }
+ }
+ else if( _stricmp( property, "car" ) == 0 )
+ {
+ float val = (float) atof( value );
+ if( val >= 0 && val <= 1 )
+ {
+ SetCarVolume( val );
+ }
+ }
+ }
+}
+
+//=============================================================================
+// SoundManager::SaveConfig
+//=============================================================================
+// Description: Saves the manager's configuration to the config string.
+//
+// Parameters: config string to save to
+//
+// Returns:
+//
+//=============================================================================
+
+void SoundManager::SaveConfig( ConfigString& config )
+{
+ char value[ 32 ];
+
+ sprintf( value, "%f", GetSfxVolume() );
+ config.WriteProperty( "sfx", value );
+ sprintf( value, "%f", GetMusicVolume() );
+ config.WriteProperty( "music", value );
+ sprintf( value, "%f", GetAmbienceVolume() );
+ config.WriteProperty( "ambience", value );
+ sprintf( value, "%f", GetDialogueVolume() );
+ config.WriteProperty( "dialogue", value );
+ sprintf( value, "%f", GetCarVolume() );
+ config.WriteProperty( "car", value );
+}
+#endif // RAD_WIN32
+
+void SoundManager::SetSoundMode( SoundMode mode )
+{
+ radSoundOutputMode radSoundMode;
+
+ m_soundMode = mode;
+
+ if( m_soundMode == SOUND_MONO )
+ {
+ radSoundMode = radSoundOutputMode_Mono;
+ }
+ else if( m_soundMode == SOUND_STEREO )
+ {
+ radSoundMode = radSoundOutputMode_Stereo;
+ }
+ else
+ {
+ radSoundMode = radSoundOutputMode_Surround;
+ }
+
+ ::radSoundHalSystemGet()->SetOutputMode( radSoundMode );
+}
+
+SoundMode SoundManager::GetSoundMode()
+{
+ return( m_soundMode );
+}
+
+//******************************************************************************
+//
+// Protected Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundManager::SoundManager
+//==============================================================================
+//
+// Description: Constructor.
+//
+// Parameters:
+//
+// Return: N/A
+//
+//==============================================================================
+SoundManager::SoundManager( bool noSound, bool noMusic,
+ bool noEffects, bool noDialogue ) :
+ m_soundLoader( NULL ),
+ m_musicPlayer( NULL ),
+ m_soundFXPlayer( NULL ),
+ m_NISPlayer( NULL ),
+ m_movingSoundManager( NULL ),
+ m_isMuted( noSound ),
+ m_noMusic( noMusic ),
+ m_noEffects( noEffects ),
+ m_noDialogue( noDialogue ),
+ m_stoppedForMovie( false ),
+ m_selectSoundClip( NULL ),
+ m_scrollSoundClip( NULL ),
+ m_selectSoundClipPlayer( NULL ),
+ m_scrollSoundClipPlayer( NULL ),
+ m_soundMode( SOUND_STEREO )
+{
+ m_dialogCoordinator = NULL;
+
+ Sound::daSoundRenderingManagerCreate( GMA_AUDIO_PERSISTENT );
+
+ if( !m_isMuted )
+ {
+ m_pSoundRenderMgr = Sound::daSoundRenderingManagerGet();
+ rAssert( m_pSoundRenderMgr != NULL );
+
+ m_pSoundRenderMgr->Initialize();
+ }
+
+ GetGameDataManager()->RegisterGameData( this, sizeof( SoundSettings ), "Sound Manager" );
+
+ prepareStartupSounds();
+}
+
+//==============================================================================
+// SoundManager::~SoundManager
+//==============================================================================
+//
+// Description: Destructor. first attempt.
+//
+// Parameters: N/A
+//
+// Return: N/A
+//
+//==============================================================================
+SoundManager::~SoundManager()
+{
+ GetEventManager()->RemoveAll( this );
+
+ if( m_isMuted )
+ {
+ return;
+ }
+
+ delete( GMA_PERSISTENT, m_soundFXPlayer);
+ delete( GMA_PERSISTENT, m_movingSoundManager);
+ delete( GMA_PERSISTENT, m_NISPlayer);
+ delete( GMA_PERSISTENT, m_dialogCoordinator);
+ delete( GMA_PERSISTENT, m_musicPlayer);
+ delete( GMA_PERSISTENT, m_soundLoader);
+
+ Sound::daSoundRenderingManagerTerminate();
+
+ delete( GMA_PERSISTENT, m_debugDisplay);
+}
+
+//=============================================================================
+// SoundManager::initialize
+//=============================================================================
+// Description: Do some class member initialization tasks that we can't really
+// do in the constructor.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundManager::initialize()
+{
+ if( m_isMuted )
+ {
+ //
+ // We need to intercept dialog skip events, since the dialog coordinator
+ // isn't going to do it if we're muted
+ //
+ GetEventManager()->AddListener( this, EVENT_CONVERSATION_SKIP );
+ return;
+ }
+ else
+ {
+ //
+ // Set up a few tuner-related events
+ //
+ GetEventManager()->AddListener( this, EVENT_CONVERSATION_START );
+ GetEventManager()->AddListener( this, EVENT_CONVERSATION_DONE );
+ GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
+ GetEventManager()->AddListener( this, EVENT_ENTER_INTERIOR_START );
+ GetEventManager()->AddListener( this, EVENT_ENTER_INTERIOR_END );
+ GetEventManager()->AddListener( this, EVENT_EXIT_INTERIOR_START );
+ GetEventManager()->AddListener( this, EVENT_EXIT_INTERIOR_END );
+ GetEventManager()->AddListener( this, EVENT_MISSION_RESET );
+ GetEventManager()->AddListener( this, EVENT_CHARACTER_POS_RESET );
+ GetEventManager()->AddListener( this, EVENT_VEHICLE_DESTROYED_SYNC_SOUND );
+ }
+
+ m_debugDisplay = new( GMA_PERSISTENT ) SoundDebugDisplay( m_pSoundRenderMgr );
+ m_soundLoader = new( GMA_PERSISTENT ) SoundLoader();
+ m_musicPlayer = new( GMA_PERSISTENT ) MusicPlayer( *(m_pSoundRenderMgr->GetTuner()) );
+ m_dialogCoordinator = new( GMA_PERSISTENT ) DialogCoordinator( m_pSoundRenderMgr->GetSoundNamespace() );
+ m_NISPlayer = new( GMA_PERSISTENT ) NISSoundPlayer();
+ m_movingSoundManager = new( GMA_PERSISTENT ) MovingSoundManager();
+ m_soundFXPlayer = new( GMA_PERSISTENT ) SoundEffectPlayer();
+ m_avatarSoundPlayer.Initialize();
+ m_listener.Initialize( *m_pSoundRenderMgr );
+
+ //
+ // Apply the non-global mute options
+ //
+ if( m_noMusic )
+ {
+ m_pSoundRenderMgr->GetTuner()->SetMusicVolume( 0.0f );
+ }
+ if( m_noEffects )
+ {
+ m_pSoundRenderMgr->GetTuner()->SetSfxVolume( 0.0f );
+ }
+ if( m_noDialogue )
+ {
+ m_pSoundRenderMgr->GetTuner()->SetDialogueVolume( 0.0f );
+ }
+
+ //
+ // Register a factory for creating the global settings object
+ //
+ ::radFactoryRegister( "globalSettings", (radFactoryOutParamProc*) ::GlobalSettingsObjCreate );
+ ::radFactoryRegister( "reverbSettings", (radFactoryOutParamProc*) ::ReverbSettingsObjCreate );
+ ::radFactoryRegister( "positionalSoundSettings", (radFactoryOutParamProc*) ::PositionalSettingsObjCreate );
+
+#ifdef RAD_WIN32
+ //
+ // Register with the game config manager
+ //
+ GetGameConfigManager()->RegisterConfig( this );
+#endif
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+void SoundManager::prepareStartupSounds()
+{
+ //
+ // Go direct to RadSound to load two sounds that we can
+ // play for bootcheck screens
+ //
+ IRadSoundRsdFileDataSource* selectFileDataSource =
+ radSoundRsdFileDataSourceCreate( GMA_DEFAULT );
+ selectFileDataSource->AddRef();
+ selectFileDataSource->InitializeFromFileName( "sound/accept.rsd",
+ false,
+ 0,
+ IRadSoundHalAudioFormat::Frames,
+ Sound::SoundNucleusGetClipFileAudioFormat() );
+ m_selectSoundClip = radSoundClipCreate( GMA_DEFAULT );
+ m_selectSoundClip->AddRef();
+ m_selectSoundClip->Initialize(
+ selectFileDataSource,
+ ::radSoundHalSystemGet()->GetRootMemoryRegion(),
+ false,
+ "sound/accept.rsd" );
+ selectFileDataSource->Release( );
+
+ m_selectSoundClipPlayer = radSoundClipPlayerCreate( GMA_DEFAULT );
+ m_selectSoundClipPlayer->AddRef();
+
+ IRadSoundRsdFileDataSource* scrollFileDataSource =
+ radSoundRsdFileDataSourceCreate( GMA_DEFAULT );
+ scrollFileDataSource->AddRef();
+ scrollFileDataSource->InitializeFromFileName( "sound/scroll.rsd",
+ false,
+ 0,
+ IRadSoundHalAudioFormat::Frames,
+ Sound::SoundNucleusGetClipFileAudioFormat() );
+ m_scrollSoundClip = radSoundClipCreate( GMA_DEFAULT );
+ m_scrollSoundClip->AddRef();
+ m_scrollSoundClip->Initialize(
+ scrollFileDataSource,
+ ::radSoundHalSystemGet()->GetRootMemoryRegion(),
+ false,
+ "sound/scroll.rsd" );
+ scrollFileDataSource->Release( );
+
+ m_scrollSoundClipPlayer = radSoundClipPlayerCreate( GMA_DEFAULT );
+ m_scrollSoundClipPlayer->AddRef();
+
+ //
+ // Starting listening for the select/scroll events
+ //
+ GetEventManager()->AddListener( this, EVENT_FE_MENU_SELECT );
+ GetEventManager()->AddListener( this, EVENT_FE_MENU_UPORDOWN );
+}
+
+void SoundManager::dumpStartupSounds()
+{
+ m_selectSoundClip->Release();
+ m_selectSoundClip = NULL;
+
+ m_selectSoundClipPlayer->Release();
+ m_selectSoundClipPlayer = NULL;
+
+ m_scrollSoundClip->Release();
+ m_scrollSoundClip = NULL;
+
+ m_scrollSoundClipPlayer->Release();
+ m_scrollSoundClipPlayer = NULL;
+
+ GetEventManager()->RemoveListener( this, EVENT_FE_MENU_SELECT );
+ GetEventManager()->RemoveListener( this, EVENT_FE_MENU_UPORDOWN );
+}
+
+void SoundManager::playStartupAcceptSound()
+{
+ if( m_selectSoundClip->GetState() == IRadSoundClip::Initialized )
+ {
+ m_selectSoundClipPlayer->SetClip( m_selectSoundClip );
+ m_selectSoundClipPlayer->Play();
+ }
+}
+
+void SoundManager::playStartupScrollSound()
+{
+ if( m_scrollSoundClip->GetState() == IRadSoundClip::Initialized )
+ {
+ m_scrollSoundClipPlayer->SetClip( m_scrollSoundClip );
+ m_scrollSoundClipPlayer->Play();
+ }
+} \ No newline at end of file
diff --git a/game/code/sound/soundmanager.h b/game/code/sound/soundmanager.h
new file mode 100644
index 0000000..40f65da
--- /dev/null
+++ b/game/code/sound/soundmanager.h
@@ -0,0 +1,377 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundmanager.h
+//
+// Description: Manager interface that the other game components use to
+// interact with sound.
+//
+// History: 01/06/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef _SOUNDMANAGER_H
+#define _SOUNDMANAGER_H
+
+#ifndef RAD_RELEASE
+#define SOUNDDEBUG_ENABLED
+#endif
+
+
+//
+// Debug display macros
+//
+#ifndef SOUNDDEBUG_ENABLED
+
+#define SOUNDDEBUG_RENDER()
+
+#else
+
+#define SOUNDDEBUG_RENDER() GetSoundManager()->DebugRender()
+
+#endif
+
+//========================================
+// Nested Includes
+//========================================
+
+#include <enums.h>
+
+#include <sound/soundloader.h>
+#include <sound/avatar/avatarsoundplayer.h>
+#include <sound/listener.h>
+#include <sound/nis/nissoundplayer.h>
+
+#include <data/gamedata.h>
+#include <events/eventlistener.h>
+#include <contexts/contextenum.h>
+
+#ifdef RAD_WIN32
+#include <data/config/gameconfig.h>
+#endif
+
+//========================================
+// Forward References
+//========================================
+
+class MusicPlayer;
+class DialogCoordinator;
+class SoundDebugDisplay;
+class MovingSoundManager;
+class Vehicle;
+class Character;
+class SoundEffectPlayer;
+struct IRadSoundClip;
+struct IRadSoundClipPlayer;
+
+//=============================================================================
+//
+// Synopsis: NIS loading and playback completion callbacks
+//
+//=============================================================================
+
+struct NISSoundLoadedCallback
+{
+ virtual void NISSoundLoaded() = 0;
+};
+
+struct NISSoundPlaybackCompleteCallback
+{
+ virtual void NISSoundPlaybackComplete() = 0;
+};
+
+enum SoundMode
+{
+ SOUND_MONO,
+ SOUND_STEREO,
+ SOUND_SURROUND
+};
+
+//=============================================================================
+//
+// Synopsis: SoundManager class declaration
+//
+//=============================================================================
+
+class SoundManager : public EventListener,
+ #ifdef RAD_WIN32
+ public GameConfigHandler, //ziemek: this is ugly..doh
+ #endif
+ public GameDataHandler
+{
+ public:
+ //
+ // Singleton accessors
+ //
+ static SoundManager* CreateInstance( bool muteSound, bool noMusic,
+ bool noEffects, bool noDialogue );
+ static SoundManager* GetInstance();
+ static void DestroyInstance();
+
+ //
+ // EventListener interface
+ //
+ void HandleEvent( EventEnum id, void* pEventData );
+
+ //
+ // All-purpose sound file loading. Coordinates the sound system
+ // with the loading system
+ //
+ void LoadSoundFile( const char* filename, SoundFileHandler* callbackObj );
+
+ //
+ // Update routines.
+ //
+ void Update();
+ // This one is for expensive stuff like positional sound calculations
+ // that we can get away with doing once per frame
+ void UpdateOncePerFrame( unsigned int elapsedTime,
+ ContextEnum context,
+ bool useContext = true,
+ bool isPausedForErrors = false );
+
+ // Prepare to load level sounds
+ void QueueLevelSoundLoads();
+
+ // Load the sounds associated with a car
+ void LoadCarSound( Vehicle* theCar, bool unloadOtherCars );
+
+ // Called when bootup context starts and ends
+ void OnBootupStart();
+ void OnBootupComplete();
+
+ // Called when front end starts and ends
+ void OnFrontEndStart();
+ void OnFrontEndEnd();
+
+ // Called when gameplay starts and ends
+ void OnGameplayStart();
+ void OnGameplayEnd( bool goingToFE );
+
+ // Called when pause menu starts and ends (ends going back to gameplay,
+ // not loading)
+ void OnPauseStart();
+ void OnPauseEnd();
+
+ // Called for pseudo-pause stuff like clothing and phone booth
+ //
+ void OnStoreScreenStart( bool playMusic = true );
+ void OnStoreScreenEnd();
+
+ // Called when we want to kill everything but music (e.g. loading,
+ // minigame standings)
+ void DuckEverythingButMusicBegin( bool playMuzak = false );
+ void DuckEverythingButMusicEnd( bool playMuzak = false );
+
+ // Called when mission briefing screen starts and ends
+ void OnMissionBriefingStart();
+ void OnMissionBriefingEnd();
+
+ // Called when in-game credits start
+ //
+ void DuckForInGameCredits();
+
+ // Call these before and after FMVs
+ void StopForMovie();
+ void ResumeAfterMovie();
+ bool IsStoppedForMovie();
+
+ // Hack! Need to mute gags during conversations
+ void MuteNISPlayers();
+ void UnmuteNISPlayers();
+
+ //
+ // Supersprint
+ //
+ void RestartSupersprintMusic();
+
+ // Surround sound control
+ void SetSoundMode( SoundMode mode );
+ SoundMode GetSoundMode();
+
+ // Function for getting that funky beat. Values from 0.0f to 4.0f, assuming
+ // that Marc doesn't write any waltzes
+ float GetBeatValue();
+
+ // Special case dialog handling
+ static bool IsFoodCharacter( Character* theGuy );
+
+ //
+ // Volume controls. Values range from 0.0f to 1.0f
+ //
+ void SetMasterVolume( float volume );
+ float GetMasterVolume();
+
+ void SetSfxVolume( float volume );
+ float GetSfxVolume();
+
+ void SetCarVolume( float volume );
+ float GetCarVolume();
+
+ void SetMusicVolume( float volume );
+ float GetMusicVolume();
+
+ void SetAmbienceVolume( float volume );
+ float GetAmbienceVolume();
+
+ void SetDialogueVolume( float volume );
+ float GetDialogueVolume();
+
+ float GetCalculatedAmbienceVolume();
+
+ //
+ // Option menu stinger stuff
+ //
+ void PlayCarOptionMenuStinger();
+ void PlayDialogueOptionMenuStinger();
+ void PlayMusicOptionMenuStinger();
+ void PlaySfxOptionMenuStinger();
+
+ //
+ // Ducking stuff
+ //
+ void ResetDucking();
+
+ //
+ // NIS Interface
+ //
+ void LoadNISSound( radKey32 NISSoundID, NISSoundLoadedCallback* callback = NULL );
+ void PlayNISSound( radKey32 NISSoundID, rmt::Box3D* boundingBox, NISSoundPlaybackCompleteCallback* callback = NULL );
+ void StopAndDumpNISSound( radKey32 NISSoundID );
+
+ //
+ // Language interface
+ //
+ void SetDialogueLanguage( Scrooby::XLLanguage language );
+
+ //
+ // Sound debug functions
+ //
+ void DebugRender();
+
+ //
+ // TODO: move these functions, they're not intended for use outside
+ // of the sound system
+ //
+ SoundLoader* GetSoundLoader() { return( m_soundLoader ); }
+ SoundDebugDisplay* GetDebugDisplay() { return( m_debugDisplay ); }
+
+ //
+ // This should NOT be called outside the sound system. Unfortunately,
+ // to keep things clean, what I should do is split the MusicPlayer class
+ // and move a low-level controller into the soundrenderer layer. I don't
+ // have time for this. Things to do for the next round.
+ //
+ void SetMusicVolumeWithoutTuner( float volume );
+ void SetAmbienceVolumeWithoutTuner( float volume );
+
+ // Implements GameDataHandler
+ //
+ virtual void LoadData( const GameDataByte* dataBuffer, unsigned int numBytes );
+ virtual void SaveData( GameDataByte* dataBuffer, unsigned int numBytes );
+ virtual void ResetData();
+
+ #ifdef RAD_WIN32
+ // Implementation of the GameConfigHandler interface
+ virtual const char* GetConfigName() const;
+ virtual int GetNumProperties() const;
+ virtual void LoadDefaults();
+ virtual void LoadConfig( ConfigString& config );
+ virtual void SaveConfig( ConfigString& config );
+ #endif
+
+ DialogCoordinator* m_dialogCoordinator;
+
+ protected:
+ //
+ // Hide the SoundManager constructor and destructor so everyone
+ // is forced to use singleton accessors
+ //
+ SoundManager( bool noSound, bool noMusic, bool noEffects, bool noDialogue );
+ ~SoundManager();
+
+ void initialize();
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundManager( const SoundManager& original );
+ SoundManager& operator=( const SoundManager& rhs );
+
+ //
+ // Hack!
+ //
+ void prepareStartupSounds();
+ void playStartupAcceptSound();
+ void playStartupScrollSound();
+ void dumpStartupSounds();
+
+ // Pointer to the one and only instance of this singleton.
+ static SoundManager* spInstance;
+
+ struct SoundSettings
+ {
+ float musicVolume;
+ float sfxVolume;
+ float carVolume;
+ float dialogVolume;
+ bool isSurround;
+ };
+
+ // Sound loading subsystem
+ SoundLoader* m_soundLoader;
+
+ // Avatar sound subsystem
+ AvatarSoundPlayer m_avatarSoundPlayer;
+
+ // Music player subsystem
+ MusicPlayer* m_musicPlayer;
+
+ // Sound effect subsystem
+ SoundEffectPlayer* m_soundFXPlayer;
+
+ // Dialog subsystem
+
+
+ // NIS subsystem
+ NISSoundPlayer* m_NISPlayer;
+
+ // RadSound listener update
+ Listener m_listener;
+
+ // AI Vehicle sound subsystem
+ MovingSoundManager* m_movingSoundManager;
+
+ // Sound debug display subsystem
+ SoundDebugDisplay* m_debugDisplay;
+
+ // Mute options
+ bool m_isMuted;
+
+ bool m_noMusic;
+ bool m_noEffects;
+ bool m_noDialogue;
+
+ // Pointer to sound rendering interface
+ Sound::daSoundRenderingManager* m_pSoundRenderMgr;
+
+ // [ps] avoid hammering on pause.
+ bool m_stoppedForMovie;
+
+ //
+ // Hack for stinky pre-script-loading menu sounds
+ //
+ IRadSoundClip* m_selectSoundClip;
+ IRadSoundClip* m_scrollSoundClip;
+
+ IRadSoundClipPlayer* m_selectSoundClipPlayer;
+ IRadSoundClipPlayer* m_scrollSoundClipPlayer;
+
+
+ SoundMode m_soundMode;
+};
+
+// A little syntactic sugar for getting at this singleton.
+inline SoundManager* GetSoundManager() { return( SoundManager::GetInstance() ); }
+
+#endif //SOUNDMANAGER_H
+
diff --git a/game/code/sound/soundrenderer/allsoundrenderer.cpp b/game/code/sound/soundrenderer/allsoundrenderer.cpp
new file mode 100644
index 0000000..f2315f3
--- /dev/null
+++ b/game/code/sound/soundrenderer/allsoundrenderer.cpp
@@ -0,0 +1,14 @@
+#include <sound/soundrenderer/dasoundplayer.cpp>
+#include <sound/soundrenderer/fader.cpp>
+#include <sound/soundrenderer/musicsoundplayer.cpp>
+#include <sound/soundrenderer/soundnucleus.cpp>
+#include <sound/soundrenderer/playermanager.cpp>
+#include <sound/soundrenderer/soundallocatedresource.cpp>
+#include <sound/soundrenderer/sounddynaload.cpp>
+#include <sound/soundrenderer/soundrenderingmanager.cpp>
+#include <sound/soundrenderer/soundresource.cpp>
+#include <sound/soundrenderer/soundresourcemanager.cpp>
+#include <sound/soundrenderer/soundtuner.cpp>
+#include <sound/soundrenderer/wireplayers.cpp>
+#include <sound/soundrenderer/wiresystem.cpp>
+#include <sound/soundrenderer/tunerdebugpage.cpp>
diff --git a/game/code/sound/soundrenderer/dasoundgroup.h b/game/code/sound/soundrenderer/dasoundgroup.h
new file mode 100644
index 0000000..884b049
--- /dev/null
+++ b/game/code/sound/soundrenderer/dasoundgroup.h
@@ -0,0 +1,100 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dasoundgroup.hpp
+//
+// Subsystem: Dark Angel - Sound Grouping
+//
+// Description: Contains definitions, enumerations, and interfaces for a
+// Dark Angel sound group.
+//
+// Revisions:
+// + Created October 18, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _DASOUNDGROUP_HPP
+#define _DASOUNDGROUP_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Typedefs and Enumerations
+//=============================================================================
+
+//
+// The list of possible sound groups
+//
+
+enum daSoundGroup {
+ // BASIC WIRING GROUPS
+ CARSOUND,
+ NIS,
+
+ NUM_BASIC_SOUND_GROUPS,
+
+ // SYSTEM WIRING GROUPS
+ // Warning: Do not modify
+ DIALOGUE = NUM_BASIC_SOUND_GROUPS,
+ DIALOGUE_TUNE,
+ DUCKABLE,
+ MASTER,
+ MASTER_TUNE,
+ MUSIC,
+ MUSIC_TUNE,
+ AMBIENCE,
+ AMBIENCE_TUNE,
+ SOUND_EFFECTS,
+ SOUND_EFFECTS_TUNE,
+ OPTIONS_MENU_STINGERS,
+
+ NUM_SOUND_GROUPS
+};
+
+enum DuckSituations
+{
+ DUCK_FULL_FADE,
+
+ DUCK_SIT_PAUSE,
+ DUCK_SIT_MISSION,
+ DUCK_SIT_LETTERBOX,
+ DUCK_SIT_DIALOG,
+ DUCK_SIT_STORE,
+ DUCK_SIT_ONFOOT,
+ DUCK_SIT_MINIGAME,
+ DUCK_SIT_JUST_MUSIC,
+ DUCK_SIT_CREDITS,
+
+ NUM_DUCK_SITUATIONS
+};
+
+enum DuckVolumes
+{
+ DUCK_SFX,
+ DUCK_CAR,
+ DUCK_MUSIC,
+ DUCK_DIALOG,
+ DUCK_AMBIENCE,
+
+ NUM_DUCK_VOLUMES
+};
+
+//
+// A structure for holding a collection of volumes
+//
+struct DuckVolumeSet
+{
+ float duckVolume[NUM_DUCK_VOLUMES];
+};
+
+} // Namespace
+#endif //_DASOUNDGROUP_HPP
+
diff --git a/game/code/sound/soundrenderer/dasoundplayer.cpp b/game/code/sound/soundrenderer/dasoundplayer.cpp
new file mode 100644
index 0000000..0220f47
--- /dev/null
+++ b/game/code/sound/soundrenderer/dasoundplayer.cpp
@@ -0,0 +1,1191 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dasoundplayer.cpp
+//
+// Subsystem: Dark Angel - Sound players
+//
+// Description: Implements the a Dark Angel sound player
+//
+// Revisions:
+// + Created October 16, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radlinkedclass.hpp>
+
+#include <radsound.hpp>
+#include <radsoundmath.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/soundplayer.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundnucleus.hpp>
+
+#include <main/commandlineoptions.h>
+
+//=============================================================================
+// Static Variables (outside namespace)
+//=============================================================================
+
+
+//
+// Initialially the player list is empty
+//
+Sound::daSoundPlayerBase* radLinkedClass< Sound::daSoundPlayerBase >::s_pLinkedClassHead = NULL;
+Sound::daSoundPlayerBase* radLinkedClass< Sound::daSoundPlayerBase >::s_pLinkedClassTail = NULL;
+Sound::daSoundClipStreamPlayer* radLinkedClass< Sound::daSoundClipStreamPlayer >::s_pLinkedClassHead = NULL;
+Sound::daSoundClipStreamPlayer* radLinkedClass< Sound::daSoundClipStreamPlayer >::s_pLinkedClassTail = NULL;
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Debug Information
+//=============================================================================
+
+//
+// Use this if you want to debug the sound player
+//
+#ifndef FINAL
+#ifndef NDEBUG
+#define DASOUNDPLAYER_DEBUG
+#ifdef DASOUNDPLAYER_DEBUG
+
+// Show sound state changes
+static bool sg_ShowSoundStates = false;
+
+#endif //DASOUNDPLAYER_DEBUG
+#endif //NDEBUG
+#endif //FINAL
+
+//=============================================================================
+// Definitions Macros and Constants
+//=============================================================================
+
+//
+// These are the minimum ranges that the given variables must range
+// over to warrant a randomization calculation
+//
+const float DASOUND_MINFLOATVARYINGRANGE = 0.0001f;
+
+//=============================================================================
+// Local functions
+//=============================================================================
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundClipStreamPlayer Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::daSoundClipStreamPlayer
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundClipStreamPlayer::daSoundClipStreamPlayer( )
+ :
+ m_Trim( 1.0f ),
+ m_GroupTrim( 1.0f ),
+ m_FaderGroupTrim( 1.0f ),
+ m_MasterTrim( 1.0f ),
+ m_State( State_DeCued ),
+ m_CueingState( CueingState_Null ),
+ m_CaptureCount( 0 ),
+ m_PauseCount( 0 ),
+ m_pAllocatedResource( NULL ),
+ m_AllocResInstanceID( 0 ),
+ m_pResource( NULL ),
+ m_pStateChangeCallback( NULL ),
+ m_pStateChangeCallbackUserData( NULL ),
+ m_Type( IDaSoundResource::UNKNOWN )
+{
+ m_IsPositional = false;
+ m_pPositionalGroup = radSoundHalPositionalGroupCreate( GetThisAllocator( ) );
+ m_pPositionalGroup->AddRef( );
+
+ m_CurrentTrim = 0.0f;
+ m_StoppingTrim = 1.0f;
+ m_VaryingTrim = 1.0f;
+
+ m_Pitch = 1.0f;
+ m_VaryingPitch = 1.0f;
+ m_CurrentPitch = 1.0f;
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::~daSoundClipStreamPlayer
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundClipStreamPlayer::~daSoundClipStreamPlayer( )
+{
+ if ( IDaSoundResource::CLIP == m_Type )
+ {
+ m_ClipInfo.m_pClipPlayer->Stop( );
+ m_ClipInfo.m_pClipPlayer->SetClip( NULL );
+ m_ClipInfo.m_pClipPlayer->Release( );
+ }
+ else
+ {
+ if ( m_StreamInfo.m_pResources != NULL )
+ {
+ Sound::SoundNucleusUnCaptureStreamerResources( m_StreamInfo.m_pResources );
+ m_StreamInfo.m_pResources->m_pStitchedDataSource->SetStitchCallback( NULL, NULL );
+ }
+
+ if ( m_StreamInfo.m_pRsdFileDataSource != NULL )
+ {
+ m_StreamInfo.m_pRsdFileDataSource->Release( );
+ }
+ }
+
+ if ( m_pResource != NULL )
+ {
+ m_pResource->Release( );
+ }
+
+ if ( m_pPositionalGroup )
+ {
+ m_pPositionalGroup->Release( );
+ }
+
+ if ( m_pAllocatedResource )
+ {
+ m_pAllocatedResource->Release( );
+ }
+
+ if ( m_pResource != NULL )
+ {
+ m_pResource->Release( );
+ }
+}
+
+void daSoundClipStreamPlayer::UpdateClip( void )
+{
+ m_ClipInfo.m_pClipPlayer->SetTrim( m_CurrentTrim );
+ m_ClipInfo.m_pClipPlayer->SetPitch( m_CurrentPitch );
+
+ IRadSoundClipPlayer * pCp = m_ClipInfo.m_pClipPlayer;
+ IRadSoundClipPlayer::State state = pCp->GetState( );
+
+ switch( m_State )
+ {
+ case State_DeCued:
+ {
+ rAssert( IRadSoundClipPlayer::NoClip == state );
+ break;
+ }
+ case State_CuedPlay:
+ case State_Cueing:
+ {
+ switch( m_CueingState )
+ {
+ case CueingState_Null:
+ {
+ rAssert( false );
+ break;
+ }
+ case CueingState_Resource:
+ {
+ rAssert( IRadSoundClipPlayer::NoClip == state );
+
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+ if ( pFileInstance->GetState( ) == daSoundFileInstance::Loaded )
+ {
+ HookUpAndCuePlayer( );
+ }
+
+ break;
+ }
+ case CueingState_Player:
+ {
+ m_CueingState = CueingState_Cued;
+ break;
+ }
+ case CueingState_Cued:
+ {
+ rAssert( IRadSoundClipPlayer::Stopped == state );
+
+ if ( State_CuedPlay == m_State )
+ {
+ if( 0 == m_PauseCount )
+ {
+ pCp->Play( );
+ }
+
+ m_CaptureCount++;
+ m_State = State_Playing;
+ }
+ else
+ {
+ m_State = State_Cued;
+ }
+
+ if ( m_pStateChangeCallback )
+ {
+ m_pStateChangeCallback->OnSoundReady( m_pStateChangeCallbackUserData );
+ }
+
+ m_CueingState = CueingState_Null;
+
+ break;
+ }
+ }
+ break;
+ }
+ case State_Cued:
+ {
+ switch( state )
+ {
+ case IRadSoundClipPlayer::Stopped:
+ break;
+ case IRadSoundClipPlayer::NoClip:
+ case IRadSoundClipPlayer::Queueing:
+ case IRadSoundClipPlayer::QueuedPlay:
+ case IRadSoundClipPlayer::Playing:
+ default:
+ rAssert( false );
+ }
+ break;
+ }
+ case State_Playing:
+ {
+ if ( m_StoppingTrim <= 1.0f )
+ {
+ m_StoppingTrim += radSoundVolumeChangeThreshold;
+
+ if ( m_StoppingTrim >= 1.0f )
+ {
+ m_StoppingTrim = 1.0f;
+ }
+ }
+ switch( state )
+ {
+ case IRadSoundClipPlayer::NoClip:
+ case IRadSoundClipPlayer::Queueing:
+ case IRadSoundClipPlayer::QueuedPlay:
+ rAssert( false );
+ break;
+ case IRadSoundClipPlayer::Playing:
+ rAssert( 0 == m_PauseCount );
+ break;
+ case IRadSoundClipPlayer::Stopped:
+ if( m_PauseCount == 0 )
+ {
+ m_State = State_Done;
+ UnCapture( );
+
+ if ( m_pStateChangeCallback )
+ {
+ m_pStateChangeCallback->OnSoundDone( m_pStateChangeCallbackUserData );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case State_Stopping:
+ {
+ if ( m_CurrentTrim <= 0.0f )
+ {
+ m_ClipInfo.m_pClipPlayer->Stop( );
+ m_State = State_Cued;
+ m_StoppingTrim = 1.0f;
+ UnCapture( );
+ }
+ else
+ {
+ m_StoppingTrim -= radSoundVolumeChangeThreshold;
+
+ if ( m_StoppingTrim <= 0.0f )
+ {
+ m_StoppingTrim = 0.0f;
+ }
+ }
+
+ break;
+ }
+
+ case State_Done:
+ {
+ rAssert( IRadSoundClipPlayer::NoClip == state );
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ }
+ }
+}
+
+void daSoundClipStreamPlayer::UpdateStream( void )
+{
+ IRadSoundStreamPlayer::State state;
+
+ if ( NULL != m_StreamInfo.m_pResources )
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetTrim( m_CurrentTrim );
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetPitch( m_CurrentPitch );
+ state = m_StreamInfo.m_pResources->m_pStreamPlayer->GetState( );
+ }
+ else
+ {
+ state = IRadSoundStreamPlayer::NoSource;
+ }
+
+ switch( m_State )
+ {
+ case State_DeCued:
+ {
+ rAssert( IRadSoundStreamPlayer::NoSource == state );
+ break;
+ }
+ case State_CuedPlay:
+ case State_Cueing:
+ {
+ switch( m_CueingState )
+ {
+ case CueingState_Resource:
+ {
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+
+ if ( pFileInstance->GetState( ) == daSoundFileInstance::Loaded )
+ {
+ if ( NULL == m_StreamInfo.m_pRsdFileDataSource )
+ {
+ m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID )->CreateFileDataSource( & m_StreamInfo.m_pRsdFileDataSource );
+ }
+ else if ( IRadSoundRsdFileDataSource::Initialized == m_StreamInfo.m_pRsdFileDataSource->GetState( ) )
+ {
+ /* rDebugPrintf( "DASOUND: Playing Streamed File: [%s], format: [%d], channels: [%d]\n",
+ pFileInstance->GetFileName( ),
+ m_StreamInfo.m_pRsdFileDataSource->GetFormat( )->GetEncoding( ),
+ m_StreamInfo.m_pRsdFileDataSource->GetFormat( )->GetNumberOfChannels( ) ); */
+
+ HookUpAndCuePlayer( );
+ }
+ }
+
+ break;
+ }
+ case CueingState_Player:
+ {
+ switch( state )
+ {
+ case IRadSoundStreamPlayer::Queueing:
+ {
+ break;
+ }
+ case IRadSoundStreamPlayer::Paused:
+ {
+
+ if ( m_pStateChangeCallback )
+ {
+ m_pStateChangeCallback->OnSoundReady( m_pStateChangeCallbackUserData );
+ }
+
+ m_CueingState = CueingState_Cued;
+ break;
+ }
+ case IRadSoundStreamPlayer::NoSource:
+ case IRadSoundStreamPlayer::Playing:
+ case IRadSoundStreamPlayer::QueuedPlay:
+ default:
+ rAssert( false );
+ }
+
+ break;
+ }
+ case CueingState_Cued:
+ {
+ if ( State_Cueing == m_State )
+ {
+ m_State = State_Cued;
+ }
+ else
+ {
+ if ( 0 == m_PauseCount )
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->Play( );
+ }
+ m_CaptureCount++;
+ m_State = State_Playing;
+ }
+
+ m_CueingState = CueingState_Null;
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ }
+ }
+ break;
+ }
+ case State_Cued:
+ {
+ rAssert( IRadSoundStreamPlayer::Paused == state );
+ break;
+ }
+ case State_Playing:
+ {
+ m_StoppingTrim += radSoundVolumeChangeThreshold;
+
+ if ( m_StoppingTrim >= 1.0f )
+ {
+ m_StoppingTrim = 1.0f;
+ }
+
+ switch( state )
+ {
+ case IRadSoundStreamPlayer::Queueing:
+ rAssert(false);
+ break;
+ case IRadSoundStreamPlayer::Paused:
+ rAssert( 0 < m_PauseCount );
+ break;
+ case IRadSoundStreamPlayer::NoSource:
+ m_State = State_Done;
+ UnCapture( ); // Internal
+ if ( m_pStateChangeCallback )
+ {
+ m_pStateChangeCallback->OnSoundDone( m_pStateChangeCallbackUserData );
+ }
+ break;
+ case IRadSoundStreamPlayer::Playing:
+ rAssert( 0 == m_PauseCount );
+ break;
+ case IRadSoundStreamPlayer::QueuedPlay:
+ default:
+ rAssert( false );
+ }
+
+ break;
+
+ }
+ case State_Stopping:
+ {
+ if ( m_CurrentTrim <= 0.0f )
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->Stop( );
+ m_State = State_Cued;
+ m_StoppingTrim = 1.0f;
+ UnCapture( );
+ }
+ else
+ {
+ m_StoppingTrim -= radSoundVolumeChangeThreshold;
+
+ if ( m_StoppingTrim <= 0.0f )
+ {
+ m_StoppingTrim = 0.0f;
+ }
+ }
+
+ break;
+ }
+ case State_Done:
+ {
+ rAssert( IRadSoundStreamPlayer::NoSource == state );
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ }
+ }
+
+}
+
+void daSoundClipStreamPlayer::ServiceOncePerFrame( void )
+{
+ //
+ // Update the state information. This now requires polling the player.
+ //
+
+ State prevState;
+ CueingState prevCueingState;
+
+ do
+ {
+
+ CalculateCurrentTrim( );
+ CalculateCurrentPitch( );
+
+ prevState = m_State;
+ prevCueingState = m_CueingState;
+
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ UpdateClip( );
+ break;
+ case IDaSoundResource::STREAM:
+ UpdateStream( );
+ break;
+ default:
+ rAssert( 0 );
+ break;
+ }
+ }
+ while( prevState != m_State || prevCueingState != m_CueingState );
+}
+
+void daSoundClipStreamPlayer::InitializeAsClipPlayer( void )
+{
+ m_Type = IDaSoundResource::CLIP;
+
+ m_ClipInfo.m_pClipPlayer = radSoundClipPlayerCreate( GetThisAllocator( ) );
+ m_ClipInfo.m_pClipPlayer->AddRef( );
+
+#ifndef RAD_WIN32
+ // Prepare the player to listen for spacial effects
+ for( unsigned int i = 0; i < ::radSoundHalSystemGet( )->GetNumAuxSends( ); i++ )
+ {
+ m_ClipInfo.m_pClipPlayer->SetAuxMode( i, radSoundAuxMode_PostFader );
+ m_ClipInfo.m_pClipPlayer->SetAuxGain( i, 1.0f );
+ }
+#endif
+}
+
+void daSoundClipStreamPlayer::InitializeAsStreamPlayer( void )
+{
+ m_Type = IDaSoundResource::STREAM;
+
+ m_StreamInfo.m_pResources = NULL;
+ m_StreamInfo.m_pRsdFileDataSource = NULL;
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::CapturePlayer
+//=============================================================================
+// Description: Capture the sound player
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::Capture(
+ IDaSoundResource* pResource,
+ bool isPositional )
+{
+ rAssert( pResource != NULL );
+ rAssert( State_DeCued == m_State );
+
+ m_IsPositional = isPositional;
+
+ ++m_CaptureCount;
+
+ // A bit of a hack, but the resource should be connected only at this time
+ rAssert( m_CaptureCount == 1 );
+
+ rAssert( m_pAllocatedResource == NULL );
+ rAssert( m_pResource == NULL );
+
+ m_pResource = pResource;
+ m_pResource->CaptureResource( );
+
+ //
+ // Get an allocated resource
+ //
+ m_pAllocatedResource = daSoundResourceManager::GetInstance( )->FindAllocatedResource( m_pResource );
+
+ rAssertMsg( m_pAllocatedResource != NULL, "Resource not properly allocated" );
+
+ m_pAllocatedResource->AddRef( );
+
+ // Choose an instance to play...
+ m_AllocResInstanceID = m_pAllocatedResource->ChooseNextInstance( );
+
+ //
+ // Check the type of resource
+ //
+
+ rAssert( m_Type == m_pResource->GetType( ) );
+
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+ rAssert( pFileInstance != NULL );
+
+ if( pFileInstance->GetType( ) == IDaSoundResource::UNKNOWN )
+ {
+ rAssert( false); // when does this happen ? -Th
+ m_State = State_DeCued;
+ }
+ else
+ {
+ //
+ // Start initializing
+ //
+ m_State = State_Cueing;
+ m_CueingState = CueingState_Resource;
+ }
+
+ // Reset state.
+
+ m_Pitch = 1.0f;
+ m_Trim = 1.0f;
+
+ CalculateNewVaryingPitch( );
+ CalculateNewVaryingTrim( );
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::IsCaptured
+//=============================================================================
+// Description: Returns true if the player is already captured
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundClipStreamPlayer::IsCaptured( void )
+{
+ return( m_CaptureCount > 0 );
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::ReleasePlayer
+//=============================================================================
+// Description: Releases a player. Automattically detatches any
+// resources when it is no longer captured.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::UnCapture( void )
+{
+ unsigned int i = 0;
+
+ //
+ // I don't think this assertion is valid anymore. If a player is cued but not
+ // playing, then Stop() will release the resource, but the player isn't
+ // captured yet and this call shouldn't do anything -- DE
+ //
+ //rAssert( IsCaptured( ) );
+ if( m_CaptureCount > 0 )
+ {
+ --m_CaptureCount;
+
+ if( 0 == m_CaptureCount )
+ {
+ rAssert( NULL == m_pStateChangeCallback );
+ rAssert( m_pResource != NULL );
+ rAssert( m_pAllocatedResource->GetResource( ) == m_pResource );
+ rAssert( m_Type == m_pResource->GetType( ) );
+
+ // Detatch the real player
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ rAssert( m_ClipInfo.m_pClipPlayer != NULL );
+
+ // Detach the clip
+ m_ClipInfo.m_pClipPlayer->Stop( );
+ m_ClipInfo.m_pClipPlayer->SetClip( NULL );
+
+ break;
+ }
+ case IDaSoundResource::STREAM:
+ {
+ if ( m_StreamInfo.m_pResources != NULL )
+ {
+ m_StreamInfo.m_pResources->m_pStitchedDataSource->SetStitchCallback( NULL, NULL );
+
+ // Detach the stream
+ m_StreamInfo.m_pResources->m_pStreamPlayer->Stop( );
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetDataSource( NULL );
+
+ if ( m_StreamInfo.m_pResources->m_pBufferedDataSource != NULL )
+ {
+ m_StreamInfo.m_pResources->m_pBufferedDataSource->SetInputDataSource( NULL );
+ }
+
+ SoundNucleusUnCaptureStreamerResources( m_StreamInfo.m_pResources );
+ m_StreamInfo.m_pResources = NULL;
+ }
+
+ if ( m_StreamInfo.m_pRsdFileDataSource != NULL )
+ {
+ m_StreamInfo.m_pRsdFileDataSource->Release( );
+ m_StreamInfo.m_pRsdFileDataSource = NULL;
+ }
+
+ break;
+ }
+ default:
+ rAssert( 0 );
+ break;
+ }
+
+ // Release the allocated resource
+ m_pAllocatedResource->Release( );
+ m_pAllocatedResource = NULL;
+ m_pResource->ReleaseResource( );
+ m_pResource = NULL;
+
+ m_State = State_DeCued;
+ m_CueingState = CueingState_Null;
+ }
+ }
+}
+
+//=============================================================================
+// daSoundClipStreamPlayer::ChangeTrim
+//=============================================================================
+// Description: Change the trim setting for a sound group, or for the master
+// volume
+//
+// Parameters: groupName - name of group to change
+// newTrim - trim value
+//
+// Return: void
+//
+//=============================================================================
+void daSoundClipStreamPlayer::ChangeTrim( daSoundGroup groupName, float newTrim )
+{
+ daSoundGroup myGroup = GetSoundGroup();
+
+ if ( myGroup == groupName )
+ {
+ SetGroupTrim(newTrim);
+ }
+ else if ( groupName == MASTER )
+ {
+ SetMasterTrim(newTrim);
+ }
+ else if ( daSoundRenderingManagerGet()->GetTuner()->IsSlaveGroup( myGroup, groupName ) )
+ {
+ SetGroupTrim(newTrim);
+ }
+}
+
+//=============================================================================
+// daSoundClipStreamPlayer::ChangeFaderTrim
+//=============================================================================
+// Description: Change the trim setting for a sound group, or for the master
+// volume
+//
+// Parameters: groupName - name of group to change
+// newTrim - trim value
+//
+// Return: void
+//
+//=============================================================================
+void daSoundClipStreamPlayer::ChangeFaderTrim( daSoundGroup groupName, float newTrim )
+{
+ daSoundGroup myGroup = GetSoundGroup();
+
+ //
+ // ChangeTrim should be used for master volume settings
+ //
+ rAssert( groupName != MASTER );
+
+ if ( myGroup == groupName )
+ {
+ SetFaderGroupTrim(newTrim);
+ }
+ else if ( daSoundRenderingManagerGet()->GetTuner()->IsSlaveGroup( myGroup, groupName ) )
+ {
+ SetFaderGroupTrim(newTrim);
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::GetSoundGroup
+//=============================================================================
+// Description: Get the sound group that this player belongs to. This is
+// the sound group that its currently active sound is a part of.
+//
+// Returns: Returns the appropriate sound group.
+//
+//-----------------------------------------------------------------------------
+
+daSoundGroup daSoundClipStreamPlayer::GetSoundGroup( void )
+{
+ daSoundGroup soundGroup = Sound::MASTER;
+ if( m_pAllocatedResource != NULL )
+ {
+ rAssert( m_pAllocatedResource->GetResource( ) != NULL );
+ soundGroup = m_pAllocatedResource->GetResource( )->GetSoundGroup( );
+ }
+ return soundGroup;
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::RegisterSoundPlayerStateCallback
+//=============================================================================
+// Description: Register a sound player state callback
+//
+// Notes: Currently, only one callback is supported.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::RegisterSoundPlayerStateCallback
+(
+ IDaSoundPlayerState* pCallback,
+ void* pUserData
+)
+{
+ rAssertMsg( m_pStateChangeCallback == NULL, "Currently, only one callback is allowed" );
+ m_pStateChangeCallback = pCallback;
+ m_pStateChangeCallbackUserData = pUserData;
+ if( m_pStateChangeCallback != NULL )
+ {
+ m_pStateChangeCallback->AddRef( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::UnregisterSoundPlayerStateCallback
+//=============================================================================
+// Description: Unregister a sound player state callback
+//
+// Notes: Currently, only one callback is supported.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::UnregisterSoundPlayerStateCallback
+(
+ IDaSoundPlayerState* pCallback,
+ void* pUserData
+)
+{
+ rAssert( pCallback == m_pStateChangeCallback );
+ if( m_pStateChangeCallback != NULL )
+ {
+ m_pStateChangeCallback->Release( );
+ m_pStateChangeCallback = NULL;
+ m_pStateChangeCallbackUserData = NULL;
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::GetPlaybackTimeInSamples
+//=============================================================================
+// Description: Get the samples that have elapsed since playback started.
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundClipStreamPlayer::GetPlaybackTimeInSamples( void )
+{
+ // Is this synchronized with play / pause?
+ unsigned int elapsedtime = 0;
+ if( IsCaptured( ) )
+ {
+ // Update the positional information
+ IRadSoundPlayer* pPlayer = NULL;
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ pPlayer = static_cast< IRadSoundPlayer* >
+ (
+ m_ClipInfo.m_pClipPlayer
+ );
+ break;
+ }
+ case IDaSoundResource::STREAM:
+ {
+ pPlayer = static_cast< IRadSoundPlayer* >
+ (
+ m_StreamInfo.m_pResources->m_pStreamPlayer
+ );
+ break;
+ }
+ default:
+ rAssert( 0 );
+ break;
+ }
+ if( pPlayer != NULL )
+ {
+ elapsedtime = pPlayer->GetPlaybackTimeInSamples( );
+ //elapsedtime = ::radSoundHalSystemGet( )->GetReferenceClock( );
+ }
+ }
+
+ // Return the time
+ return( elapsedtime );
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::Play
+//=============================================================================
+// Description: Play the active sound resource.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::Play( void )
+{
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+ rAssert( pFileInstance != NULL );
+
+ #ifndef RAD_RELEASE
+ if ( daSoundFileInstance::Loaded != pFileInstance->GetState( ) )
+ {
+ char fileName[ 256 ];
+ pFileInstance->GetFileName( fileName, 256 );
+
+ rTunePrintf(
+ "\nAUDIO: Controlling code is not paying attention to latency: [%s]\n\n", fileName );
+ }
+ #endif
+
+ switch ( m_State )
+ {
+ case State_Cueing:
+ {
+ m_State = State_CuedPlay;
+ break;
+ }
+ case State_Cued:
+ {
+ m_StoppingTrim = 1.0f;
+
+ // fall through
+ }
+ case State_Stopping:
+ {
+ m_State = State_CuedPlay;
+ m_CueingState = CueingState_Cued;
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ break;
+ }
+ }
+}
+
+
+void daSoundClipStreamPlayer::OnStitch( IRadSoundHalDataSource ** ppHds , unsigned int frameCount, void * pUserData )
+{
+ bool loop = m_pAllocatedResource->GetResource( )->GetLooping( );
+
+ if ( loop || NULL != m_StreamInfo.m_pRsdFileDataSource )
+ {
+ if ( NULL != m_StreamInfo.m_pRsdFileDataSource )
+ {
+ // pass on ref count
+
+ *ppHds = m_StreamInfo.m_pRsdFileDataSource;
+ m_StreamInfo.m_pRsdFileDataSource = NULL;
+ }
+ else
+ {
+ ref< IRadSoundRsdFileDataSource > refFds;
+ m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID )->CreateFileDataSource( & refFds );
+
+ *ppHds = refFds;
+ (*ppHds)->AddRef( );
+ }
+ //rDebugPrintf( "DASOUND: Player: [0x%x] Stitching: [%s]\n", this, refFds->GetName( ) );
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::Pause
+//=============================================================================
+// Description: Pause the active sound resource.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::Pause( void )
+{
+ m_PauseCount++;
+
+ if ( State_Playing == m_State )
+ {
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ m_ClipInfo.m_pClipPlayer->Stop( );
+ break;
+ }
+ case IDaSoundResource::STREAM:
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->Stop( );
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ }
+ }
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::Continue
+//=============================================================================
+// Description: Continue the active sound resource.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::Continue( void )
+{
+ rAssert( m_PauseCount > 0 );
+
+ m_PauseCount--;
+
+ if ( 0 == m_PauseCount )
+ {
+ if ( State_Playing == m_State )
+ {
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ m_ClipInfo.m_pClipPlayer->Play( );
+ break;
+ }
+ case IDaSoundResource::STREAM:
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->Play( );
+ break;
+ }
+ default:
+ {
+ rAssert( false );
+ }
+ }
+ }
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::UberContinue
+//=============================================================================
+// Description: Continue the active sound resource, no matter how many times
+// it was previously paused
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::UberContinue( void )
+{
+ if( IsPaused() )
+ {
+ if( m_PauseCount > 1 )
+ {
+ m_PauseCount = 1;
+ }
+ Continue();
+ }
+}
+
+//=============================================================================
+// Function: daSoundClipStreamPlayer::Stop
+//=============================================================================
+// Description: Stop the active sound resource.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundClipStreamPlayer::Stop( void )
+{
+ if ( State_CuedPlay == m_State )
+ {
+ m_State = State_Cueing;
+ }
+ else if ( State_Playing == m_State )
+ {
+ m_State = State_Stopping;
+ }
+}
+
+void daSoundClipStreamPlayer::HookUpAndCuePlayer( void )
+{
+ rAssert( State_Cueing == m_State || State_CuedPlay == m_State );
+ rAssert( CueingState_Resource == m_CueingState );
+
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+ rAssert( pFileInstance != NULL );
+
+ //
+ // Initialize the group trims
+ //
+ daSoundGroup myGroup = m_pResource->GetSoundGroup();
+ SetMasterTrim( daSoundRenderingManagerGet()->GetTuner()->GetMasterVolume() );
+ SetGroupTrim( daSoundRenderingManagerGet()->GetTuner()->GetGroupTrim( myGroup ) );
+ SetFaderGroupTrim( daSoundRenderingManagerGet()->GetTuner()->GetFaderGroupTrim( myGroup ) );
+
+ switch( m_Type )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ IRadSoundClip * pClip = pFileInstance->GetSoundClip( );
+ rAssert( NULL != pClip );
+
+ // Attach the clip to the player
+ m_ClipInfo.m_pClipPlayer->SetClip( pClip );
+ m_ClipInfo.m_pClipPlayer->SetPositionalGroup( m_IsPositional ? m_pPositionalGroup : NULL );
+
+ break;
+ }
+
+ case IDaSoundResource::STREAM:
+ {
+ m_StreamInfo.m_pResources = SoundNucleusCaptureStreamerResources(
+ m_StreamInfo.m_pRsdFileDataSource->GetFormat( ) );
+
+ rAssert( m_StreamInfo.m_pResources != NULL );
+
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetPositionalGroup( m_IsPositional ? m_pPositionalGroup : NULL );
+
+ m_StreamInfo.m_pResources->m_pStitchedDataSource->SetStitchCallback( this, NULL );
+ m_StreamInfo.m_pResources->m_pStitchedDataSource->ResetAudioFormat( m_StreamInfo.m_pRsdFileDataSource->GetFormat( ) ); // GCN ADPCM HACK
+ m_StreamInfo.m_pResources->m_pStitchedDataSource->Reset( );
+
+ if ( NULL != m_StreamInfo.m_pResources->m_pBufferedDataSource )
+ {
+ m_StreamInfo.m_pResources->m_pBufferedDataSource->SetInputDataSource( m_StreamInfo.m_pResources->m_pStitchedDataSource );
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetDataSource( m_StreamInfo.m_pResources->m_pBufferedDataSource );
+ }
+ else
+ {
+ m_StreamInfo.m_pResources->m_pStreamPlayer->SetDataSource(
+ m_StreamInfo.m_pResources->m_pStitchedDataSource );
+ }
+
+
+ break;
+ }
+ default:
+ rAssert( 0 );
+ break;
+ }
+
+ m_CueingState = CueingState_Player;
+}
+
+const void daSoundClipStreamPlayer::GetFileName( char * pBuf, unsigned int max )
+{
+ rAssert( m_pAllocatedResource );
+
+ daSoundFileInstance* pFileInstance = m_pAllocatedResource->GetFileInstance( m_AllocResInstanceID );
+
+ return pFileInstance->GetFileName( pBuf, max );
+
+}
+
+} // Sound Namespace
+ \ No newline at end of file
diff --git a/game/code/sound/soundrenderer/fader.cpp b/game/code/sound/soundrenderer/fader.cpp
new file mode 100644
index 0000000..125fc9e
--- /dev/null
+++ b/game/code/sound/soundrenderer/fader.cpp
@@ -0,0 +1,483 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: fader.cpp
+//
+// Description: Implementation for Fader class which brings down volume on
+// associated multi-input knob. Replaces IRadSoundFade
+// objects from radsound/util.
+//
+// History: 13/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+#include <float.h>
+#include <radmath/radmath.hpp>
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundrenderer/fader.h>
+
+#include <sound/soundrenderer/playermanager.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+
+using namespace Sound;
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+Fader* Fader::s_faderUpdateList = NULL;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// Fader::Fader
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Fader::Fader( globalSettings* duckSettings,
+ DuckSituations situation,
+ daSoundPlayerManager& playerMgr,
+ IDaSoundTuner& tuner ) :
+ m_duckSituation( situation ),
+ m_playerManager( playerMgr ),
+ m_tuner( tuner )
+{
+ m_Time = 750;
+ m_In = true;
+ m_State = FadedIn;
+ m_callback = NULL;
+ m_nextUpdatableFader = NULL;
+
+ ReinitializeFader( duckSettings );
+}
+
+//==============================================================================
+// Fader::~Fader
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+Fader::~Fader()
+{
+ if( s_faderUpdateList != NULL )
+ {
+ removeFromUpdateList();
+ }
+}
+
+//========================================================================
+// Fader::SetTime
+//========================================================================
+
+void Fader::SetTime( unsigned int milliseconds )
+{
+ m_Time = milliseconds;
+}
+
+//========================================================================
+// Fader::GetTime
+//========================================================================
+
+unsigned int Fader::GetTime( void )
+{
+ return m_Time;
+}
+
+//========================================================================
+// Fader::BroadCast
+//========================================================================
+
+void Fader::BroadCast( void )
+{
+ m_playerManager.PlayerFaderVolumeChange( SOUND_EFFECTS, m_currentVolumes.duckVolume[DUCK_SFX] );
+ m_playerManager.PlayerFaderVolumeChange( CARSOUND, m_currentVolumes.duckVolume[DUCK_CAR] );
+ m_playerManager.PlayerFaderVolumeChange( DIALOGUE, m_currentVolumes.duckVolume[DUCK_DIALOG] );
+ m_playerManager.PlayerFaderVolumeChange( MUSIC, m_currentVolumes.duckVolume[DUCK_MUSIC] );
+ m_playerManager.PlayerFaderVolumeChange( AMBIENCE, m_currentVolumes.duckVolume[DUCK_AMBIENCE] );
+
+ m_tuner.SetFaderGroupTrim( DUCK_SFX, m_currentVolumes.duckVolume[DUCK_SFX] );
+ m_tuner.SetFaderGroupTrim( DUCK_CAR, m_currentVolumes.duckVolume[DUCK_CAR] );
+ m_tuner.SetFaderGroupTrim( DUCK_DIALOG, m_currentVolumes.duckVolume[DUCK_DIALOG] );
+ m_tuner.SetFaderGroupTrim( DUCK_MUSIC, m_currentVolumes.duckVolume[DUCK_MUSIC] );
+ m_tuner.SetFaderGroupTrim( DUCK_AMBIENCE, m_currentVolumes.duckVolume[DUCK_AMBIENCE] );
+}
+
+//========================================================================
+// Fader::Fade
+//========================================================================
+
+void Fader::Fade( bool in, DuckVolumeSet* initialVolumes, DuckVolumeSet* targetVolumes )
+{
+ unsigned int i;
+
+ m_In = in;
+
+ //
+ // Set current values to whatever we're fading from and target values
+ // to whatever we're fading to
+ //
+ if( initialVolumes != NULL )
+ {
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ m_currentVolumes.duckVolume[i] = initialVolumes->duckVolume[i];
+ }
+ }
+ else
+ {
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ if( m_In )
+ {
+ m_currentVolumes.duckVolume[i] = m_globalDuckSettings.duckVolume[i];
+ }
+ else
+ {
+ m_currentVolumes.duckVolume[i] = 1.0f;
+ }
+ }
+ }
+
+ if( targetVolumes != NULL )
+ {
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ m_targetVolumes.duckVolume[i] = targetVolumes->duckVolume[i];
+ }
+ }
+ else
+ {
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ if( m_In )
+ {
+ m_targetVolumes.duckVolume[i] = 1.0f;
+ }
+ else
+ {
+ m_targetVolumes.duckVolume[i] = m_globalDuckSettings.duckVolume[i];
+ }
+ }
+ }
+
+ //
+ // Now calculate the time steps
+ //
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ if ( m_Time == 0 )
+ {
+ // avoid divide by zero
+
+ m_stepValues[i] = FLT_MAX / 10.0f; // Some arbitrarily large number
+ }
+ else
+ {
+ m_stepValues[i] = ( rmt::Fabs( m_currentVolumes.duckVolume[i] - m_targetVolumes.duckVolume[i] ) ) / ( m_Time );
+ }
+ }
+
+ setState( );
+
+ addToUpdateList( );
+}
+
+//========================================================================
+// Fader::RegisterStateCallback
+//========================================================================
+
+void Fader::RegisterStateCallback( FaderStateChangeCallback* callback )
+{
+ //
+ // I'm assuming only one callback is set at a time
+ //
+ rAssert( m_callback == NULL );
+ m_callback = callback;
+}
+
+//========================================================================
+// Fader::UnRegisterStateCallback
+//========================================================================
+
+void Fader::UnRegisterStateCallback( FaderStateChangeCallback* callback )
+{
+ //
+ // Accept the callback as a parameter to test my assumption that
+ // we only set one at a time
+ //
+ rAssert( m_callback == callback );
+
+ m_callback = NULL;
+}
+
+//========================================================================
+// Fader::GetState
+//========================================================================
+
+Fader::State Fader::GetState( void )
+{
+ unsigned int i;
+ float targetValue;
+ State currentState = m_In ? FadedIn : FadedOut;
+
+ //
+ // Test each of the fading volumes. If one of them hasn't hit
+ // the target yet, we're still fading
+ //
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ targetValue = m_In ? 1.0f : m_globalDuckSettings.duckVolume[i];
+
+ if( m_currentVolumes.duckVolume[i] != targetValue )
+ {
+ currentState = m_In ? FadingIn : FadingOut;
+ break;
+ }
+ }
+
+ return( currentState );
+}
+
+//========================================================================
+// Fader::OnTimerDone
+//========================================================================
+
+void Fader::Update( unsigned int elapsed )
+{
+ unsigned int i;
+ float stepValue;
+ bool allTargetsHit = true;
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ stepValue = m_stepValues[i] * elapsed; // adjust for game chug.
+
+ if ( stepValue >= radSoundVolumeChangeThreshold )
+ {
+ stepValue = radSoundVolumeChangeThreshold;
+ }
+
+ if ( m_currentVolumes.duckVolume[i] < m_targetVolumes.duckVolume[i] )
+ {
+ m_currentVolumes.duckVolume[i] += stepValue;
+
+ if ( m_currentVolumes.duckVolume[i] >= m_targetVolumes.duckVolume[i] )
+ {
+ m_currentVolumes.duckVolume[i] = m_targetVolumes.duckVolume[i];
+ }
+ else
+ {
+ allTargetsHit = false;
+ }
+ }
+ else if ( m_currentVolumes.duckVolume[i] > m_targetVolumes.duckVolume[i] )
+ {
+ m_currentVolumes.duckVolume[i] -= stepValue;
+
+ if ( m_currentVolumes.duckVolume[i] <= m_targetVolumes.duckVolume[i] )
+ {
+ m_currentVolumes.duckVolume[i] = m_targetVolumes.duckVolume[i];
+ }
+ else
+ {
+ allTargetsHit = false;
+ }
+ }
+
+ }
+
+ BroadCast();
+
+ if ( allTargetsHit )
+ {
+ removeFromUpdateList( );
+
+ setState( );
+ }
+}
+
+//=============================================================================
+// Fader::UpdateAllFaders
+//=============================================================================
+// Description: Run through the fader list and update everything
+//
+// Parameters: elapsedTime - number of elapsed msecs since last call
+//
+// Return: void
+//
+//=============================================================================
+void Fader::UpdateAllFaders( unsigned int elapsedTime )
+{
+ Fader* currFader;
+
+ currFader = s_faderUpdateList;
+ while( currFader != NULL )
+ {
+ currFader->Update( elapsedTime );
+ currFader = currFader->m_nextUpdatableFader;
+ }
+}
+
+//=============================================================================
+// Fader::ReinitializeFader
+//=============================================================================
+// Description: Get the ducking parameters from the global settings object
+//
+// Parameters: ( globalSettings* settingObj )
+//
+// Return: void
+//
+//=============================================================================
+void Fader::ReinitializeFader( globalSettings* settingObj )
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ if( settingObj == NULL )
+ {
+ m_globalDuckSettings.duckVolume[i] = 0.0f;
+ }
+ else
+ {
+ m_globalDuckSettings.duckVolume[i] =
+ settingObj->GetDuckVolume( m_duckSituation, static_cast<Sound::DuckVolumes>(i) );
+ }
+ }
+}
+
+//=============================================================================
+// Fader::Stop
+//=============================================================================
+// Description: Fader is being interrupted, get it out of the update list
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void Fader::Stop()
+{
+ removeFromUpdateList();
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//========================================================================
+// Fader::setState
+//========================================================================
+
+void Fader::setState( void )
+{
+
+ if ( GetState( ) != m_State )
+ {
+ m_State = GetState( );
+
+ if( m_callback != NULL )
+ {
+ m_callback->OnStateChange( m_State );
+ }
+ }
+}
+
+//========================================================================
+// Fader::addToUpdateList
+//========================================================================
+void Fader::addToUpdateList()
+{
+ if( !faderInUpdateList() )
+ {
+ //
+ // Order doesn't matter, add it to the head of the list
+ //
+ m_nextUpdatableFader = s_faderUpdateList;
+ s_faderUpdateList = this;
+ }
+}
+
+//========================================================================
+// Fader::removeFromUpdateList
+//========================================================================
+void Fader::removeFromUpdateList()
+{
+ Fader* currentFader;
+
+ //
+ // Search for position in list. The list is usually one or two faders,
+ // I think, so don't bother with double-linked lists.
+ //
+ if( s_faderUpdateList == this )
+ {
+ s_faderUpdateList = m_nextUpdatableFader;
+ }
+ else
+ {
+ currentFader = s_faderUpdateList;
+ while( ( currentFader != NULL )
+ && ( currentFader->m_nextUpdatableFader != this ) )
+ {
+ currentFader = currentFader->m_nextUpdatableFader;
+ }
+
+ if( currentFader != NULL )
+ {
+ currentFader->m_nextUpdatableFader = m_nextUpdatableFader;
+ }
+ }
+
+ m_nextUpdatableFader = NULL;
+}
+
+//=============================================================================
+// Fader::faderInUpdateList
+//=============================================================================
+// Description: Indicate whether this fader is currently in the update list
+//
+// Parameters: None
+//
+// Return: true if in list, false otherwise
+//
+//=============================================================================
+bool Fader::faderInUpdateList()
+{
+ Fader* currFader;
+
+ currFader = s_faderUpdateList;
+ while( currFader != NULL )
+ {
+ if( currFader == this )
+ {
+ return( true );
+ }
+
+ currFader = currFader->m_nextUpdatableFader;
+ }
+
+ return( false );
+}
diff --git a/game/code/sound/soundrenderer/fader.h b/game/code/sound/soundrenderer/fader.h
new file mode 100644
index 0000000..492080d
--- /dev/null
+++ b/game/code/sound/soundrenderer/fader.h
@@ -0,0 +1,146 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: fader.h
+//
+// Description: Declaration for Fader class which brings down volume on
+// associated multi-input knob. Replaces IRadSoundFade
+// objects from radsound/util.
+//
+// History: 13/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef FADER_H
+#define FADER_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+
+#include <sound/soundrenderer/dasoundgroup.h>
+#include <sound/tuning/globalsettings.h>
+
+//========================================
+// Forward References
+//========================================
+
+struct FaderStateChangeCallback;
+
+namespace Sound
+{
+ class daSoundPlayerManager;
+ struct IDaSoundTuner;
+}
+
+//=============================================================================
+//
+// Synopsis: Fader
+//
+//=============================================================================
+
+class Fader : public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "Fader" );
+
+ Fader( globalSettings* duckSettings,
+ Sound::DuckSituations situation,
+ Sound::daSoundPlayerManager& playerMgr,
+ Sound::IDaSoundTuner& tuner );
+ ~Fader();
+
+ void Update( unsigned int elapsed );
+ static void UpdateAllFaders( unsigned int elapsedTime );
+
+ void Stop();
+
+ void SetTime( unsigned int milliseconds );
+ unsigned int GetTime( void );
+
+ void Fade( bool in, Sound::DuckVolumeSet* initialVolumes = NULL, Sound::DuckVolumeSet* targetVolumes = NULL );
+
+ float GetCurrentVolume( Sound::DuckVolumes volumeKnob ) { return( m_currentVolumes.duckVolume[volumeKnob] ); }
+ float GetTargetSettings( Sound::DuckVolumes volumeKnob ) { return( m_globalDuckSettings.duckVolume[volumeKnob] ); }
+
+ enum State { FadedIn, FadedOut, FadingIn, FadingOut };
+
+ void RegisterStateCallback( FaderStateChangeCallback* callback );
+ void UnRegisterStateCallback( FaderStateChangeCallback* callback );
+
+ State GetState( void );
+
+ void BroadCast( void );
+
+ Sound::DuckSituations GetSituation( void ) { return( m_duckSituation ); }
+
+ void ReinitializeFader( globalSettings* settingObj );
+
+ private:
+ //Prevent wasteful constructor creation.
+ Fader();
+ Fader( const Fader& original );
+ Fader& operator=( const Fader& rhs );
+
+ void setState();
+
+ //
+ // Add and remove fader from the update list. We should only update
+ // the fader if it's not on its target value yet.
+ //
+ void addToUpdateList();
+ void removeFromUpdateList();
+ bool faderInUpdateList();
+
+ unsigned int m_Time;
+ bool m_In;
+ State m_State;
+
+ Sound::DuckVolumeSet m_currentVolumes;
+ float m_stepValues[Sound::NUM_DUCK_VOLUMES];
+ Sound::DuckVolumeSet m_targetVolumes;
+ Sound::DuckVolumeSet m_globalDuckSettings;
+
+ Sound::DuckSituations m_duckSituation;
+
+ //
+ // Callback object for state change notification. Was a list of objects
+ // in radSoundFade
+ //
+ FaderStateChangeCallback* m_callback;
+
+ //
+ // Static fader list, used for updates
+ //
+ static Fader* s_faderUpdateList;
+
+ //
+ // Pointer used to hold place in update list
+ //
+ Fader* m_nextUpdatableFader;
+
+ //
+ // Player manager, used to actually do the fading
+ //
+ Sound::daSoundPlayerManager& m_playerManager;
+
+ //
+ // Tuner, stores the results
+ //
+ Sound::IDaSoundTuner& m_tuner;
+};
+
+//=============================================================================
+//
+// Synopsis: FaderStateChangeCallback
+//
+//=============================================================================
+struct FaderStateChangeCallback
+{
+ virtual void OnStateChange( Fader::State newState );
+};
+
+
+#endif // FADER_H
+
diff --git a/game/code/sound/soundrenderer/idasoundresource.h b/game/code/sound/soundrenderer/idasoundresource.h
new file mode 100644
index 0000000..f6564db
--- /dev/null
+++ b/game/code/sound/soundrenderer/idasoundresource.h
@@ -0,0 +1,172 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: idasoundresource.hpp
+//
+// Subsystem: Dark Angel - Sound resources
+//
+// Description: Defines the interface for a sound resource
+//
+// WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// IF THIS FILE IS MODIFIED THE TYPE INFO FILE MUST BE REGENERATED
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// Revisions:
+// + Created October 3, 2001 -- aking
+//
+//=============================================================================
+
+#ifndef _IDASOUNDRESOURCE_HPP
+#define _IDASOUNDRESOURCE_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+
+#include <sound/soundrenderer/dasoundgroup.h>
+
+//=============================================================================
+// Definitions and macros
+//=============================================================================
+
+//
+// This is the maximum number of file variations that can exist in a resource.
+//
+#define DASound_MaxNumSoundResourceFiles 7
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+struct IDaSoundResource;
+
+//=============================================================================
+// Typedefs and enumerations
+//=============================================================================
+
+//
+// A procedure used to modify a sound resource
+//
+typedef void daSoundResourceProc( IDaSoundResource* pRes, void* pUserData );
+
+//=============================================================================
+// Interface Definitions
+//=============================================================================
+
+//
+// IDaSoundResourceData contains sound resource data.
+//
+struct IDaSoundResourceData : public IRefCount
+{
+ // SCRIPTED FEATURES THAT CAN BE TUNED IN REAL TIME
+
+ //
+ // Add files to the resource
+ //
+ virtual void AddFilename
+ (
+ const char* newFileName,
+ float trim
+ ) = 0;
+
+ //
+ // Set the pitch variation
+ //
+ virtual void SetPitchRange
+ (
+ float minPitch,
+ float maxPitch
+ ) = 0;
+
+ //
+ // Set the trim variation
+ //
+ virtual void SetTrimRange
+ (
+ float minTrim,
+ float maxTrim
+ ) = 0;
+
+ //
+ // Set the trim to one value
+ //
+ virtual void SetTrim( float trim ) = 0;
+
+ // SCRIPTED FEATURES THAT CAN NOT BE TUNED IN REAL TIME
+
+ // Is this a streaming sound resource?
+ virtual void SetStreaming( bool streaming ) = 0;
+
+ // Is this a looping sound resource?
+ virtual void SetLooping( bool looping ) = 0;
+
+ // SCRIPTED FEATURES AVAILABLE ONLY FOR TUNERS
+
+ // Play the resource
+ virtual void Play( void ) = 0;
+};
+
+//
+// IDaSoundResource is based on an IDaSoundResourceData. It adds functionality
+// to get parameters, and to capture/release resources.
+//
+struct IDaSoundResource : public IDaSoundResourceData
+{
+ // A resource file description
+ struct daSoundResourceFileDesc
+ {
+ char* m_Filename;
+ float m_Trim;
+ int m_TableIndex;
+ };
+
+ //
+ // Monitor files in the resource
+ //
+ virtual unsigned int GetNumFiles( void ) = 0;
+
+ virtual void GetFileNameAt( unsigned int index, char* buffer, unsigned int max ) = 0;
+ virtual void GetFileKeyAt( unsigned int index, char* buffer, unsigned int max ) = 0;
+ //
+ // Get parameters set in IDaSoundResourceData
+ //
+ virtual void GetPitchRange
+ (
+ float* pMinPitch,
+ float* pMaxPitch
+ ) = 0;
+ virtual void GetTrimRange
+ (
+ float* pMinTrim,
+ float* pMaxTrim
+ ) = 0;
+ virtual bool GetLooping( void ) = 0;
+
+ //
+ // Find out what kind of resource this is
+ //
+ enum Type {
+ UNKNOWN,
+ CLIP,
+ STREAM
+ };
+ virtual Type GetType( void ) = 0;
+
+ //
+ // Modify the sound group that this resource belongs to
+ //
+ virtual void SetSoundGroup( Sound::daSoundGroup soundGroup ) = 0;
+ virtual Sound::daSoundGroup GetSoundGroup( void ) = 0;
+
+ //
+ // Capture and release the resource
+ //
+ virtual void CaptureResource( void ) = 0;
+ virtual bool IsCaptured( void ) = 0;
+ virtual void ReleaseResource( void ) = 0;
+};
+
+//}; //Sound Namespace
+#endif // _IDASOUNDRESOURCE_HPP
diff --git a/game/code/sound/soundrenderer/idasoundtuner.h b/game/code/sound/soundrenderer/idasoundtuner.h
new file mode 100644
index 0000000..c537af2
--- /dev/null
+++ b/game/code/sound/soundrenderer/idasoundtuner.h
@@ -0,0 +1,205 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: idasoundtuner.hpp
+//
+// Subsystem: Dark Angel - Sound Tuner System
+//
+// Description: Description of the DA sound tuner interface
+//
+// Revisions:
+// + Created October 4, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _IDASOUNDTUNER_HPP
+#define _IDASOUNDTUNER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+
+#include <sound/soundrenderer/dasoundgroup.h>
+#include <sound/soundrenderer/soundsystem.h>
+
+#include <sound/tuning/globalsettings.h>
+
+//=============================================================================
+// Global namespace forward declarations
+//=============================================================================
+
+struct IRadSoundMultiInputKnob;
+class Fader;
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+struct IDaSoundWiring;
+struct IDaSoundTuner;
+struct IDaSoundFadeState;
+
+//=============================================================================
+// Interfaces
+//=============================================================================
+
+//
+// Wire together various sound groups that take the form of multi-input
+// knobs.
+//
+struct IDaSoundWiring : public IRefCount
+{
+ //
+ // Wire a sound group to a path
+ //
+ virtual void WirePath
+ (
+ daSoundGroup soundGroup,
+ const char* path
+ ) = 0;
+
+ //
+ // Initialize the sound groups
+ //
+ virtual void WireGroup( daSoundGroup slaveGroup, daSoundGroup masterGroup ) = 0;
+};
+
+//
+// The sound tuner is responsible for managing global settings and various
+// "wirings" of the sound system. It allows the generation of tuner instances
+// for controlling various game parameters, and it manages common global
+// sound settings (like ducking, master volume, pause/continue/cancel,
+// mono/stereo).
+//
+struct IDaSoundTuner : public IDaSoundWiring
+{
+ //
+ // Initialize and perform all wiring. This will lock down the resources
+ // if they have not been locked already.
+ //
+ virtual void Initialize( void ) = 0;
+
+ //
+ // Create faders after we've got scripts to latch them to
+ //
+ virtual void PostScriptLoadInitialize() = 0;
+
+ //
+ // Service the tuner
+ //
+ virtual void ServiceOncePerFrame( unsigned int elapsedTime ) = 0;
+
+ //
+ // Modify the sound output mode
+ //
+ enum SoundOutputMode
+ {
+ MONO,
+ STEREO,
+ SURROUND
+ };
+ virtual void SetSoundOutputMode
+ (
+ SoundOutputMode outputMode
+ ) = 0;
+ virtual SoundOutputMode GetSoundOutputMode( void ) = 0;
+
+ // SPECIALIZED SOUND SETTINGS FOR COMMON CONTROL
+
+ //
+ // Duck sounds
+ //
+ virtual void ActivateDuck( IDaSoundFadeState* pObject,
+ void* pUserData,
+ bool fadeIn ) = 0;
+
+ virtual void ActivateSituationalDuck( IDaSoundFadeState* pObject,
+ DuckSituations situation,
+ void* pUserData,
+ bool fadeIn ) = 0;
+ virtual void ResetDuck() = 0;
+
+ //
+ // Common volume controls
+ //
+ virtual void SetMasterVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetMasterVolume( void ) = 0;
+
+ virtual void SetDialogueVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetDialogueVolume( void ) = 0;
+
+ virtual void SetMusicVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetMusicVolume( void ) = 0;
+
+ virtual void SetAmbienceVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetAmbienceVolume( void ) = 0;
+
+ virtual void SetSfxVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetSfxVolume( void ) = 0;
+
+ virtual void SetCarVolume( daTrimValue volume ) = 0;
+ virtual daTrimValue GetCarVolume( void ) = 0;
+
+ virtual daTrimValue GetGroupTrim( daSoundGroup group ) = 0;
+ virtual daTrimValue GetFaderGroupTrim( daSoundGroup group ) = 0;
+
+ virtual void MuteNIS() = 0;
+ virtual void UnmuteNIS() = 0;
+
+ virtual void SetFaderGroupTrim( Sound::DuckVolumes group, daTrimValue trim ) = 0;
+
+ // GENERAL SOUND SETTINGS
+
+ //
+ // Fade a sound group
+ //
+ virtual void FadeSounds( IDaSoundFadeState* pObject,
+ void* pUserData,
+ Fader* pFader,
+ bool fadeIn,
+ DuckVolumeSet* initialVolumes = NULL ) = 0;
+
+
+ //
+ // Sound group info
+ //
+ virtual bool IsSlaveGroup( daSoundGroup slave, daSoundGroup master ) = 0;
+
+};
+
+//=============================================================================
+// Public functions
+//=============================================================================
+
+//
+// Do the wiring of the sound system
+//
+void daSoundTunerWireSystem
+(
+ IDaSoundWiring* pWiring
+);
+
+//=============================================================================
+// Factory functions
+//=============================================================================
+
+//
+// Create the tuner manager
+//
+void daSoundTunerCreate
+(
+ IDaSoundTuner** ppTuner,
+ radMemoryAllocator allocator
+);
+
+} // Sound Namespace
+#endif //_IDASOUNDTUNER_HPP
+
diff --git a/game/code/sound/soundrenderer/musicsoundplayer.cpp b/game/code/sound/soundrenderer/musicsoundplayer.cpp
new file mode 100644
index 0000000..365b8ef
--- /dev/null
+++ b/game/code/sound/soundrenderer/musicsoundplayer.cpp
@@ -0,0 +1,300 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: musicsoundplayer.cpp
+//
+// Subsystem: Dark Angel - Sound players
+//
+// Description: Implements the a Dark Angel sound player
+//
+// Revisions:
+// + Created October 16, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <sound/soundrenderer/musicsoundplayer.h>
+
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+
+#include <sound/soundmanager.h>
+
+//=============================================================================
+// Static Variables (outside namespace)
+//=============================================================================
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Debug Information
+//=============================================================================
+
+//=============================================================================
+// Definitions Macros and Constants
+//=============================================================================
+
+//=============================================================================
+// Local functions
+//=============================================================================
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// MusicSoundPlayer Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: MusicSoundPlayer::MusicSoundPlayer
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+MusicSoundPlayer::MusicSoundPlayer( )
+ :
+ m_isMusic( true ),
+ m_PlayerTrim( 1.0f ),
+ m_ResourceTrim( 1.0f ),
+ m_ExternalTrim( 1.0f ),
+ m_GroupTrim( 1.0f ),
+ m_FaderGroupTrim( 1.0f ),
+ m_MasterTrim( 1.0f )
+{
+}
+
+//=============================================================================
+// Function: MusicSoundPlayer::~MusicSoundPlayer
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+MusicSoundPlayer::~MusicSoundPlayer( )
+{
+}
+
+//=============================================================================
+// Function: MusicSoundPlayer::Initialize
+//=============================================================================
+// Description: Initialize the sound player to determine whether it will
+// set the trim for music or ambience
+//
+//-----------------------------------------------------------------------------
+void MusicSoundPlayer::Initialize( bool isMusic )
+{
+ m_isMusic = isMusic;
+
+ //
+ // Set the group trim
+ //
+ if( m_isMusic )
+ {
+ SetGroupTrim( daSoundRenderingManagerGet()->GetTuner()->GetGroupTrim( Sound::MUSIC ) );
+ }
+ else
+ {
+ SetGroupTrim( daSoundRenderingManagerGet()->GetTuner()->GetGroupTrim( Sound::AMBIENCE ) );
+ }
+}
+
+//=============================================================================
+// MusicSoundPlayer::GetSoundGroup
+//=============================================================================
+// Description: Unlike regular sound players, our group is determined by
+// the music/ambience specification from initialization, not
+// by an associated sound resource
+//
+// Parameters: None
+//
+// Return: sound group (either MUSIC or AMBIENCE)
+//
+//=============================================================================
+daSoundGroup MusicSoundPlayer::GetSoundGroup()
+{
+ if( m_isMusic )
+ {
+ return( Sound::MUSIC );
+ }
+ else
+ {
+ return( Sound::AMBIENCE );
+ }
+}
+
+//=============================================================================
+// MusicSoundPlayer::SetExternalTrim
+//=============================================================================
+// Description: Set arbitrary player trim. May not be needed.
+//
+// Parameters: newTrim - new trim value
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::SetExternalTrim( float newTrim )
+{
+ m_ExternalTrim = newTrim;
+ m_PlayerTrim = m_ResourceTrim * m_ExternalTrim * m_GroupTrim * m_FaderGroupTrim * m_MasterTrim;
+
+ ResetMusicTrim();
+}
+
+//=============================================================================
+// MusicSoundPlayer::SetGroupTrim
+//=============================================================================
+// Description: Set sound group trim
+//
+// Parameters: newTrim - new trim setting
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::SetGroupTrim( float newTrim )
+{
+ m_GroupTrim = newTrim;
+ m_PlayerTrim = m_ResourceTrim * m_ExternalTrim * m_GroupTrim * m_FaderGroupTrim * m_MasterTrim;
+
+ ResetMusicTrim();
+}
+
+//=============================================================================
+// MusicSoundPlayer::SetFaderGroupTrim
+//=============================================================================
+// Description: Set sound group fader trim
+//
+// Parameters: newTrim - new trim setting
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::SetFaderGroupTrim( float newTrim )
+{
+ m_FaderGroupTrim = newTrim;
+ m_PlayerTrim = m_ResourceTrim * m_ExternalTrim * m_GroupTrim * m_FaderGroupTrim * m_MasterTrim;
+
+ ResetMusicTrim();
+}
+
+//=============================================================================
+// MusicSoundPlayer::SetMasterTrim
+//=============================================================================
+// Description: Set master trim. Duh.
+//
+// Parameters: newTrim - new trim setting
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::SetMasterTrim( float newTrim )
+{
+ m_MasterTrim = newTrim;
+ m_PlayerTrim = m_ResourceTrim * m_ExternalTrim * m_GroupTrim * m_FaderGroupTrim * m_MasterTrim;
+
+ ResetMusicTrim();
+}
+
+//
+// TODO: revisit trim functions below. They're identical to the one in the base
+// class, should be virtual.
+//
+
+//=============================================================================
+// MusicSoundPlayer::ChangeTrim
+//=============================================================================
+// Description: Change the trim setting for a sound group, or for the master
+// volume
+//
+// Parameters: groupName - name of group to change
+// newTrim - trim value
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::ChangeTrim( daSoundGroup groupName, float newTrim )
+{
+ daSoundGroup myGroup = GetSoundGroup();
+
+ if ( myGroup == groupName )
+ {
+ SetGroupTrim(newTrim);
+ }
+ else if ( groupName == MASTER )
+ {
+ SetMasterTrim(newTrim);
+ }
+ else if ( daSoundRenderingManagerGet()->GetTuner()->IsSlaveGroup( myGroup, groupName ) )
+ {
+ SetGroupTrim(newTrim);
+ }
+}
+
+//=============================================================================
+// MusicSoundPlayer::ChangeFaderTrim
+//=============================================================================
+// Description: Change the trim setting for a sound group, or for the master
+// volume
+//
+// Parameters: groupName - name of group to change
+// newTrim - trim value
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::ChangeFaderTrim( daSoundGroup groupName, float newTrim )
+{
+ daSoundGroup myGroup = GetSoundGroup();
+
+ //
+ // Shouldn't change master volume here, use ChangeTrim
+ //
+ rAssert( groupName != MASTER );
+
+ if ( myGroup == groupName )
+ {
+ SetFaderGroupTrim(newTrim);
+ }
+ else if ( daSoundRenderingManagerGet()->GetTuner()->IsSlaveGroup( myGroup, groupName ) )
+ {
+ SetFaderGroupTrim(newTrim);
+ }
+}
+
+
+//=============================================================================
+// Private functions
+//=============================================================================
+
+//=============================================================================
+// MusicSoundPlayer::resetMusicTrim
+//=============================================================================
+// Description: Update the music player with the given trim setting
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void MusicSoundPlayer::ResetMusicTrim()
+{
+ if( m_isMusic )
+ {
+ GetSoundManager()->SetMusicVolumeWithoutTuner( m_PlayerTrim );
+ }
+ else
+ {
+ GetSoundManager()->SetAmbienceVolumeWithoutTuner( m_PlayerTrim );
+ }
+}
+
+} // Sound Namespace
+
diff --git a/game/code/sound/soundrenderer/musicsoundplayer.h b/game/code/sound/soundrenderer/musicsoundplayer.h
new file mode 100644
index 0000000..15cedb3
--- /dev/null
+++ b/game/code/sound/soundrenderer/musicsoundplayer.h
@@ -0,0 +1,112 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: musicsoundplayer.hpp
+//
+// Subsystem: Dark Angel - Sound players
+//
+// Description: Used to hack in volume control for RadMusic, even though
+// it doesn't go through the DA system
+//
+// Revisions:
+// + Hacked 5 Mar 03 -- Esan
+//
+//=============================================================================
+
+#ifndef _MUSICSOUNDPLAYER_HPP
+#define _MUSICSOUNDPLAYER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <sound/soundrenderer/soundplayer.h>
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+//=============================================================================
+// Typdefs and enumerations
+//=============================================================================
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+//
+// This contains a DA player instance.
+//
+class MusicSoundPlayer : public daSoundPlayerBase
+{
+public:
+ //
+ // Constructor and destructor
+ //
+ MusicSoundPlayer ( );
+ virtual ~MusicSoundPlayer ( );
+
+ void Initialize ( bool isMusic );
+
+ // Suspend the player if it should be playing, but no one can hear it
+ void Suspend ( void );
+
+ void SetExternalTrim( float newTrim );
+ void SetGroupTrim( float newTrim );
+ void SetFaderGroupTrim( float newTrim );
+ void SetMasterTrim( float newTrim );
+
+ daSoundGroup GetSoundGroup ( void );
+
+ unsigned int GetPlaybackTimeInSamples ( void );
+
+ // daSoundPlayerBase
+
+ virtual void ServiceOncePerFrame( void ) { }
+ virtual bool IsCaptured ( void ) { return true; }
+ virtual void Pause ( void ) { }
+ virtual bool IsPaused( void ) { return false; }
+ virtual void Continue ( void ) { }
+ virtual void UberContinue( void ) { }
+ virtual void Stop ( void ) { }
+ virtual void SetPitch( float pitch ) { }
+
+ virtual void ChangeTrim( daSoundGroup groupName, float newTrim );
+ virtual void ChangeFaderTrim( daSoundGroup groupName, float newTrim );
+
+
+private:
+ void ResetMusicTrim( );
+
+ bool m_isMusic;
+
+ //
+ // Trim values
+ //
+ float m_PlayerTrim;
+ float m_ResourceTrim;
+ float m_ExternalTrim;
+ float m_GroupTrim;
+ float m_FaderGroupTrim;
+ float m_MasterTrim;
+
+};
+
+
+//=============================================================================
+// Public Functions
+//=============================================================================
+
+} // Sound Namespace
+#endif //_MUSICSOUNDPLAYER_HPP
+
diff --git a/game/code/sound/soundrenderer/playermanager.cpp b/game/code/sound/soundrenderer/playermanager.cpp
new file mode 100644
index 0000000..9a92b77
--- /dev/null
+++ b/game/code/sound/soundrenderer/playermanager.cpp
@@ -0,0 +1,989 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: playermagaer.cpp
+//
+// Subsystem: Dark Angel - Player Manager System
+//
+// Description: Implementation of the DA sound player manager
+//
+// Revisions:
+// + Created October 16, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radobjectlist.hpp>
+#include <raddebug.hpp>
+#include <radlinkedclass.hpp>
+#include <radnamespace.hpp>
+#include <radsound_hal.hpp>
+
+#include <memory/srrmemory.h>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/dasoundgroup.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/playermanager.h>
+#include <sound/soundrenderer/soundplayer.h>
+#include <sound/soundrenderer/musicsoundplayer.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/fader.h>
+#include <sound/soundrenderer/soundconstants.h>
+#include <sound/soundrenderer/soundnucleus.hpp>
+
+#include <pddi/pddi.hpp>
+#include <p3d/utility.hpp>
+#include <p3d/p3dtypes.hpp>
+
+#include <radobjectbtree.hpp>
+
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Debug Information
+//=============================================================================
+
+daSoundPlayerManager * daSoundPlayerManager::s_pInstance = 0;
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundAsyncFadeCallback Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::daSoundAsyncFadeCallback
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundAsyncFadeCallback::daSoundAsyncFadeCallback( )
+:
+radObject( ),
+m_Action( 0 ),
+m_pPlayerManager( NULL ),
+m_pCallback( NULL ),
+m_pUserData( NULL )
+{
+
+}
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::~daSoundAsyncFadeCallback
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundAsyncFadeCallback::~daSoundAsyncFadeCallback( )
+{
+
+ if( m_pCallback != NULL )
+ {
+ m_pCallback->Release( );
+ }
+ if( m_pPlayerManager != NULL )
+ {
+ m_pPlayerManager->Release( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::SetPlayerManager
+//=============================================================================
+// Description: Set the player manager
+//
+//-----------------------------------------------------------------------------
+
+void daSoundAsyncFadeCallback::SetPlayerManager
+(
+ daSoundPlayerManager* pPlayerManager
+)
+{
+ rAssert( m_pPlayerManager == NULL );
+ rAssert( pPlayerManager != NULL );
+
+ m_pPlayerManager = pPlayerManager;
+ m_pPlayerManager->AddRef( );
+}
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::GetPlayerManager
+//=============================================================================
+// Description: Get the player manager
+//
+//-----------------------------------------------------------------------------
+
+daSoundPlayerManager* daSoundAsyncFadeCallback::GetPlayerManager( void )
+{
+ return m_pPlayerManager;
+}
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::SetCallback
+//=============================================================================
+// Description: Set the fade callback
+//
+//-----------------------------------------------------------------------------
+
+void daSoundAsyncFadeCallback::SetCallback
+(
+ IDaSoundFadeState* pCallback,
+ void* pUserData
+)
+{
+ rAssert( m_pCallback == NULL );
+ m_pCallback = pCallback;
+ m_pUserData = pUserData;
+
+ if( m_pCallback != NULL )
+ {
+ m_pCallback->AddRef( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundAsyncFadeCallback::GetCallback
+//=============================================================================
+// Description: Get the fade callback
+//
+//-----------------------------------------------------------------------------
+
+void daSoundAsyncFadeCallback::GetCallback( IDaSoundFadeState** ppCallback, void** ppUserData )
+{
+ rAssert( ppCallback != NULL );
+ rAssert( ppUserData != NULL );
+
+ *ppCallback = m_pCallback;
+ *ppUserData = m_pUserData;
+}
+
+
+//=============================================================================
+// daSoundPlayerManager Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundPlayerManager::daSoundPlayerManager
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundClipStreamPlayer * gClipPlayerArray[ SOUND_NUM_CLIP_PLAYERS ];
+daSoundClipStreamPlayer * gStreamPlayerArray [ SOUND_NUM_STREAM_PLAYERS ];
+
+daSoundPlayerManager::daSoundPlayerManager( )
+ :
+ radRefCount( 0 )
+{
+ m_pIngameFadeIn = NULL;
+ m_pIngameFadeOut = NULL;
+ m_pMusicPlayer = NULL;
+ m_pAmbiencePlayer = NULL;
+ m_Initialized = false;
+
+ s_pInstance = this;
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::~daSoundPlayerManager
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundPlayerManager::~daSoundPlayerManager( )
+{
+ s_pInstance = NULL;
+ // Release our faders
+ if( m_pIngameFadeOut != NULL )
+ {
+ m_pIngameFadeOut->Release();
+ m_pIngameFadeOut = NULL;
+ }
+ if( m_pIngameFadeIn != NULL )
+ {
+ m_pIngameFadeIn->Release();
+ m_pIngameFadeIn = NULL;
+ }
+
+ // Release music players
+ if( m_pMusicPlayer != NULL )
+ {
+ m_pMusicPlayer->Release();
+ m_pMusicPlayer = NULL;
+ }
+ if( m_pAmbiencePlayer != NULL )
+ {
+ m_pAmbiencePlayer->Release();
+ m_pAmbiencePlayer = NULL;
+ }
+
+ for( unsigned int c = 0; c < SOUND_NUM_CLIP_PLAYERS; c ++ )
+ {
+ gClipPlayerArray[ c ]->Release( );
+ }
+
+ for( unsigned int s = 0; s < SOUND_NUM_STREAM_PLAYERS; s ++ )
+ {
+ gStreamPlayerArray[ s ]->Release( );
+ }
+}
+
+//=============================================================================
+// daSoundPlayerManager::UglyHackPostInitialize
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( IDaSoundTuner* pTuner )
+//
+// Return: void
+//
+//=============================================================================
+void daSoundPlayerManager::UglyHackPostInitialize( IDaSoundTuner* pTuner )
+{
+ // Ingame faders
+ m_pIngameFadeIn = new( GMA_PERSISTENT ) Fader( NULL, DUCK_FULL_FADE, *this, *pTuner );
+ rAssert( m_pIngameFadeIn != NULL );
+
+ m_pIngameFadeOut = new( GMA_PERSISTENT ) Fader( NULL, DUCK_FULL_FADE, *this, *pTuner );
+ rAssert( m_pIngameFadeOut != NULL );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::GetObjectSize
+//=============================================================================
+// Description: Get the size of the sound player object
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundPlayerManager::GetObjectSize( void )
+{
+ unsigned int thisSize = sizeof( *this );
+ return thisSize;
+}
+
+unsigned int daSoundPlayerManager::GetNumUsedClipPlayers()
+{
+ unsigned int playerCount = 0;
+
+ for( unsigned int c = 0; c < SOUND_NUM_CLIP_PLAYERS; c ++ )
+ {
+ if ( gClipPlayerArray[ c ]->IsCaptured( ) )
+ {
+ playerCount++;
+ }
+ }
+
+ return( playerCount );
+}
+
+unsigned int daSoundPlayerManager::GetNumUsedStreamPlayers()
+{
+ unsigned int playerCount = 0;
+
+ for( unsigned int s = 0; s < SOUND_NUM_STREAM_PLAYERS; s ++ )
+ {
+ if ( gStreamPlayerArray[ s ]->IsCaptured( ) )
+ {
+ playerCount++;
+ }
+ }
+
+ return playerCount;
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::Initialize
+//=============================================================================
+// Description: Initialize the player manager
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::Initialize( void )
+{
+ // The stream players are tuned from associated radscripts
+
+ IRadSoundClipPlayer* pClipPlayer = NULL;
+ IRadSoundStreamPlayer* pStreamPlayer = NULL;
+ IRadSoundStitchedDataSource* pStitchedDataSource = NULL;
+
+ // CLIP PLAYERS ///////////////////////////////////////////////////////////
+
+ for( unsigned int c = 0; c < SOUND_NUM_CLIP_PLAYERS; c++ )
+ {
+ gClipPlayerArray[ c ] = new (GetThisAllocator( ) ) daSoundClipStreamPlayer( );
+ gClipPlayerArray[ c ]->AddRef( );
+ gClipPlayerArray[ c ]->InitializeAsClipPlayer( );
+ }
+
+ // STREAM PLAYERS /////////////////////////////////////////////////////////
+
+ for( unsigned int s = 0; s < SOUND_NUM_STREAM_PLAYERS; s++ )
+ {
+
+ gStreamPlayerArray[ s ] = new ( GetThisAllocator() ) daSoundClipStreamPlayer;
+ gStreamPlayerArray[ s ]->AddRef( );
+ gStreamPlayerArray[ s ]->InitializeAsStreamPlayer( );
+ }
+
+ //
+ // Make a couple of fake players for controlling music and
+ // ambience trim
+ //
+
+ // Create a music and an ambience sound player
+ m_pMusicPlayer = new( GetThisAllocator() ) MusicSoundPlayer;
+ m_pMusicPlayer->AddRef( );
+ m_pMusicPlayer->Initialize( true );
+
+ m_pAmbiencePlayer = new( GetThisAllocator() ) MusicSoundPlayer;
+ m_pAmbiencePlayer->AddRef( );
+ m_pAmbiencePlayer->Initialize( false );
+
+ m_Initialized = true;
+
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::ServiceOncePerFrame
+//=============================================================================
+// Description: Service once per frame
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::ServiceOncePerFrame( void )
+{
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ pPlayer->ServiceOncePerFrame( );
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::CaptureFreePlayer
+//=============================================================================
+// Description: This function finds and captures a sound player
+// and connects the given resource to it.
+//
+// Parameters: ppPlayer - (out) the captured player or NULL if one can't be
+// found
+// pResource - a pointer to a sound resource
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::CaptureFreePlayer
+(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource,
+ bool positional
+)
+{
+ rAssert( ppPlayer != NULL );
+ rAssert( pResource != NULL );
+
+ // Find out where to look
+ unsigned int i = 0;
+ bool playerFound = false;
+ daSoundGroup soundGroup = pResource->GetSoundGroup( );
+ IDaSoundResource::Type resourceType = pResource->GetType( );
+
+ switch( pResource->GetType( ) )
+ {
+ case IDaSoundResource::CLIP:
+ {
+ // Look in the clip player list
+ playerFound = FindFreeClipPlayer( ppPlayer, pResource );
+ break;
+ }
+ case IDaSoundResource::STREAM:
+ {
+ // Look in the stream player list
+ playerFound = FindFreeStreamPlayer( ppPlayer, pResource );
+ break;
+ }
+ default:
+ {
+ rAssert( 0 );
+ break;
+ }
+ }
+ if( playerFound )
+ {
+ // Capture it
+ (*ppPlayer)->Capture( pResource, positional );
+ }
+ else
+ {
+ (*ppPlayer) = NULL;
+ }
+
+}
+
+bool daSoundPlayerManager::FindFreePlayer(
+ daSoundClipStreamPlayer** ppPlayerArray,
+ unsigned int numPlayers,
+ daSoundClipStreamPlayer ** ppPlayer )
+{
+ *ppPlayer = 0;
+
+ for( unsigned int c = 0; c < numPlayers; c ++ )
+ {
+ if ( false == ppPlayerArray[ c ]->IsCaptured( ) )
+ {
+ *ppPlayer = ppPlayerArray[ c ];
+ break;
+ }
+ }
+
+ return NULL != *ppPlayer;
+}
+
+
+//=============================================================================
+// Function: daSoundPlayerManager::FindFreeClipPlayer
+//=============================================================================
+// Description: Find a free clip player
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundPlayerManager::FindFreeClipPlayer(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource
+)
+{
+ return FindFreePlayer( gClipPlayerArray, SOUND_NUM_CLIP_PLAYERS, ppPlayer );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::FindFreeStreamPlayer
+//=============================================================================
+// Description: Find a free stream player
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundPlayerManager::FindFreeStreamPlayer(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource )
+{
+ return FindFreePlayer( gStreamPlayerArray, SOUND_NUM_STREAM_PLAYERS, ppPlayer );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::PausePlayers
+//=============================================================================
+// Description: Pause the sound players
+//
+// Parameters: stackFrame - the stack frame that a player is associated with.
+// If NULL, all players pause.
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::PausePlayers
+(
+)
+{
+ //
+ // Pause all players
+ //
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ pPlayer->Pause( );
+
+ // Move on
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::PausePlayersWithFade
+//=============================================================================
+// Description: Fade out the players and then pause
+//
+// Parameters: see PausePlayers
+// pCallback - the asynchronous callback to call when done
+// pUserData - the user data to pass into the callback
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::PausePlayersWithFade
+(
+ IDaSoundFadeState* pCallback,
+ void* pUserData
+)
+{
+ // Create the fade info
+ daSoundAsyncFadeCallback* pFadeInfo = new( GMA_TEMP ) daSoundAsyncFadeCallback( );
+ rAssert( pFadeInfo != NULL );
+ pFadeInfo->SetPlayerManager( this );
+ pFadeInfo->SetAction( OnFade_PausePlayers );
+ pFadeInfo->SetCallback( pCallback, pUserData );
+
+ // Start fading the sounds
+ rAssert( m_pIngameFadeOut != NULL );
+ Sound::daSoundRenderingManagerGet( )->GetTuner( )->FadeSounds
+ (
+ this,
+ pFadeInfo,
+ m_pIngameFadeOut,
+ false
+ );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::ContinuePlayers
+//=============================================================================
+// Description: Continue the sound players
+//
+// Parameters: stackFrame - the stack frame that a player is associated with.
+// If NULL, all players continue.
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::ContinuePlayers
+(
+)
+{
+ //
+ // Continue all players
+ //
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ if( pPlayer->IsPaused() )
+ {
+ pPlayer->Continue( );
+ }
+
+ // Move on
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::ContinuePlayersWithFade
+//=============================================================================
+// Description: Continue the players and then fade in.
+//
+// Parameters: see PausePlayers
+// pCallback - the asynchronous callback to call when done
+// pUserData - the user data to pass into the callback
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::ContinuePlayersWithFade
+(
+ IDaSoundFadeState* pCallback,
+ void* pUserData
+)
+{
+ // Create the fade info
+ daSoundAsyncFadeCallback* pFadeInfo =
+ new( GMA_TEMP ) daSoundAsyncFadeCallback( );
+ rAssert( pFadeInfo != NULL );
+ pFadeInfo->SetPlayerManager( this );
+ pFadeInfo->SetAction( OnFade_ContinuePlayers );
+ pFadeInfo->SetCallback( pCallback, pUserData );
+
+ // Continue the players
+ ContinuePlayers();
+
+ // Start fading the sounds
+ rAssert( m_pIngameFadeIn != NULL );
+ Sound::daSoundRenderingManagerGet( )->GetTuner( )->FadeSounds
+ (
+ this,
+ pFadeInfo,
+ m_pIngameFadeIn,
+ true
+ );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::CancelPlayers
+//=============================================================================
+// Description: Stop the sound players
+//
+// Parameters: stackFrame - the stack frame that a player is associated with.
+// If NULL, all players stop.
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::CancelPlayers
+(
+)
+{
+ //
+ // Stop all players
+ //
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ if( pPlayer->IsCaptured( ) )
+ {
+ // Stop the player
+ pPlayer->Stop( );
+ }
+
+ // Move on
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+
+ //
+ // Since this command may be called by the sound manager destructor,
+ // we must make sure that we service the sound system at least one
+ // more time so that we can actually stop all the sounds.
+ //
+ ::radSoundHalSystemGet( )->Service( );
+ ::radSoundHalSystemGet( )->ServiceOncePerFrame( );
+}
+
+//=============================================================================
+// daSoundPlayerManager::AreAllPlayersStopped
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: bool
+//
+//=============================================================================
+bool daSoundPlayerManager::AreAllPlayersStopped()
+{
+ unsigned int c;
+ daSoundClipStreamPlayer::State playerState;
+
+ for( c = 0; c < SOUND_NUM_CLIP_PLAYERS; c++ )
+ {
+ if( gClipPlayerArray[c] != NULL )
+ {
+ playerState = gClipPlayerArray[c]->GetState();
+
+ if( ( playerState == daSoundClipStreamPlayer::State_Cueing )
+ || ( playerState == daSoundClipStreamPlayer::State_CuedPlay )
+ || ( playerState == daSoundClipStreamPlayer::State_Playing ) )
+ {
+ if( !(gClipPlayerArray[c]->IsPaused()) )
+ {
+ return( false );
+ }
+ }
+ }
+ }
+
+ for( c = 0; c < SOUND_NUM_STREAM_PLAYERS; c ++ )
+ {
+ if( gStreamPlayerArray[c] != NULL )
+ {
+ playerState = gStreamPlayerArray[c]->GetState();
+
+ if( ( playerState == daSoundClipStreamPlayer::State_Cueing )
+ || ( playerState == daSoundClipStreamPlayer::State_CuedPlay )
+ || ( playerState == daSoundClipStreamPlayer::State_Playing )
+ || ( playerState == daSoundClipStreamPlayer::State_Stopping ) )
+ {
+ if( !(gStreamPlayerArray[c]->IsPaused()) )
+ {
+ return( false );
+ }
+ }
+ }
+ }
+
+ return( true );
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::PlayerVolumeChange
+//=============================================================================
+// Description: updates all of the players with the new volume value
+//
+//-----------------------------------------------------------------------------
+void daSoundPlayerManager::PlayerVolumeChange( daSoundGroup groupName, float trim )
+{
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ pPlayer->ChangeTrim(groupName,trim);
+
+ // Move on
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::PlayerFaderVolumeChange
+//=============================================================================
+// Description: updates all of the players with the new fader volume value
+//
+//-----------------------------------------------------------------------------
+void daSoundPlayerManager::PlayerFaderVolumeChange( daSoundGroup groupName, float trim )
+{
+ daSoundPlayerBase* pPlayer = daSoundPlayerBase::GetLinkedClassHead( );
+ while( pPlayer != NULL )
+ {
+ pPlayer->ChangeFaderTrim(groupName,trim);
+
+ // Move on
+ pPlayer = pPlayer->GetLinkedClassNext( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundPlayerManager::OnFadeDone
+//=============================================================================
+// Description: React when the fade is done
+//
+// Parameters: pUserData - a void* to a daSoundAsyncFadeCallback
+//
+//-----------------------------------------------------------------------------
+
+void daSoundPlayerManager::OnFadeDone( void* pUserData )
+{
+ daSoundAsyncFadeCallback* pFadeInfo =
+ reinterpret_cast< daSoundAsyncFadeCallback* >( pUserData );
+ rAssert( pFadeInfo != NULL );
+
+ // Perform the appropriate action
+ switch( pFadeInfo->GetAction( ) )
+ {
+ case OnFade_PausePlayers:
+ {
+ PausePlayers();
+ break;
+ }
+ case OnFade_ContinuePlayers:
+ {
+ break;
+ }
+ case OnFade_CancelPlayers:
+ {
+ CancelPlayers();
+ Sound::daSoundRenderingManagerGet( )->
+ GetTuner( )->
+ SetMasterVolume( 1.0f );
+ break;
+ }
+ default:
+ {
+ rAssert( 0 );
+ break;
+ }
+ }
+
+ // Call the callback
+ IDaSoundFadeState* pCallback = NULL;
+ void* pData = NULL;
+ pFadeInfo->GetCallback( &pCallback, &pData );
+
+ if( pCallback != NULL )
+ {
+ pCallback->OnFadeDone( pData );
+ }
+
+ // Delete the fade info
+ delete pFadeInfo;
+}
+
+void TrimFileName( char * pS, int len )
+{
+ int sl = strlen( pS );
+
+ char * pStart;
+ char * pEnd;
+
+ pEnd = pS + sl - 4;
+ pStart = pEnd - len;
+
+ if ( pStart < pS )
+ {
+ pStart = pS;
+ }
+
+ if ( pEnd < pStart )
+ {
+ pEnd = pS + 1;
+ }
+
+ int chars = pEnd - pStart;
+
+ ::memcpy( pS, pStart, chars);
+ pS[ chars ] = 0;
+}
+
+void RenderPlayer( daSoundClipStreamPlayer * pPlayer, int row, int col )
+{
+ char buf[ 256 ];
+
+ if ( false == pPlayer->IsCaptured( ) )
+ {
+ sprintf( buf, "free" );
+ }
+ else
+ {
+ float fDistToListener;
+ char sDistToListener[ 64 ];
+ char sFileName[ 64 ];
+ char sMaxDistance[ 64 ];
+
+ pPlayer->GetFileName( sFileName, 64 );
+
+ TrimFileName( sFileName, 8 );
+
+ IRadSoundHalPositionalGroup * pPosGroup = pPlayer->GetPositionalGroup( );
+
+ if ( pPosGroup )
+ {
+ radSoundVector listenerPos;
+ radSoundVector position;
+
+ float minDist;
+ float maxDist;
+
+ radSoundHalListenerGet( )->GetPosition( & listenerPos );
+
+ pPosGroup->GetPosition( & position );
+ pPosGroup->GetMinMaxDistance( & minDist, & maxDist );
+
+ fDistToListener = listenerPos.GetDistanceBetween( position );
+
+ sprintf( sDistToListener, "%.2f", fDistToListener );
+ sprintf( sMaxDistance, "%.2f", maxDist );
+ }
+ else
+ {
+ strcpy( sDistToListener, "--" );
+ strcpy( sMaxDistance, "--" );
+ }
+
+
+ // gClipPlayerArray[ c ]->
+ sprintf( buf, "[%s](%s)[%d][%s][%s]",
+ sFileName,
+ pPlayer->IsPaused( ) ? "-" : "*",
+ pPlayer->GetState( ),
+ sDistToListener,
+ sMaxDistance );
+ }
+
+ p3d::pddi->DrawString( buf, 40 + col * 320
+ , 36 + row * 16, pddiColour( 255, 255, 0 ) );
+
+}
+
+void daSoundPlayerManager::Render( void )
+{
+ if( m_Initialized )
+ {
+ int col = 0;
+ int row = 0;
+
+ unsigned int freeMem;
+ unsigned int numObjects;
+ unsigned int largestBlock;
+ unsigned int size;
+
+ radSoundHalSystemGet( )->GetRootMemoryRegion( )->GetStats(
+ & freeMem,
+ & numObjects,
+ & largestBlock,
+ true );
+
+ size = radSoundHalSystemGet( )->GetRootMemoryRegion( )->GetSize( );
+
+ char memStr[ 256 ];
+ sprintf(
+ memStr,
+ "Usd %dK Fre %dK Lrg %dK Objs: %d",
+ ( size - freeMem ) / 1024,
+ freeMem / 1024,
+ largestBlock / 1024,
+ numObjects );
+
+ p3d::pddi->DrawString( memStr, 40 + col * 320, 36 + row * 16, pddiColour( 255, 255, 0 ) );
+
+ row++;
+
+ unsigned int usedBTreeNodes = radObjectBTree::GetNumAllocatedNodes( );
+ unsigned int nodeSize = sizeof( radObjectBTreeNode );
+
+ sprintf( memStr,
+ "BTree Nodes: [0x%x], size: [0x%x]",
+ usedBTreeNodes,
+ nodeSize );
+
+ p3d::pddi->DrawString( memStr, 40 + col * 320, 36 + row * 16, pddiColour( 255, 255, 0 ) );
+
+ row++;
+
+ char listenerStr[ 128 ];
+ radSoundVector lp;
+ radSoundVector lv;
+ radSoundHalListenerGet( )->GetPosition( & lp );
+ radSoundHalListenerGet( )->GetVelocity( & lv );
+
+ sprintf( listenerStr, "Pos:[%.2f][%.2f][%.2f] Vel:[%.2f][%.2f][%.2f]\n",
+ lp.m_x, lp.m_y, lp.m_z, lv.m_x, lv.m_y, lv.m_z );
+
+ p3d::pddi->DrawString( listenerStr, 40 + col * 320, 36 + row * 16, pddiColour( 255, 255, 0 ) );
+
+ row++;
+
+ for( unsigned int c = 0; c < SOUND_NUM_CLIP_PLAYERS / 2; c ++ )
+ {
+ RenderPlayer( gClipPlayerArray[ c ], row, col );
+
+ col++;
+
+ if ( col >= 2 )
+ {
+ row++;
+ col = 0;
+ }
+ }
+
+ row++;
+
+ for( unsigned int c = 0; c < SOUND_NUM_STREAM_PLAYERS; c ++ )
+ {
+ RenderPlayer( gStreamPlayerArray[ c ], row, col );
+
+ col++;
+
+ if ( col >= 2 )
+ {
+ row++;
+ col = 0;
+ }
+ }
+ }
+}
+
+} // Sound Namespace
+
diff --git a/game/code/sound/soundrenderer/playermanager.h b/game/code/sound/soundrenderer/playermanager.h
new file mode 100644
index 0000000..09fa4eb
--- /dev/null
+++ b/game/code/sound/soundrenderer/playermanager.h
@@ -0,0 +1,185 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: playermanager.h
+//
+// Subsystem: Dark Angel - Player Manager System
+//
+// Description: Description of the DA sound player manager
+//
+// Revisions:
+// + Created October 16, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _PLAYERMANAGER_HPP
+#define _PLAYERMANAGER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/musicsoundplayer.h>
+#include <radsound.hpp>
+
+//=============================================================================
+// Global namespace forward declarations
+//=============================================================================
+
+struct IRadObjectList;
+
+class Fader;
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundPlayerGroupWiring;
+class daSoundPlayerManager;
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+class daSoundClipStreamPlayer;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+//
+// This class is created for our asynchronous fades
+//
+
+class daSoundAsyncFadeCallback : public radObject
+{
+public:
+ IMPLEMENT_BASEOBJECT( "daSoundAsyncFadeCallback" )
+
+ daSoundAsyncFadeCallback( );
+ virtual ~daSoundAsyncFadeCallback( );
+
+ void SetAction( int action ) { m_Action = action; }
+ int GetAction( void ) { return m_Action; }
+
+ void SetPlayerManager( daSoundPlayerManager* pPlayerManager );
+ daSoundPlayerManager* GetPlayerManager( void );
+
+ void SetCallback( IDaSoundFadeState* pCallback, void* pUserData );
+ void GetCallback( IDaSoundFadeState** ppCallback, void** ppUserData );
+
+private:
+
+ int m_Action;
+ daSoundPlayerManager* m_pPlayerManager;
+ IDaSoundFadeState* m_pCallback;
+ void* m_pUserData;
+};
+
+//
+// The player manager is responsible for creating and managing daSoundClipStreamPlayer
+// objects. These objects allow the user to play sound resources.
+//
+class daSoundPlayerManager : public IDaSoundFadeState,
+ public radRefCount
+{
+public:
+ IMPLEMENT_REFCOUNTED_NOSIZE( "daSoundPlayerManager" );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundPlayerManager( );
+ virtual ~daSoundPlayerManager( );
+
+ inline daSoundPlayerManager * GetInstance( void );
+
+ bool FindFreeClipPlayer(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource );
+ bool FindFreeStreamPlayer(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource );
+
+ unsigned int GetNumUsedClipPlayers();
+ unsigned int GetNumUsedStreamPlayers();
+ void Initialize( void );
+ void UglyHackPostInitialize( IDaSoundTuner* pTuner );
+ void ServiceOncePerFrame( void );
+ unsigned int GetObjectSize( void );
+ void CaptureFreePlayer(
+ daSoundClipStreamPlayer** ppPlayer,
+ IDaSoundResource* pResource,
+ bool positional );
+
+ void PausePlayers ( );
+ void PausePlayersWithFade(
+ IDaSoundFadeState* pCallback,
+ void* pUserData );
+
+ void ContinuePlayers ( );
+
+ void ContinuePlayersWithFade(
+ IDaSoundFadeState* pCallback,
+ void* pUserData );
+
+ void CancelPlayers ( );
+
+ bool AreAllPlayersStopped();
+
+ //
+ // Volume controls
+ //
+ void PlayerVolumeChange( daSoundGroup soundGroup, daTrimValue trim );
+ void PlayerFaderVolumeChange( daSoundGroup soundGroup, daTrimValue trim );
+
+ void Render( void );
+
+protected:
+ // When a fade is done go here and call our callback
+ enum FadeTypesEnum {
+ OnFade_PausePlayers,
+ OnFade_ContinuePlayers,
+ OnFade_CancelPlayers
+ };
+ void OnFadeDone( void* pUserData );
+
+private:
+
+ bool FindFreePlayer( daSoundClipStreamPlayer** ppPlayerArray, unsigned int numPlayers, daSoundClipStreamPlayer ** ppPlayer );
+
+ MusicSoundPlayer* m_pMusicPlayer;
+ MusicSoundPlayer* m_pAmbiencePlayer;
+
+ //
+ // The ingame faders
+ //
+ Fader* m_pIngameFadeIn;
+ Fader* m_pIngameFadeOut;
+
+ bool m_Initialized;
+
+ static daSoundPlayerManager * s_pInstance;
+
+};
+
+inline daSoundPlayerManager * daSoundPlayerManager::GetInstance( void )
+{
+ return s_pInstance;
+}
+
+} // Sound Namespace
+#endif //_PLAYERMANAGER_HPP
+
+
diff --git a/game/code/sound/soundrenderer/soundallocatedresource.cpp b/game/code/sound/soundrenderer/soundallocatedresource.cpp
new file mode 100644
index 0000000..e6678ca
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundallocatedresource.cpp
@@ -0,0 +1,429 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundallocatedresource.cpp
+//
+// Subsystem: Dark Angel - Sound Resource Management System
+//
+// Description: Implementation of an allocated sound resource
+//
+// Revisions:
+// + Created October 18, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radsound.hpp>
+#include <raddebugwatch.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundnucleus.hpp>
+
+#include <memory/srrmemory.h>
+
+//=============================================================================
+// Static Variables (outside namespace)
+//=============================================================================
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Static Variables (inside namespace)
+//=============================================================================
+
+//=============================================================================
+// Constants
+//=============================================================================
+
+#ifndef RAD_RELEASE
+
+#ifdef RAD_DEBUG
+static bool s_displayMemoryInfo = true;
+#else
+static bool s_displayMemoryInfo = false;
+#endif
+
+static bool s_isInitialized = false;
+static int s_memoryRemaining = 0;
+
+#endif // RAD_RELEASE
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundAllocatedResource Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundFileInstance::daSoundFileInstance
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance::daSoundFileInstance(
+ IDaSoundResource* pResource,
+ unsigned int fileIndex )
+{
+ rAssert( pResource != NULL );
+
+ m_RefCount = 0;
+ m_State = UnLoaded;
+ m_pSoundClip = NULL;
+
+ m_State = UnLoaded;
+
+ m_FileIndex = fileIndex;
+
+ m_pResource = pResource;
+ m_pResource->AddRef( );
+
+ // Set the type of resource
+
+ IDaSoundResource::Type type = pResource->GetType( );
+
+ if( type == IDaSoundResource::CLIP )
+ {
+ m_Type = IDaSoundResource::CLIP;
+ }
+ else
+ {
+ rAssert( type == IDaSoundResource::STREAM );
+ m_Type = IDaSoundResource::STREAM;
+ }
+
+#ifndef RAD_RELEASE
+ if( !s_isInitialized )
+ {
+ radDbgWatchAddBoolean( &s_displayMemoryInfo, "Show Loading Spew", "Sound Info", 0, 0 );
+
+ s_isInitialized = true;
+ }
+#endif
+}
+
+//=============================================================================
+// Function: daSoundFileInstance::~daSoundFileInstance
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance::~daSoundFileInstance( )
+{
+ m_pResource->Release( );
+
+ rAssert( m_State == UnLoaded );
+ rAssert( NULL == m_pSoundClip );
+
+}
+
+//=============================================================================
+// Function: daSoundFileInstance::CreateFileDataSource
+//=============================================================================
+// Description: Get the sound stream.
+//
+// Returns: Returns the sound stream if it is allocated for this resource,
+// or NULL if it is not.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundFileInstance::CreateFileDataSource(
+ IRadSoundRsdFileDataSource** ppFds )
+{
+ rAssert( GetType( ) == IDaSoundResource::STREAM );
+ rAssert( Loaded == m_State );
+
+ char fileName[ 256 ];
+ m_pResource->GetFileKeyAt( m_FileIndex, fileName, 256 );
+
+ *ppFds = radSoundRsdFileDataSourceCreate( GMA_AUDIO_PERSISTENT );
+ (*ppFds)->AddRef( );
+
+ (*ppFds)->InitializeFromFileName(
+ fileName,
+ true,
+ 0,
+ IRadSoundHalAudioFormat::Milliseconds,
+ SoundNucleusGetStreamFileAudioFormat( ) );
+
+}
+
+//=============================================================================
+// Function: daSoundFileInstance::OnDynaLoadObjectCreate
+//=============================================================================
+// Description: Called when this object is being created (by dynamic loading)
+//
+//-----------------------------------------------------------------------------
+
+void daSoundFileInstance::Load( IRadSoundHalMemoryRegion* pRegion )
+{
+ rAssert( m_State == UnLoaded );
+
+ rAssert( m_Type == IDaSoundResource::UNKNOWN || m_pResource != NULL );
+
+ // Create each type of object
+ if( m_Type == IDaSoundResource::CLIP )
+ {
+ char fileName[ 256 ];
+ m_pResource->GetFileKeyAt( m_FileIndex, fileName, 256 );
+
+ SoundNucleusLoadClip( fileName, m_pResource->GetLooping( ) );
+ }
+
+ m_State = Loading;
+}
+
+//=============================================================================
+// Function: daSoundFileInstance::OnDynaLoadObjectCreate
+//=============================================================================
+// Description: Is this object ready and stable?
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundFileInstance::UpdateLoading( void )
+{
+ rAssert( Loading == m_State );
+
+ if( m_Type == IDaSoundResource::CLIP )
+ {
+ if ( SoundNucleusIsClipLoaded( ) )
+ {
+ SoundNucleusFinishClipLoad( & m_pSoundClip );
+ m_State = Loaded;
+ }
+ }
+ else
+ {
+ m_State = Loaded;
+ }
+
+ return Loaded == m_State;
+}
+
+//=============================================================================
+// Function: daSoundFileInstance::OnDynaLoadObjectDestroy
+//=============================================================================
+// Description: Destroy this dynamically loading object
+//
+//-----------------------------------------------------------------------------
+
+void daSoundFileInstance::UnLoad( void )
+{
+ rAssert( m_State == Loaded || Loading == m_State );
+
+ if ( m_Type == IDaSoundResource::CLIP )
+ {
+ if ( Loading == m_State )
+ {
+ SoundNucleusCancelClipLoad( );
+ }
+ else if ( Loaded == m_State )
+ {
+ rAssert( m_pSoundClip != NULL );
+ m_pSoundClip->Release( );
+ m_pSoundClip = NULL;
+ }
+ }
+
+ m_State = UnLoaded;
+}
+
+//=============================================================================
+// daSoundAllocatedResource Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundAllocatedResource::daSoundAllocatedResource
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundAllocatedResource::daSoundAllocatedResource( )
+ :
+ m_RefCount( 0 )
+{
+ unsigned int i = 0;
+
+ for( i = 0; i < DASound_MaxNumSoundResourceFiles; i++ )
+ {
+ m_pFileInstance[ i ] = NULL;
+ m_pDynaLoadRegion[ i ] = NULL;
+ }
+}
+
+//=============================================================================
+// Function: daSoundAllocatedResource::~daSoundAllocatedResource
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundAllocatedResource::~daSoundAllocatedResource( void )
+{
+ if( GetResource( ) != NULL )
+ {
+ unsigned int i = 0;
+ unsigned int j = 0;
+ for( i = 0; i < DASound_MaxNumSoundResourceFiles; i++ )
+ {
+ // Release the dynamic loading region
+ if( m_pDynaLoadRegion[ i ] != NULL )
+ {
+ for( j = 0; j < m_pDynaLoadRegion[ i ]->GetNumSlots( ); j++ )
+ {
+ m_pDynaLoadRegion[ i ]->SwapInObject( j, NULL );
+ }
+ m_pDynaLoadRegion[ i ]->Release( );
+ m_pDynaLoadRegion[ i ] = NULL;
+ }
+
+ // Release file instance
+ if( m_pFileInstance[ i ] != NULL )
+ {
+ m_pFileInstance[ i ]->Release( );
+ m_pFileInstance[ i ] = NULL;
+ }
+ }
+
+ // Release the resource
+ m_pResource->Release( );
+ }
+
+}
+
+//=============================================================================
+// Function: daSoundAllocatedResource::Initialize
+//=============================================================================
+// Description: Intialize the allocated resource by giving it a normal
+// resource.
+//
+// Parameters: pResource - the resource for this instance to associate with
+// index - the index of the resource file to use
+//
+//-----------------------------------------------------------------------------
+
+void daSoundAllocatedResource::Initialize
+(
+ IDaSoundResource* pResource
+)
+{
+ rAssert( pResource != NULL );
+
+ m_pResource = pResource;
+ m_pResource->AddRef( );
+
+ // Look in the resource manager's tree of allocated resources
+ // If the file is already loaded, just addref the object
+ Sound::daSoundResourceManager* pResManager = Sound::daSoundResourceManager::GetInstance( );
+
+ // Load and initialize the files;
+
+ unsigned int numFiles = m_pResource->GetNumFiles( );
+
+ for( unsigned int i = 0; i < numFiles; i++ )
+ {
+
+#ifdef RAD_XBOX
+ daSoundFileInstance* pFileInstance = new( GMA_XBOX_SOUND_MEMORY ) daSoundFileInstance( m_pResource, i );
+#else
+ daSoundFileInstance* pFileInstance = new( GMA_AUDIO_PERSISTENT ) daSoundFileInstance( m_pResource, i );
+#endif
+ pFileInstance->AddRef( );
+
+ //
+ // Generate a dyna load region for this object
+ //
+
+ unsigned int size = 0;
+ daSoundDynaLoadRegion* pRegion = NULL;
+ m_pDynaLoadRegion[ i ] = Sound::daSoundRenderingManagerGet( )->
+ GetDynaLoadManager( )->
+ CreateRegion
+ (
+ ::radSoundHalSystemGet( )->GetRootMemoryRegion( ),
+ size,
+ 1
+ );
+ rAssert( m_pDynaLoadRegion[ i ] != NULL );
+ m_pDynaLoadRegion[ i ]->AddRef( );
+ m_pDynaLoadRegion[ i ]->SwapInObject( 0, pFileInstance );
+
+ // Set the file instance internally
+ // (The AddRef is just copied)
+
+ m_pFileInstance[ i ] = pFileInstance;
+ }
+}
+
+//=============================================================================
+// Function: daSoundAllocatedResource::ChooseNextInstance
+//=============================================================================
+// Description: Choose the next instance to play in this allocated resource
+//
+// Notes:
+// The resource automatically keeps track of what files
+// are being used. It will try not to let anything repeat
+// based on the following rules:
+// (1) IF ( numfiles <= DASound_NumLastPlayedFilesToRemember ) THEN
+// Choose a file randomly
+// (2) IF ( numfiles == DASound_NumLastPlayedFilesToRemember + 1 ) THEN
+// Choose randomly out of all files except the last one
+// used.
+// (2) ELSE
+// Don't choose one of the DASound_NumLastPlayedFilesToRemember
+// last files, but choose randomly out of the rest
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundAllocatedResource::ChooseNextInstance( void )
+{
+ rAssert( GetResource( ) != NULL );
+
+ // Get the number of resource files
+ unsigned int numResourceFiles = GetResource( )->GetNumFiles( );
+ rAssert( numResourceFiles > 0 );
+
+ // Return the chosen file
+ return( rand( ) % numResourceFiles );
+}
+
+//=============================================================================
+// Function: daSoundAllocatedResource::GetFileInstance
+//=============================================================================
+// Description: Get the file instance at the given index
+//
+// Returns: Returns a pointer to the file instance
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance* daSoundAllocatedResource::GetFileInstance
+(
+ unsigned int index
+)
+{
+ rAssert( GetResource( ) != NULL );
+ rAssert( index < GetResource( )->GetNumFiles( ) );
+
+ return m_pFileInstance[ index ];
+}
+
+} // Sound Namespace
+
diff --git a/game/code/sound/soundrenderer/soundallocatedresource.h b/game/code/sound/soundrenderer/soundallocatedresource.h
new file mode 100644
index 0000000..599e4ca
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundallocatedresource.h
@@ -0,0 +1,249 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundallocatedresource.hpp
+//
+// Subsystem: Dark Angel - Sound Resource Management System
+//
+// Description: Description of an allocated sound resource
+//
+// Revisions:
+// + Created October 19, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _SOUNDALLOCATEDRESOURCE_HPP
+#define _SOUNDALLOCATEDRESOURCE_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+#include <radsound_hal.hpp>
+#include <radsound.hpp>
+
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/sounddynaload.h>
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundAllocatedResource;
+
+class daSoundFileInstance
+{
+public:
+
+ inline void * operator new ( size_t size, radMemoryAllocator allocator );
+ inline void operator delete( void * pMem );
+
+ inline void AddRef( void );
+ inline void Release( void );
+
+ // Constructor and destructor
+ daSoundFileInstance( IDaSoundResource* pResource, unsigned int fileIndex );
+ ~daSoundFileInstance( );
+
+ void Load( IRadSoundHalMemoryRegion* pRegion );
+ bool UpdateLoading( void );
+ void UnLoad( void );
+
+ inline IDaSoundResource::Type GetType( void );
+
+ inline IRadSoundClip* GetSoundClip( void );
+ void CreateFileDataSource( IRadSoundRsdFileDataSource** );
+
+ // Internal state
+ enum State { Loading, Loaded, UnLoaded };
+
+ inline State GetState( void );
+
+ inline void GetFileName( char * pFileName, unsigned int maxChars );
+
+protected:
+
+private:
+
+ unsigned int m_FileIndex;
+ unsigned int m_RefCount;
+
+ // Store the resource
+ IDaSoundResource * m_pResource;
+
+ // Store the actual allocated resource based on the attached
+ IDaSoundResource::Type m_Type;
+
+ IRadSoundClip* m_pSoundClip;
+
+ State m_State;
+};
+
+//
+// The resource library stores a giant array of resources, and provides helpfull
+// ways to get at the information. Notices that there is no
+// way to remove a resource file from this library.
+//
+class daSoundAllocatedResource : public IRefCount
+{
+
+public:
+
+ inline void AddRef( void );
+ inline void Release( void );
+
+ inline void * operator new ( size_t size, radMemoryAllocator allocator );
+ inline void operator delete( void * pMem );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundAllocatedResource( );
+ ~daSoundAllocatedResource( );
+
+ //
+ // IDaSoundAllocatedResource
+ //
+ void Initialize( IDaSoundResource* pResource );
+ inline IDaSoundResource* GetResource( void );
+ unsigned int ChooseNextInstance( void );
+
+ daSoundFileInstance* GetFileInstance( unsigned int index );
+
+protected:
+ void ApplyResourceSettings_Internal( unsigned int index );
+
+private:
+ // Store the attached resource
+ IDaSoundResource* m_pResource;
+
+ unsigned int m_RefCount;
+
+ // Store the file instances
+ daSoundFileInstance* m_pFileInstance[ DASound_MaxNumSoundResourceFiles ];
+
+ // Dynamic loading region
+ daSoundDynaLoadRegion* m_pDynaLoadRegion[ DASound_MaxNumSoundResourceFiles ];
+};
+
+//=============================================================================
+// Function: daSoundFileInstance::GetType
+//=============================================================================
+// Description: Get the type of the allocated res
+//
+//-----------------------------------------------------------------------------
+
+inline IDaSoundResource::Type daSoundFileInstance::GetType( void )
+{
+ return m_Type;
+}
+
+
+//=============================================================================
+// Function: daSoundFileInstance::GetSoundClip
+//=============================================================================
+// Description: Get the sound clip.
+//
+// Returns: Returns the sound clip if it is allocated for this resource,
+// or NULL if it is not.
+//
+//-----------------------------------------------------------------------------
+
+inline IRadSoundClip* daSoundFileInstance::GetSoundClip( void )
+{
+ rAssert( IDaSoundResource::CLIP == GetType( ) );
+ rAssert( Loaded == m_State );
+
+ return m_pSoundClip;
+}
+
+
+//=============================================================================
+// Function: daSoundAllocatedResource::GetResource
+//=============================================================================
+// Description: Get the resource data from the allocated resource
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundResource* daSoundAllocatedResource::GetResource( void )
+{
+ return m_pResource;
+}
+
+inline daSoundFileInstance::State daSoundFileInstance::GetState( void )
+{
+ return m_State;
+}
+
+inline void daSoundFileInstance::GetFileName( char * pBuffer, unsigned int max )
+{
+ m_pResource->GetFileKeyAt( m_FileIndex, pBuffer, max );
+}
+
+
+inline void daSoundFileInstance::AddRef( void )
+{
+ m_RefCount++;
+}
+
+inline void daSoundFileInstance::Release( void )
+{
+ rAssert( m_RefCount > 0 );
+
+ m_RefCount--;
+
+ if( 0 == m_RefCount )
+ {
+ delete this;
+ }
+}
+
+
+inline void * daSoundFileInstance::operator new ( size_t size, radMemoryAllocator allocator )
+{
+ return radMemoryAlloc( allocator, size );
+}
+
+inline void daSoundFileInstance::operator delete( void * pMem )
+{
+ return radMemoryFree( pMem );
+}
+
+inline void daSoundAllocatedResource::AddRef( void )
+{
+ m_RefCount++;
+}
+
+inline void daSoundAllocatedResource::Release( void )
+{
+ rAssert( m_RefCount > 0 );
+
+ m_RefCount--;
+
+ if( 0 == m_RefCount )
+ {
+ delete this;
+ }
+}
+
+inline void * daSoundAllocatedResource::operator new ( size_t size, radMemoryAllocator allocator )
+{
+ return radMemoryAlloc( allocator, size );
+}
+
+inline void daSoundAllocatedResource::operator delete( void * pMem )
+{
+ return radMemoryFree( pMem );
+}
+
+} // Sound Namespace
+#endif //_SOUNDALLOCATEDRESOURCE_HPP
+
diff --git a/game/code/sound/soundrenderer/soundconstants.h b/game/code/sound/soundrenderer/soundconstants.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundconstants.h
diff --git a/game/code/sound/soundrenderer/sounddynaload.cpp b/game/code/sound/soundrenderer/sounddynaload.cpp
new file mode 100644
index 0000000..8a5f7b4
--- /dev/null
+++ b/game/code/sound/soundrenderer/sounddynaload.cpp
@@ -0,0 +1,954 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddynaload.cpp
+//
+// Subsystem: Dark Angel - Dynamic Loading System
+//
+// Description: Implementation of the DA Dynamic Sound Loading System
+//
+// Revisions:
+// + Created: Novemeber 22, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radkey.hpp>
+#include <radsound.hpp>
+
+#include <sound/soundrenderer/sounddynaload.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+
+//=============================================================================
+// Static Variables (outside namespace)
+//=============================================================================
+
+Sound::daSoundDynaLoadRegion* radLinkedClass< Sound::daSoundDynaLoadRegion >::s_pLinkedClassHead = NULL;
+Sound::daSoundDynaLoadRegion* radLinkedClass< Sound::daSoundDynaLoadRegion >::s_pLinkedClassTail = NULL;
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Debug Information
+//=============================================================================
+
+//
+// Use this if you want to debug the sound player
+//
+#ifndef FINAL
+#ifndef NDEBUG
+#define DASOUNDDYNALOAD_DEBUG
+#ifdef DASOUNDDYNALOAD_DEBUG
+
+// Show the creation and destruction of dynamic loading regions
+static bool sg_ShowDynaLoadRegionCreation = false;
+
+#endif //DASOUNDDYNALOAD_DEBUG
+#endif //NDEBUG
+#endif //FINAL
+
+//=============================================================================
+// Static Variables
+//=============================================================================
+
+daSoundDynaLoadManager* daSoundDynaLoadManager::s_pSingleton = NULL;
+daSoundDynaLoadRegion* daSoundDynaLoadRegion::s_pActiveRegion = NULL;
+unsigned int daSoundDynaLoadRegion::s_ActiveSlot = 0;
+unsigned int daSoundDynaLoadRegion::s_GlobalPendingSwapCount = 0;
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundFileInstance;
+class daSoundDynaLoadRegion;
+
+//=============================================================================
+// Class Implementation
+//=============================================================================
+
+//=============================================================================
+// daSoundDynaLoadRegion Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::daSoundDynaLoadRegion
+//=============================================================================
+// Description: Constructor.
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadRegion::daSoundDynaLoadRegion( )
+:
+radRefCount( 0 ),
+m_IsInitialized( false ),
+m_NumSlots( 0 ),
+m_SlotSize( 0 ),
+m_ppSlot( NULL ),
+m_ppSlotObjects( NULL ),
+m_ppPendingSwapObjects( NULL ),
+m_PendingSwapCount( 0 )
+{
+ //
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::~daSoundDynaLoadRegion
+//=============================================================================
+// Description: Destructor.
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadRegion::~daSoundDynaLoadRegion( )
+{
+ // Destroy everything
+ Destroy( );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::~daSoundDynaLoadRegion
+//=============================================================================
+// Description: Create the region. If the size of slots is zero, do
+// not preallocate the region memory.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::Create
+(
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots,
+ unsigned int numslots
+)
+{
+ rAssert( pMemRegion != NULL );
+ rAssert( !m_IsInitialized );
+ rAssert( !ArePendingSwapsRegistered( ) );
+
+ // Set the region information
+ m_SlotSize = sizeofslots;
+ m_NumSlots = numslots;
+
+ // Create the slots
+ m_ppSlot = reinterpret_cast< IRadSoundHalMemoryRegion** >
+ (
+ ::radMemoryAlloc
+ (
+ GetThisAllocator( ),
+ sizeof( IRadSoundHalMemoryRegion* ) * numslots
+ )
+ );
+ rAssert( m_ppSlot );
+
+ unsigned int i = 0;
+ for( i = 0; i < numslots; i++ )
+ {
+ // If the slot size is zero, just use the main memory
+ if( SharedMemoryRegions( ) )
+ {
+ m_ppSlot[ i ] = pMemRegion;
+ m_ppSlot[ i ]->AddRef( );
+ }
+ else
+ {
+ //
+ // ESAN TODO: Investigate the magic number 32 below...
+ //
+ m_ppSlot[ i ] = pMemRegion->CreateChildRegion( m_SlotSize, 32, "Sound Memory Region object" );
+ if( m_ppSlot[ i ] == NULL )
+ {
+ // If this occurs, there in the check for free space. This may
+ // occur if the slot size is not aligned in the same way as
+ // sound memory.
+ rDebugString( "Out of sound memory allocating region\n" );
+ rAssert( m_ppSlot[ i ] != NULL );
+ }
+ else
+ {
+ m_ppSlot[ i ]->AddRef( );
+ }
+ }
+ rAssert( m_ppSlot[ i ] != NULL );
+ rAssert( m_ppSlot[ i ]->GetSize( ) >= m_SlotSize );
+ }
+
+ // Create the slot objects and pending slot objects
+ m_ppSlotObjects = reinterpret_cast< daSoundFileInstance** >
+ (
+ ::radMemoryAlloc
+ (
+ GetThisAllocator( ),
+ sizeof( daSoundFileInstance* ) * numslots
+ )
+ );
+ m_ppPendingSwapObjects = reinterpret_cast< daSoundFileInstance** >
+ (
+ ::radMemoryAlloc
+ (
+ GetThisAllocator( ),
+ sizeof( daSoundFileInstance* ) * numslots
+ )
+ );
+ for( i = 0; i < numslots; i++ )
+ {
+ m_ppSlotObjects[ i ] = NULL;
+ m_ppPendingSwapObjects[ i ] = NULL;
+ }
+
+ m_IsInitialized = true;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::Destroy
+//=============================================================================
+// Description: Destroy the region.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::Destroy( void )
+{
+ if( m_IsInitialized )
+ {
+ //
+ // Swap out all the objects
+ //
+ unsigned int i = 0;
+ for( i = 0; i < m_NumSlots; i++ )
+ {
+ SwapInObject( i, NULL );
+ }
+
+ // Destroy the pending swap objects
+ if( m_ppPendingSwapObjects != NULL )
+ {
+ ::radMemoryFree( GetThisAllocator( ), m_ppPendingSwapObjects );
+ m_ppPendingSwapObjects = NULL;
+ }
+
+ // Destroy the memory objects
+ if( m_ppSlotObjects != NULL )
+ {
+ ::radMemoryFree( GetThisAllocator( ), m_ppSlotObjects );
+ m_ppSlotObjects = NULL;
+ }
+
+ // Destroy the memory regions
+ if( m_ppSlot != NULL )
+ {
+ for( i = 0; i < m_NumSlots; i++ )
+ {
+ rAssert( m_ppSlot[ i ] != NULL );
+ m_ppSlot[ i ]->Release( );
+ m_ppSlot[ i ] = NULL;
+ }
+ ::radMemoryFree( GetThisAllocator( ), m_ppSlot );
+ m_ppSlot = NULL;
+ }
+
+ // Make sure we are not the active swap
+ ClearActiveSwap( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the sound system once per frame.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::ServiceOncePerFrame( void )
+{
+ // Service any active swaps
+ if( s_pActiveRegion == this )
+ {
+ if( GetSlotState( s_ActiveSlot ) != Initializing )
+ {
+ ClearActiveSwap( );
+ }
+ }
+ else
+ {
+ // Make sure that any pending swaps take place
+ if( ArePendingSwapsRegistered( ) )
+ {
+ unsigned int i = 0;
+ for( i = 0; i < GetNumSlots( ); i++ )
+ {
+ daSoundFileInstance* pObject = GetPendingSwapObject( i );
+ if( pObject != NULL )
+ {
+ daSoundDynaLoadRegion::SlotState state = GetSlotState( i );
+ if( state == Empty )
+ {
+ PerformSwap( i );
+ }
+ }
+ }
+ }
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SwapInObject
+//=============================================================================
+// Description: Swap in a sound object.
+//
+// Parameters: slot - the slot number to swap a sound into
+// pObject - a dynamic loading object
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::SwapInObject
+(
+ unsigned int slot,
+ daSoundFileInstance* pObject
+)
+{
+ // Destroy any pending swap object
+ daSoundFileInstance* pOldObject = GetPendingSwapObject( slot );
+ if( pOldObject != NULL )
+ {
+ SetPendingSwapObject( slot, NULL );
+ ClearActiveSwap( );
+ }
+
+ // Destroy the old object
+ pOldObject = GetSlotObject( slot );
+ if( pOldObject != NULL )
+ {
+ pOldObject->UnLoad( );
+ SetSlotObject( slot, NULL );
+ }
+
+ // Set the pending swap object
+ SetPendingSwapObject( slot, pObject );
+
+ // The swap will occur asynchronously in ServiceOncePerFrame( )
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetSlotState
+//=============================================================================
+// Description: Get the state of a slot
+//
+// Parameters: slot - the slot number to check
+//
+// Return: Returns the state of a slot
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadRegion::SlotState daSoundDynaLoadRegion::GetSlotState
+(
+ unsigned int slot
+)
+{
+ rAssert( m_IsInitialized );
+ rAssert( m_ppSlot != NULL );
+ rAssert( slot < m_NumSlots );
+ rAssert( GetSlotMemoryRegion( slot ) != NULL );
+
+ bool slotHasObject = true;
+ bool slotHasAllocation = true;
+
+ unsigned int numobjs = 0;
+ GetSlotMemoryRegion( slot )->GetStats( NULL, &numobjs, NULL, false );
+ slotHasAllocation = ( ( numobjs != 0 ) && ( !SharedMemoryRegions( ) ) );
+
+ daSoundFileInstance* pObject = GetSlotObject( slot );
+ // If we do not have our own memory regions, we assume that the object has already disapeared.
+ slotHasObject = ( pObject != NULL );
+
+ // Determine the state
+ daSoundDynaLoadRegion::SlotState state = Empty;
+ if( slotHasObject )
+ {
+ rAssert( pObject != NULL );
+
+ if( pObject->UpdateLoading( ) )
+ {
+ state = Ready;
+ }
+ else
+ {
+ state = Initializing;
+ }
+ }
+ else
+ {
+ if( slotHasAllocation )
+ {
+ state = Destroying;
+ }
+ else
+ {
+ state = Empty;
+ }
+ }
+
+ return state;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetNumSlots
+//=============================================================================
+// Description: Get the number of slots in this region
+//
+// Return: Returns the number of slots
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundDynaLoadRegion::GetNumSlots( void )
+{
+ rAssert( m_IsInitialized );
+ return m_NumSlots;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetSlotSize
+//=============================================================================
+// Description: Get the size of the slots in this dynaload region
+//
+// Return: Returns the size of the slots
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundDynaLoadRegion::GetSlotSize( void )
+{
+ rAssert( m_IsInitialized );
+ return m_SlotSize;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SharedMemoryRegions
+//=============================================================================
+// Description: Are the memory regions shared, or does each slot have its own?
+//
+// Return: Returns true if the memory regions are shared.
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundDynaLoadRegion::SharedMemoryRegions( void )
+{
+ return( m_SlotSize == 0 );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::PerformSwap
+//=============================================================================
+// Description: Do an actual swap into a memory slot. The slot
+// should be already verified as empty.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::PerformSwap
+(
+ unsigned int slot
+)
+{
+ bool result = SetActiveSwap( slot );
+ if( result )
+ {
+ rAssert( GetSlotState( slot ) == Empty );
+
+ // Swap in the object
+ daSoundFileInstance* pObject = GetPendingSwapObject( slot );
+ rAssert( pObject != NULL );
+ pObject->AddRef( );
+ SetSlotObject( slot, pObject );
+ SetPendingSwapObject( slot, NULL );
+
+ // Tell it to create itself
+ IRadSoundHalMemoryRegion* pRegion = GetSlotMemoryRegion( slot );
+ rAssert( pRegion != NULL );
+ pObject->Load( pRegion );
+
+ pObject->Release( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetSlotMemoryRegion
+//=============================================================================
+// Description: Get the slot memory region
+//
+// Return: Returns the size of the slots
+//
+//-----------------------------------------------------------------------------
+
+IRadSoundHalMemoryRegion* daSoundDynaLoadRegion::GetSlotMemoryRegion
+(
+ unsigned int slot
+)
+{
+ rAssert( m_IsInitialized );
+ rAssert( m_ppSlot != NULL );
+ rAssert( slot < m_NumSlots );
+
+ return( m_ppSlot[ slot ] );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SetSlotObject
+//=============================================================================
+// Description: Set a slot's object
+//
+// Parameters: slot - the slot whose object is to be set
+// pObject - the object to place in the slot
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::SetSlotObject
+(
+ unsigned int slot,
+ daSoundFileInstance* pObject
+)
+{
+ SetObject_Internal( m_ppSlotObjects, slot, pObject );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetSlotObject
+//=============================================================================
+// Description: Get a slot's object
+//
+// Return: Returns the sound object
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance* daSoundDynaLoadRegion::GetSlotObject
+(
+ unsigned int slot
+)
+{
+ return GetObject_Internal( m_ppSlotObjects, slot );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SetPendingSwapObject
+//=============================================================================
+// Description: Set a pending swap ovject for a given slot
+//
+// Parameters: slot - the slot whose object is to be set
+// pObject - the object to place in the slot
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::SetPendingSwapObject
+(
+ unsigned int slot,
+ daSoundFileInstance* pObject
+)
+{
+ if( GetPendingSwapObject( slot ) != NULL )
+ {
+ --m_PendingSwapCount;
+ --s_GlobalPendingSwapCount;
+ }
+ if( pObject != NULL )
+ {
+ ++m_PendingSwapCount;
+ ++s_GlobalPendingSwapCount;
+ }
+ SetObject_Internal( m_ppPendingSwapObjects, slot, pObject );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::ArePendingSwapsRegistered
+//=============================================================================
+// Description: Returns true if there are still pending swaps registered
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundDynaLoadRegion::ArePendingSwapsRegistered( void )
+{
+ return( m_PendingSwapCount > 0 );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::ArePendingSwapsRegistered
+//=============================================================================
+// Description: Returns true if there are still pending swaps registered
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundDynaLoadRegion::GetNumPendingSwaps( void )
+{
+ return( s_GlobalPendingSwapCount );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetPendingSwapObject
+//=============================================================================
+// Description: Get a pending swap object for a given slot
+//
+// Return: Returns the sound object
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance* daSoundDynaLoadRegion::GetPendingSwapObject
+(
+ unsigned int slot
+)
+{
+ return GetObject_Internal( m_ppPendingSwapObjects, slot );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SetObject_Internal
+//=============================================================================
+// Description: Set an object in an object array
+//
+// Parameters: ppObjects - the object array
+// slot - the slot whose object is to be set
+// pObject - the object to place in the slot
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::SetObject_Internal
+(
+ daSoundFileInstance** ppObjects,
+ unsigned int slot,
+ daSoundFileInstance* pObject
+)
+{
+ rAssert( m_IsInitialized );
+ rAssert( ppObjects != NULL );
+ rAssert( slot < m_NumSlots );
+
+ // Under the current usage of this class, we cannot set a slot object
+ // to anything but NULL if an object already exists.
+ daSoundFileInstance* pOldObject = GetObject_Internal
+ (
+ ppObjects,
+ slot
+ );
+ rAssert( (pObject == NULL ) || ( pOldObject == NULL ) );
+ if( pOldObject != pObject )
+ {
+ // Out with the old
+ if( pOldObject != NULL )
+ {
+ pOldObject->Release( );
+ pOldObject = NULL;
+ }
+
+ // In with the new
+ ppObjects[ slot ] = pObject;
+ rAssert( GetObject_Internal( ppObjects, slot ) == pObject );
+ if( ppObjects[ slot ] != NULL )
+ {
+ ppObjects[ slot ]->AddRef( );
+ }
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::GetObject_Internal
+//=============================================================================
+// Description: Get an object in an object array
+//
+// Return: Returns the sound object
+//
+//-----------------------------------------------------------------------------
+
+daSoundFileInstance* daSoundDynaLoadRegion::GetObject_Internal
+(
+ daSoundFileInstance** ppObjects,
+ unsigned int slot
+)
+{
+ rAssert( m_IsInitialized );
+ rAssert( ppObjects != NULL );
+ rAssert( slot < m_NumSlots );
+
+ return( ppObjects[ slot ] );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::ClearActiveSwap
+//=============================================================================
+// Description: Clear the active swap region
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadRegion::ClearActiveSwap( void )
+{
+ if( s_pActiveRegion == this )
+ {
+ s_pActiveRegion = NULL;
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadRegion::SetActiveSwap
+//=============================================================================
+// Description: Set the active swap to this object. This is used
+// to help serialize dynamic loading.
+//
+// Returns: Returns true if the active swap region has been set to
+// this.
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundDynaLoadRegion::SetActiveSwap( unsigned int slot )
+{
+ if( s_pActiveRegion == NULL )
+ {
+ s_pActiveRegion = this;
+ s_ActiveSlot = slot;
+
+ return true;
+ }
+ return false;
+}
+
+
+//=============================================================================
+// daSoundDynaLoadManager Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::daSoundDynaLoadManager
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadManager::daSoundDynaLoadManager( )
+ :
+ radRefCount( 0 ),
+ m_pCompletionCallback( NULL ),
+ m_pCompletionUserData( NULL )
+{
+ // Set the singleton
+ rAssert( s_pSingleton == NULL );
+ s_pSingleton = this;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager:~daSoundDynaLoadManager
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadManager::~daSoundDynaLoadManager( )
+{
+ // Remove the singleton
+ rAssert( s_pSingleton != NULL );
+ s_pSingleton = NULL;
+
+ // Assert that there is no pending completion callback
+ rAssert( m_pCompletionCallback == NULL );
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::GetInstance
+//=============================================================================
+// Description: Get the singleton instance of the load manager
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadManager* daSoundDynaLoadManager::GetInstance( void )
+{
+ return s_pSingleton;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the load manager.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadManager::ServiceOncePerFrame( void )
+{
+ IDaSoundDynaLoadCompletionCallback* callback;
+
+ // Service each of the regions
+ daSoundDynaLoadRegion* pDynaLoadRegion =
+ daSoundDynaLoadRegion::GetLinkedClassHead( );
+ while( pDynaLoadRegion != NULL )
+ {
+ pDynaLoadRegion->ServiceOncePerFrame( );
+ pDynaLoadRegion = pDynaLoadRegion->GetLinkedClassNext( );
+ }
+
+ // Call any completion callbacks
+ if
+ (
+ ( m_pCompletionCallback != NULL ) &&
+ ( daSoundDynaLoadRegion::GetNumPendingSwaps( ) == 0 )
+ )
+ {
+ //
+ // Store the callback separately before using, since the callback
+ // may lead to another sound load
+ //
+ callback = m_pCompletionCallback;
+ m_pCompletionCallback = NULL;
+ m_pCompletionUserData = NULL;
+
+ callback->OnDynaLoadOperationsComplete
+ (
+ m_pCompletionUserData
+ );
+
+ callback->Release();
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::CreateRegion
+//=============================================================================
+// Description: Create a dynamic loading region
+//
+// Parameters: pMemRegion - the sound region to divide up so that
+// the given slots may be created.
+// sizeofslots - the size of the dynamic loading slots
+// numslots - the number of dynamic loading slots
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadRegion* daSoundDynaLoadManager::CreateRegion
+(
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots,
+ unsigned int numslots
+)
+{
+ rAssert( pMemRegion != NULL );
+#ifdef DASOUNDDYNALOAD_DEBUG
+ if( sg_ShowDynaLoadRegionCreation )
+ {
+ rReleasePrintf
+ (
+ "CreateRegion( %#x, sizeofslots=%u, numslots=%u )\n",
+ pMemRegion,
+ sizeofslots,
+ numslots,
+ 0
+ );
+ }
+#endif //DASOUNDDYNALOAD_DEBUG
+
+ // Make sure the new region fits into memory
+ unsigned int freeSpace = 0;
+ pMemRegion->GetStats( NULL, NULL, &freeSpace, false );
+ daSoundDynaLoadRegion* pDynaRegion = NULL;
+ if( freeSpace >= sizeofslots * numslots )
+ {
+ // Create the memory region
+ pDynaRegion = new( GetThisAllocator( ) ) daSoundDynaLoadRegion( );
+ rAssert( pDynaRegion != NULL );
+ pDynaRegion->Create( pMemRegion, sizeofslots, numslots );
+ }
+ else
+ {
+ // Out of memory!
+ // If this occurs during the game, your loading stratagies must be
+ // reconsidered. If it happens while setting up sounds for
+ // the game then the choices of resident sound files must
+ // be looked at, or more sound memory should be allocated.
+ rDebugString( "Out of sound memory trying to create sound region\n" );
+ rAssert( 0 );
+ }
+
+ return pDynaRegion;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::CreateRegionFromTotalSpace
+//=============================================================================
+// Description: Create a dynamic loading region when given a total amount of
+// space.
+//
+// Parameters: pMemRegion - the sound region to divide up so that
+// the given slots may be created.
+// sizeofslots - the size of the dynamic loading slots
+//
+// Note: The actual amount of space used will be aligned down by the
+// size of slots.
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadRegion* daSoundDynaLoadManager::CreateRegionFromTotalSpace
+(
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots
+)
+{
+ rAssert( pMemRegion != NULL );
+
+ // How much free space is there?
+ unsigned int freeSpace = 0;
+ pMemRegion->GetStats( NULL, NULL, &freeSpace, false );
+
+ // How many slots can we make
+ unsigned int numslots = freeSpace / sizeofslots;
+
+ // Make the slots
+ daSoundDynaLoadRegion* pDynaRegion = NULL;
+ if( numslots > 0 )
+ {
+ pDynaRegion = CreateRegion( pMemRegion, sizeofslots, numslots );
+ }
+
+ return pDynaRegion;
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::AddCompletionCallback
+//=============================================================================
+// Description: Add a completion callback
+//
+//-----------------------------------------------------------------------------
+
+void daSoundDynaLoadManager::AddCompletionCallback
+(
+ IDaSoundDynaLoadCompletionCallback* pCallback,
+ void* pUserData
+)
+{
+ if( m_pCompletionCallback != NULL )
+ {
+ rDebugString( "Cannot add a completion callback while one is\n" );
+ rDebugString( "pending using current sounddynamic loading manager.\n" );
+ rAssert( 0 );
+
+ m_pCompletionCallback->Release( );
+ m_pCompletionCallback = NULL;
+ }
+
+ m_pCompletionCallback = pCallback;
+ m_pCompletionUserData = pUserData;
+
+ if( m_pCompletionCallback != NULL )
+ {
+ m_pCompletionCallback->AddRef( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundDynaLoadManager::GetNumPendingSwaps
+//=============================================================================
+// Description: Returns the number of load regions in line to
+// be loaded with new data
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundDynaLoadManager::GetNumPendingSwaps( void )
+{
+ return daSoundDynaLoadRegion::GetNumPendingSwaps( );
+}
+
+} // Sound Namespace
diff --git a/game/code/sound/soundrenderer/sounddynaload.h b/game/code/sound/soundrenderer/sounddynaload.h
new file mode 100644
index 0000000..ef24357
--- /dev/null
+++ b/game/code/sound/soundrenderer/sounddynaload.h
@@ -0,0 +1,199 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: sounddynaload.hpp
+//
+// Subsystem: Dark Angel - Dynamic Loading System
+//
+// Description: Description of the DA Dynamic Sound Loading System
+//
+// Revisions:
+// + Created: Novemeber 22, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _SOUNDDYNALOAD_HPP
+#define _SOUNDDYNALOAD_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <radsound.hpp>
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundDynaLoadRegion;
+class daSoundDynaLoadManager;
+class daSoundFileInstance;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+struct IDaSoundDynaLoadCompletionCallback : public IRefCount
+{
+ virtual void OnDynaLoadOperationsComplete( void* pUserData ) = 0;
+};
+
+//
+// A dynamic load region
+//
+class daSoundDynaLoadRegion : public radLinkedClass< daSoundDynaLoadRegion >,
+ public radRefCount
+{
+public:
+
+ enum SlotState {
+ Empty,
+ Initializing,
+ Ready,
+ Destroying
+ };
+
+ IMPLEMENT_REFCOUNTED( "daSoundDynaLoadRegion" );
+ daSoundDynaLoadRegion( );
+ virtual ~daSoundDynaLoadRegion( );
+
+ // Create and destroy the region
+ void Create
+ (
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots,
+ unsigned int numslots
+ );
+ void Destroy( void );
+ void ServiceOncePerFrame( void );
+
+ // Track if there are any pending swaps registered.
+ static unsigned int GetNumPendingSwaps( void );
+
+ //
+ // daSoundDynaLoadRegion
+ //
+ void SwapInObject
+ (
+ unsigned int slot,
+ daSoundFileInstance* pObject
+ );
+ daSoundDynaLoadRegion::SlotState GetSlotState
+ (
+ unsigned int slot
+ );
+ unsigned int GetNumSlots( void );
+ unsigned int GetSlotSize( void );
+
+protected:
+ bool SharedMemoryRegions( void );
+
+ void PerformSwap( unsigned int slot );
+
+ IRadSoundHalMemoryRegion* GetSlotMemoryRegion( unsigned int slot );
+
+ void SetSlotObject( unsigned int slot, daSoundFileInstance* pObject );
+ daSoundFileInstance* GetSlotObject( unsigned int slot );
+
+ void SetPendingSwapObject( unsigned int slot, daSoundFileInstance * pObject );
+ bool ArePendingSwapsRegistered( void );
+ daSoundFileInstance* GetPendingSwapObject( unsigned int slot );
+
+ void SetObject_Internal
+ (
+ daSoundFileInstance** ppObjects,
+ unsigned int slot,
+ daSoundFileInstance* pObject
+ );
+ daSoundFileInstance* GetObject_Internal
+ (
+ daSoundFileInstance** ppObjects,
+ unsigned int slot
+ );
+
+ void ClearActiveSwap( void );
+ bool SetActiveSwap( unsigned int slot );
+
+private:
+ bool m_IsInitialized;
+
+ // The active swap
+ static daSoundDynaLoadRegion* s_pActiveRegion;
+ static unsigned int s_ActiveSlot;
+
+ // Region information
+ unsigned int m_NumSlots;
+ unsigned int m_SlotSize;
+
+ // Allocated regions
+ IRadSoundHalMemoryRegion** m_ppSlot;
+ daSoundFileInstance** m_ppSlotObjects;
+ daSoundFileInstance** m_ppPendingSwapObjects;
+
+ // Count of pending swap operations
+ unsigned int m_PendingSwapCount;
+ static unsigned int s_GlobalPendingSwapCount;
+};
+
+//
+// Dynamic loading system interface
+//
+class daSoundDynaLoadManager : public radRefCount
+{
+public:
+ IMPLEMENT_REFCOUNTED( "daSoundDynaLoadManager" );
+ daSoundDynaLoadManager( );
+ virtual ~daSoundDynaLoadManager( );
+
+ static daSoundDynaLoadManager* GetInstance( void );
+
+ //
+ // daSoundDynaLoadRegion
+ //
+ virtual void ServiceOncePerFrame( void );
+
+ daSoundDynaLoadRegion* CreateRegion
+ (
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots,
+ unsigned int numslots
+ );
+ daSoundDynaLoadRegion* CreateRegionFromTotalSpace
+ (
+ IRadSoundHalMemoryRegion* pMemRegion,
+ unsigned int sizeofslots
+ );
+ void AddCompletionCallback
+ (
+ IDaSoundDynaLoadCompletionCallback* pCallback,
+ void* pUserData
+ );
+ unsigned int GetNumPendingSwaps( void );
+
+protected:
+private:
+ //
+ // Store this class as a singleton
+ //
+ static daSoundDynaLoadManager* s_pSingleton;
+
+ //
+ // Store a completion callback
+ //
+ IDaSoundDynaLoadCompletionCallback* m_pCompletionCallback;
+ void* m_pCompletionUserData;
+};
+
+} // Sound Namespace
+#endif //_SOUNDDYNALOAD_HPP
+
diff --git a/game/code/sound/soundrenderer/soundnucleus.cpp b/game/code/sound/soundrenderer/soundnucleus.cpp
new file mode 100644
index 0000000..2c56488
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundnucleus.cpp
@@ -0,0 +1,594 @@
+#include <sound/soundrenderer/soundnucleus.hpp>
+#include <main/commandlineoptions.h>
+#include <memory/srrmemory.h>
+#include <radmusic/radmusic.hpp>
+#include <memory/srrmemory.h>
+
+namespace Sound
+{
+
+const Encoding gPcmEncoding = { IRadSoundHalAudioFormat::PCM, 1, 1 };
+const Encoding gPcmBEncoding = { IRadSoundHalAudioFormat::PCM_BIGENDIAN, 1, 1 };
+const Encoding gVagEncoding = { IRadSoundHalAudioFormat::VAG, 2, 7 };
+const Encoding gGcAdpcmEncoding = { IRadSoundHalAudioFormat::GCNADPCM, 2, 7 };
+const Encoding gRadAdpcmEncoding = { IRadSoundHalAudioFormat::RadicalAdpcm, 5, 16 };
+const Encoding gXAdpcmEncoding = { IRadSoundHalAudioFormat::XBOXADPCM, 36, 128 };
+
+const unsigned int NUM_AUX_SENDS = 1;
+
+const unsigned int MUSIC_NUM_STREAM_PLAYERS = 4;
+const unsigned int MUSIC_NUM_CLIP_PLAYERS = 2;
+const unsigned int MUSIC_NUM_CHANNELS = 2;
+const unsigned int MUSIC_SAMPLING_RATE = 24000;
+
+const unsigned int TOTAL_PS2_FREE_UNCOMPRESSED_CLIP_BYTES = ( 1624 * 1024 * 7 ) / 2;
+
+#if defined RAD_GAMECUBE
+
+ const int ARAM_SILENT_BUFFER_SIZE = 1280;
+ const int ARAM_USER_START = 0x4000;
+ const int ARAM_RESERVED_BINK_MEMORY = 0x25800;
+ const int GAMECUBE_SOUND_MEMORY_AVAILABLE =
+ ( 1024 * 1024 * 10 ) - ARAM_SILENT_BUFFER_SIZE - ARAM_USER_START - ARAM_RESERVED_BINK_MEMORY;
+
+ const int PLAYBACK_RATE = 32000;
+
+ AudioFormat gCompressedStreamAudioFormat = { 1, & gGcAdpcmEncoding, 24000 };
+ AudioFormat gUnCompressedStreamAudioFormat = { 1, & gPcmBEncoding, 24000 };
+ AudioFormat gClipFileAudioFormat = { 1, & gPcmBEncoding, 24000 };
+ AudioFormat gMusicAudioFormat = { 2, & gPcmBEncoding, 24000 };
+
+ const unsigned int STREAM_BUFFER_SIZE_MS = 6000;
+ const bool STREAM_USE_BUFFERED_DATA_SOURCES = false;
+ const unsigned int STREAM_BUFFERED_DATA_SOURCE_SIZE_MS = 0;
+ const radMemorySpace STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Local;
+
+ const unsigned int CLIP_BUFFERED_DATA_SOURCE_SIZE_MS = 0;
+ const radMemorySpace CLIP_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Local;
+
+#elif defined RAD_XBOX || defined RAD_WIN32
+
+ const int PLAYBACK_RATE = 0;
+
+#ifdef PAL
+ AudioFormat gCompressedStreamAudioFormat = { 1, & gXAdpcmEncoding, 24000 };
+#else
+ AudioFormat gCompressedStreamAudioFormat = { 1, & gPcmEncoding, 24000 };
+#endif
+ AudioFormat gUnCompressedStreamAudioFormat = { 1, & gPcmEncoding, 24000 };
+ AudioFormat gClipFileAudioFormat = { 1, & gPcmEncoding, 24000 };
+ AudioFormat gMusicAudioFormat = { 2, & gPcmEncoding, 24000 };
+
+ const unsigned int STREAM_BUFFER_SIZE_MS = 6000;
+ const bool STREAM_USE_BUFFERED_DATA_SOURCES = false;
+ const unsigned int STREAM_BUFFERED_DATA_SOURCE_SIZE_MS = 0;
+ const radMemorySpace STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Local;
+
+ const unsigned int CLIP_BUFFERED_DATA_SOURCE_SIZE_MS = 0;
+ const radMemorySpace CLIP_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Local;
+
+
+#elif defined RAD_PS2
+
+ const int PLAYBACK_RATE = 0;
+
+ AudioFormat gCompressedStreamAudioFormat = { 1, & gVagEncoding, 24000 };
+ AudioFormat gUnCompressedStreamAudioFormat = { 1, & gVagEncoding, 24000 };
+ AudioFormat gClipFileAudioFormat = { 1, & gVagEncoding, 24000 };
+ AudioFormat gMusicAudioFormat = { 2, & gVagEncoding, 24000 };
+
+ const unsigned int STREAM_BUFFER_SIZE_MS = 1000;
+ const bool STREAM_USE_BUFFERED_DATA_SOURCES = true;
+ const unsigned int STREAM_BUFFERED_DATA_SOURCE_SIZE_MS = 4100;
+ const radMemorySpace STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Iop;
+
+ const unsigned int CLIP_BUFFERED_DATA_SOURCE_SIZE_MS = 5000;
+ const radMemorySpace CLIP_BUFFERED_DATA_SOURCE_MEMORY_SPACE = radMemorySpace_Ee;
+
+#endif
+
+enum ClipLoadState
+{
+ ClipLoadState_Idle,
+ ClipLoadState_InitFile,
+ ClipLoadState_FillingBuffer,
+ ClipLoadState_LoadingClip,
+ ClipLoadState_Done
+};
+
+
+struct ClipLoadInfo
+{
+ IRadSoundRsdFileDataSource * pFds;
+ IRadSoundClip * pClip;
+ IRadSoundBufferedDataSource * pBds;
+ ClipLoadState state;
+ bool looping;
+} gClipLoadInfo;
+
+StreamerResources gStreamers[ SOUND_NUM_STREAM_PLAYERS ] =
+{
+ { NULL, NULL, NULL, & gCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+#ifdef RAD_XBOX
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 },
+#endif
+ { NULL, NULL, NULL, & gUnCompressedStreamAudioFormat, false, 0 }
+};
+
+
+void CreateAudioFormat( AudioFormat * pAf, radMemoryAllocator alloc )
+{
+ pAf->m_pAudioFormat = ::radSoundHalAudioFormatCreate( alloc );
+ pAf->m_pAudioFormat->AddRef( );
+
+ pAf->m_pAudioFormat->Initialize(
+ pAf->m_pEncoding->m_Encoding,
+ NULL,
+ pAf->m_SamplingRate,
+ pAf->m_Channels,
+ 16 );
+}
+
+void DestroyAudioFormat( AudioFormat * pAf )
+{
+ pAf->m_pAudioFormat->Release( );
+ pAf->m_pAudioFormat = NULL;
+}
+
+void CreateStreamerResources( StreamerResources * pSi, radMemoryAllocator alloc )
+{
+ pSi->m_pStreamPlayer = ::radSoundStreamPlayerCreate( alloc );
+ pSi->m_pStreamPlayer->AddRef( );
+
+ pSi->m_pStreamPlayer->Initialize(
+ pSi->m_pAudioFormat->m_pAudioFormat,
+ STREAM_BUFFER_SIZE_MS,
+ IRadSoundHalAudioFormat::Milliseconds,
+ ::radSoundHalSystemGet( )->GetRootMemoryRegion( ),
+ "Sound Stream Player" );
+
+ pSi->m_pStitchedDataSource = ::radSoundStitchedDataSourceCreate( alloc );
+ pSi->m_pStitchedDataSource->AddRef( );
+ pSi->m_pStitchedDataSource->InitializeFromAudioFormat( pSi->m_pAudioFormat->m_pAudioFormat );
+
+ if ( STREAM_USE_BUFFERED_DATA_SOURCES && ( false == CommandLineOptions::Get( CLO_FIREWIRE ) ) )
+ {
+ pSi->m_pBufferedDataSource = radSoundBufferedDataSourceCreate( alloc );
+ pSi->m_pBufferedDataSource->AddRef( );
+
+ pSi->m_pBufferedDataSource->Initialize(
+ STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE,
+ radMemorySpaceGetAllocator( STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE, RADMEMORY_ALLOC_DEFAULT ), // This is IOP Memory
+ STREAM_BUFFERED_DATA_SOURCE_SIZE_MS,
+ IRadSoundHalAudioFormat::Milliseconds,
+ pSi->m_pAudioFormat->m_pAudioFormat,
+ "DaSound Buffered DataSource" );
+
+ }
+ else
+ {
+ pSi->m_pBufferedDataSource = NULL;
+ }
+}
+
+void DestroyStreamerResources( StreamerResources* pSi )
+{
+ // Its a stream player
+ pSi->m_pStreamPlayer->Stop( );
+ pSi->m_pStreamPlayer->SetDataSource( NULL );
+
+ if( pSi->m_pBufferedDataSource )
+ {
+ pSi->m_pBufferedDataSource->Release( );
+ pSi->m_pBufferedDataSource = NULL;
+ }
+
+ // Release the player
+ pSi->m_pStreamPlayer->Release( );
+ pSi->m_pStreamPlayer = NULL;
+
+
+ pSi->m_pStitchedDataSource->Release( );
+ pSi->m_pStitchedDataSource = NULL;
+}
+
+unsigned int CalculateStreamerSize( unsigned int ms, AudioFormat * pAf )
+{
+ unsigned int sizeInFrames = pAf->m_pAudioFormat->MillisecondsToFrames( ms );
+
+ unsigned int optimalFrameMultiple =
+ pAf->m_pAudioFormat->BytesToFrames( radSoundHalDataSourceReadMultipleGet( ) );
+
+ // Our buffer must be at least as big as two optimal reads.
+
+ sizeInFrames = radMemoryRoundUp( sizeInFrames, optimalFrameMultiple * 2 );
+
+ sizeInFrames = ::radSoundHalBufferCalculateMemorySize( IRadSoundHalAudioFormat::Frames,
+ sizeInFrames, IRadSoundHalAudioFormat::Frames, pAf->m_pAudioFormat );
+
+ unsigned int sizeInBytes = pAf->m_pAudioFormat->FramesToBytes( sizeInFrames );
+
+ return sizeInBytes;
+}
+
+void SoundNucleusInitialize( radMemoryAllocator alloc )
+{
+
+#if defined( RAD_PS2 ) || defined( RAD_GAMECUBE ) || defined( RAD_WIN32 )
+ ::radSoundHalSystemInitialize( alloc );
+#else
+ ::radSoundHalSystemInitialize( GMA_XBOX_SOUND_MEMORY );
+#endif
+
+ CreateAudioFormat( & gCompressedStreamAudioFormat, alloc );
+ CreateAudioFormat( & gUnCompressedStreamAudioFormat, alloc );
+ CreateAudioFormat( & gClipFileAudioFormat, alloc );
+ CreateAudioFormat( & gMusicAudioFormat, alloc );
+
+
+
+ //
+ // ESAN TODO: Investigate the magic number 150 below...
+ //
+
+ unsigned int totalStreamSoundMemoryNeeded = 0;
+ unsigned int totalStreamBufferMemoryNeeded = 0;
+ unsigned int totalClipBufferMemoryNeeded = 0;
+
+ if ( CLIP_BUFFERED_DATA_SOURCE_SIZE_MS > 0 )
+ {
+ gClipLoadInfo.pBds = radSoundBufferedDataSourceCreate( GMA_AUDIO_PERSISTENT );
+ gClipLoadInfo.pBds->AddRef( );
+ gClipLoadInfo.pBds->Initialize(
+ CLIP_BUFFERED_DATA_SOURCE_MEMORY_SPACE,
+ radMemorySpaceGetAllocator(
+ CLIP_BUFFERED_DATA_SOURCE_MEMORY_SPACE,
+ GMA_AUDIO_PERSISTENT ),
+ CLIP_BUFFERED_DATA_SOURCE_SIZE_MS,
+ IRadSoundHalAudioFormat::Milliseconds,
+ SoundNucleusGetClipFileAudioFormat( ),
+ "Clip Bds" );
+
+ gClipLoadInfo.pBds->SetLowWaterMark( 1.0f );
+
+ totalClipBufferMemoryNeeded =
+ SoundNucleusGetClipFileAudioFormat( )->MillisecondsToBytes(
+ CLIP_BUFFERED_DATA_SOURCE_SIZE_MS );
+ }
+
+
+ for( unsigned int i = 0; i < SOUND_NUM_STREAM_PLAYERS; i ++ )
+ {
+ StreamerResources* pSi = gStreamers + i;
+
+ unsigned int streamSoundMemoryNeeded = CalculateStreamerSize(
+ STREAM_BUFFER_SIZE_MS,
+ pSi->m_pAudioFormat );
+
+ totalStreamSoundMemoryNeeded += streamSoundMemoryNeeded;
+
+ unsigned int streamBufferMemoryNeeded = CalculateStreamerSize(
+ STREAM_BUFFERED_DATA_SOURCE_SIZE_MS,
+ pSi->m_pAudioFormat );
+
+ totalStreamBufferMemoryNeeded += streamBufferMemoryNeeded;
+
+ rTunePrintf( "AUDIO: Predicting SOUND streamer will allocate: Sound: [0x%x] Buffer:[0x%x]\n",
+ streamSoundMemoryNeeded,
+ streamBufferMemoryNeeded );
+ }
+
+ for( unsigned int i = 0; i < MUSIC_NUM_STREAM_PLAYERS; i ++ )
+ {
+ unsigned int streamSoundMemoryNeeded = CalculateStreamerSize(
+ STREAM_BUFFER_SIZE_MS,
+ & gMusicAudioFormat );
+
+ totalStreamSoundMemoryNeeded += streamSoundMemoryNeeded;
+
+ unsigned int streamBufferMemoryNeeded = CalculateStreamerSize(
+ STREAM_BUFFERED_DATA_SOURCE_SIZE_MS,
+ & gMusicAudioFormat );
+
+ totalStreamBufferMemoryNeeded += streamBufferMemoryNeeded;
+
+ rTunePrintf( "AUDIO: Predicting MUSIC streamer will allocate: Sound: [0x%x] Buffer:[0x%x]\n",
+ streamSoundMemoryNeeded,
+ streamBufferMemoryNeeded );
+
+ }
+
+ unsigned int totalClipMemoryNeeded =
+ ( TOTAL_PS2_FREE_UNCOMPRESSED_CLIP_BYTES * gClipFileAudioFormat.m_pEncoding->m_CompressionNumerator ) /
+ gClipFileAudioFormat.m_pEncoding->m_CompressionDenominator;
+
+ rTunePrintf(
+ "AUDIO: Sound Memory totals: Stream: [0x%x] Clip: [0x%x], Total: [0x%x]\n",
+ totalStreamSoundMemoryNeeded,
+ totalClipMemoryNeeded,
+ totalStreamSoundMemoryNeeded + totalClipMemoryNeeded );
+
+ #ifdef RAD_GAMECUBE
+ rAssert(
+ ( totalStreamSoundMemoryNeeded + totalClipMemoryNeeded ) <=
+ GAMECUBE_SOUND_MEMORY_AVAILABLE );
+ #endif
+
+ rTunePrintf(
+ "AUDIO: Sound Buffered Stream Memory Stream: [0x%x], Clip: [0x%x] Total:\n",
+ totalStreamBufferMemoryNeeded,
+ totalClipBufferMemoryNeeded,
+ totalStreamBufferMemoryNeeded + totalClipBufferMemoryNeeded );
+
+ IRadSoundHalSystem::SystemDescription desc;
+
+ desc.m_MaxRootAllocations = 170;
+ desc.m_NumAuxSends = NUM_AUX_SENDS;
+#ifdef RAD_WIN32
+ desc.m_SamplingRate = 24000;
+#endif
+
+#ifndef RAD_PS2
+ desc.m_ReservedSoundMemory = totalStreamSoundMemoryNeeded + totalClipMemoryNeeded;
+#endif
+
+#ifdef RAD_GAMECUBE
+ desc.m_EffectsAllocator = GMA_AUDIO_PERSISTENT;
+#endif
+
+ ::radSoundHalSystemGet( )->Initialize( desc );
+ //::radSoundHalSystemGet( )->SetOutputMode( radSoundOutputMode_Surround );
+
+ for( unsigned int i = 0; i < SOUND_NUM_STREAM_PLAYERS; i ++ )
+ {
+ gStreamers[ i ].index = i;
+ CreateStreamerResources( gStreamers + i, alloc );
+ }
+
+ radmusic::stream_graph_description sgDesc[ MUSIC_NUM_STREAM_PLAYERS ];
+
+ for( unsigned int i = 0; i < MUSIC_NUM_STREAM_PLAYERS; i ++ )
+ {
+ sgDesc[ i ].buffered_data_source_size_in_ms = STREAM_BUFFERED_DATA_SOURCE_SIZE_MS;
+ sgDesc[ i ].buffered_data_source_space = STREAM_BUFFERED_DATA_SOURCE_MEMORY_SPACE;
+ sgDesc[ i ].channels = MUSIC_NUM_CHANNELS;
+ sgDesc[ i ].sampling_rate = MUSIC_SAMPLING_RATE;
+ sgDesc[ i ].stream_buffer_size_in_ms = STREAM_BUFFER_SIZE_MS;
+ sgDesc[ i ].use_buffered_data_source = CommandLineOptions::Get( CLO_FIREWIRE ) ? false : STREAM_USE_BUFFERED_DATA_SOURCES;
+ }
+
+ radmusic::initialize( sgDesc, MUSIC_NUM_STREAM_PLAYERS, MUSIC_NUM_CLIP_PLAYERS, GMA_MUSIC );
+ radmusic::register_radload_loaders( );
+
+}
+
+void SoundNucleusTerminate( void )
+{
+ rAssert( ClipLoadState_Idle == gClipLoadInfo.state );
+
+ if ( gClipLoadInfo.pBds != NULL )
+ {
+ gClipLoadInfo.pBds->Release( );
+ }
+
+ for( unsigned int i = 0; i < SOUND_NUM_STREAM_PLAYERS; i ++ )
+ {
+ DestroyStreamerResources( gStreamers + i );
+ }
+
+ DestroyAudioFormat( & gCompressedStreamAudioFormat );
+ DestroyAudioFormat( & gUnCompressedStreamAudioFormat );
+ DestroyAudioFormat( & gClipFileAudioFormat );
+ DestroyAudioFormat( & gMusicAudioFormat );
+
+ radmusic::terminate( );
+
+ // Shutdown our related systems
+ ::radSoundHalSystemTerminate( );
+
+}
+
+IRadSoundHalAudioFormat * SoundNucleusGetStreamFileAudioFormat( void )
+{
+#if defined( RAD_GAMECUBE ) || ( defined( RAD_XBOX ) && defined( PAL ) )
+ return NULL;
+ #else
+ return gUnCompressedStreamAudioFormat.m_pAudioFormat;
+ #endif
+
+}
+
+IRadSoundHalAudioFormat * SoundNucleusGetClipFileAudioFormat( void )
+{
+ return gClipFileAudioFormat.m_pAudioFormat;
+}
+
+StreamerResources* SoundNucleusCaptureStreamerResources( IRadSoundHalAudioFormat * pAf )
+{
+ for( unsigned int i = 0; i < SOUND_NUM_STREAM_PLAYERS; i ++ )
+ {
+ StreamerResources * pSi =
+ gStreamers + i;
+
+ if ( ! pSi->m_IsCaptured )
+ {
+ if ( pSi->m_pAudioFormat->m_pAudioFormat->Matches( pAf ) )
+ {
+ pSi->m_IsCaptured = true;
+ return pSi;
+ }
+ }
+ }
+
+ rTuneAssertMsg( false, "Out of streamers of desired format" );
+
+ return NULL;
+}
+
+void SoundNucleusUnCaptureStreamerResources( StreamerResources * pSi )
+{
+ rAssert( gStreamers[ pSi->index ].m_IsCaptured == true );
+ gStreamers[ pSi->index ].m_IsCaptured = false;
+}
+
+void SoundNucleusLoadClip( const char * pFileName, bool looping )
+{
+ rAssert( ClipLoadState_Idle == gClipLoadInfo.state );
+
+ gClipLoadInfo.pFds = radSoundRsdFileDataSourceCreate( GMA_AUDIO_PERSISTENT );
+ gClipLoadInfo.pFds->AddRef( );
+ gClipLoadInfo.looping = looping;
+
+
+ // Initialize the file data source iwth our file
+ //
+ gClipLoadInfo.pFds->InitializeFromFileName(
+ pFileName,
+ false,
+ 0,
+ IRadSoundHalAudioFormat::Frames,
+ SoundNucleusGetClipFileAudioFormat( ) );
+
+ gClipLoadInfo.state = ClipLoadState_InitFile;
+}
+
+bool SoundNucleusIsClipLoaded( void )
+{
+ rAssert( ClipLoadState_Idle != gClipLoadInfo.state );
+
+ return ClipLoadState_Done == gClipLoadInfo.state;
+}
+
+void SoundNucleusFinishClipLoad( IRadSoundClip ** ppClip )
+{
+ rAssert( ClipLoadState_Done == gClipLoadInfo.state );
+
+ *ppClip = gClipLoadInfo.pClip;
+ gClipLoadInfo.pClip = NULL;
+
+ gClipLoadInfo.pFds->Release( );
+ gClipLoadInfo.pFds = NULL;
+
+ if ( NULL != gClipLoadInfo.pBds )
+ {
+ gClipLoadInfo.pBds->SetInputDataSource( 0 );
+ }
+
+ gClipLoadInfo.state = ClipLoadState_Idle;
+}
+
+void SoundNucleusCancelClipLoad( void )
+{
+ rAssert( ClipLoadState_Idle != gClipLoadInfo.state );
+
+ if( NULL != gClipLoadInfo.pClip )
+ {
+ gClipLoadInfo.pClip->Release( );
+ gClipLoadInfo.pClip = NULL;
+ }
+
+ if( NULL != gClipLoadInfo.pFds )
+ {
+ gClipLoadInfo.pFds->Release( );
+ gClipLoadInfo.pFds = NULL;
+ }
+
+ if ( NULL != gClipLoadInfo.pBds )
+ {
+ gClipLoadInfo.pBds->SetInputDataSource( 0 );
+ }
+
+ gClipLoadInfo.state = ClipLoadState_Idle;
+
+}
+
+
+void SoundNucleusServiceClipLoad( void )
+{
+ ClipLoadState oldState;
+
+ do
+ {
+ oldState = gClipLoadInfo.state;
+
+ switch ( gClipLoadInfo.state )
+ {
+ case ClipLoadState_Idle:
+ {
+ break;
+ }
+ case ClipLoadState_InitFile:
+ {
+ if ( IRadSoundHalDataSource::Initialized == gClipLoadInfo.pFds->GetState( ) )
+ {
+ if ( gClipLoadInfo.pBds != NULL )
+ {
+ unsigned int ms =
+ gClipLoadInfo.pBds->GetFormat( )->FramesToMilliseconds(
+ gClipLoadInfo.pFds->GetRemainingFrames( ) );
+
+ rTuneAssert( ms < CLIP_BUFFERED_DATA_SOURCE_SIZE_MS );
+
+ gClipLoadInfo.pBds->SetInputDataSource( gClipLoadInfo.pFds );
+
+ gClipLoadInfo.state = ClipLoadState_FillingBuffer;
+ }
+ else
+ {
+ gClipLoadInfo.pClip = radSoundClipCreate( GMA_AUDIO_PERSISTENT );
+ gClipLoadInfo.pClip->AddRef( );
+ gClipLoadInfo.pClip->Initialize(
+ gClipLoadInfo.pFds,
+ radSoundHalSystemGet( )->GetRootMemoryRegion( ),
+ gClipLoadInfo.looping,
+ "Clip" );
+
+ gClipLoadInfo.state = ClipLoadState_LoadingClip;
+ }
+ }
+
+ break;
+ }
+ case ClipLoadState_FillingBuffer:
+ {
+ if ( gClipLoadInfo.pBds->IsBufferFull( ) )
+ {
+ gClipLoadInfo.pClip = radSoundClipCreate( GMA_AUDIO_PERSISTENT );
+ gClipLoadInfo.pClip->AddRef( );
+ gClipLoadInfo.pClip->Initialize(
+ gClipLoadInfo.pBds,
+ radSoundHalSystemGet( )->GetRootMemoryRegion( ),
+ gClipLoadInfo.looping,
+ "Clip" );
+
+ gClipLoadInfo.state = ClipLoadState_LoadingClip;
+ }
+
+ break;
+ }
+ case ClipLoadState_LoadingClip:
+ {
+ if ( IRadSoundClip::Initialized == gClipLoadInfo.pClip->GetState( ) )
+ {
+ gClipLoadInfo.state = ClipLoadState_Done;
+ }
+
+ break;
+ }
+ case ClipLoadState_Done:
+ {
+ break;
+ }
+ }
+ }
+ while( oldState != gClipLoadInfo.state );
+}
+
+} \ No newline at end of file
diff --git a/game/code/sound/soundrenderer/soundnucleus.hpp b/game/code/sound/soundrenderer/soundnucleus.hpp
new file mode 100644
index 0000000..dc028e3
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundnucleus.hpp
@@ -0,0 +1,70 @@
+
+#ifndef SOUNDNUCLEUS_HPP
+#define SOUNDNUCLEUS_HPP
+
+#include <radmemory.hpp>
+#include <radsound.hpp>
+
+namespace Sound
+{
+#ifdef RAD_XBOX
+ const unsigned int SOUND_NUM_STREAM_PLAYERS = 10;
+#else
+ const unsigned int SOUND_NUM_STREAM_PLAYERS = 9;
+#endif
+ const unsigned int SOUND_NUM_CLIP_PLAYERS = 64;
+
+struct Encoding
+{
+ IRadSoundHalAudioFormat::Encoding m_Encoding;
+ unsigned int m_CompressionNumerator;
+ unsigned int m_CompressionDenominator;
+};
+
+struct AudioFormat
+{
+ unsigned int m_Channels;
+ const Encoding * m_pEncoding;
+ unsigned int m_SamplingRate;
+ IRadSoundHalAudioFormat * m_pAudioFormat;
+};
+
+struct StreamerResources
+{
+ IRadSoundStreamPlayer * m_pStreamPlayer;
+ IRadSoundBufferedDataSource * m_pBufferedDataSource;
+ IRadSoundStitchedDataSource * m_pStitchedDataSource;
+ AudioFormat * m_pAudioFormat;
+ bool m_IsCaptured;
+ unsigned int index;
+};
+
+void SoundNucleusInitialize( radMemoryAllocator alloc );
+void SoundNucleusTerminate( void );
+
+IRadSoundHalAudioFormat * SoundNucleusGetStreamFileAudioFormat( void );
+IRadSoundHalAudioFormat * SoundNucleusGetClipFileAudioFormat( void );
+
+StreamerResources * SoundNucleusCaptureStreamerResources( IRadSoundHalAudioFormat * pAf );
+void SoundNucleusUnCaptureStreamerResources( StreamerResources * pSi );
+
+void SoundNucleusLoadClip( const char * pFileName, bool looping );
+bool SoundNucleusIsClipLoaded( void );
+void SoundNucleusCancelClipLoad( void );
+void SoundNucleusFinishClipLoad( IRadSoundClip ** ppClip );
+void SoundNucleusServiceClipLoad( void );
+
+}
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
diff --git a/game/code/sound/soundrenderer/soundplayer.h b/game/code/sound/soundrenderer/soundplayer.h
new file mode 100644
index 0000000..78538d3
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundplayer.h
@@ -0,0 +1,468 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: dasoundplayer.hpp
+//
+// Subsystem: Dark Angel - Sound players
+//
+// Description: Defines the a Dark Angel sound player
+//
+// Revisions:
+// + Created October 16, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _DASOUNDPLAYER_HPP
+#define _DASOUNDPLAYER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <radsound.hpp>
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+struct IRadObjectBTree;
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundClipStreamPlayer;
+class daSoundTuner;
+struct IDaSoundPlayerState;
+struct StreamerResources;
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+class daSoundAllocatedResource;
+
+//=============================================================================
+// Typdefs and enumerations
+//=============================================================================
+
+const float radSoundPitchChangeThreshold = 0.1f;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+class daSoundPlayerBase :
+ public IRefCount,
+ public radLinkedClass< daSoundPlayerBase >,
+ public radRefCount
+{
+ public:
+
+ inline daSoundPlayerBase( ) : radRefCount( 0 ) { }
+ virtual ~daSoundPlayerBase( ) { }
+
+ IMPLEMENT_REFCOUNTED( "daSoundPlayerBase" );
+
+ virtual void ServiceOncePerFrame ( void ) = 0;
+ virtual bool IsCaptured ( void ) = 0;
+ virtual void Pause ( void ) = 0;
+ virtual void Continue ( void ) = 0;
+ virtual void UberContinue( void ) = 0;
+ virtual void Stop ( void ) = 0;
+ virtual void SetPitch( float pitch ) = 0;
+ virtual bool IsPaused( void ) = 0;
+
+ virtual void ChangeTrim( daSoundGroup groupName, float newTrim ) = 0;
+ virtual void ChangeFaderTrim( daSoundGroup groupName, float newTrim ) = 0;
+};
+
+//
+// This contains a Dark Angel player instance.
+//
+class daSoundClipStreamPlayer
+ :
+ public daSoundPlayerBase,
+ public IRadSoundStitchCallback
+
+{
+public:
+
+ //
+ // Constructor and destructor
+ //
+ daSoundClipStreamPlayer( void );
+ virtual ~daSoundClipStreamPlayer ( void );
+
+ // daSoundPlayerBase
+
+ virtual void ServiceOncePerFrame ( void );
+ virtual bool IsCaptured ( void );
+ virtual void Pause ( void );
+ virtual void Continue ( void );
+ virtual void UberContinue( void );
+ virtual void Stop ( void );
+ virtual void SetPitch( float pitch );
+
+ virtual void ChangeTrim( daSoundGroup groupName, float newTrim );
+ virtual void ChangeFaderTrim( daSoundGroup groupName, float newTrim );
+
+ bool IsPaused( void );
+
+ //
+ // Sound player states
+ //
+
+ enum State {
+ State_DeCued,
+ State_Cueing,
+ State_Cued,
+ State_CuedPlay,
+ State_Playing,
+ State_Stopping,
+ State_Done
+ };
+
+ //
+ // Get and state this player's state
+ //
+
+ inline State GetState ( void );
+
+ //
+ // Initialize with some form of player
+ //
+ void InitializeAsClipPlayer( void );
+ void InitializeAsStreamPlayer( void );
+
+ void Capture(
+ IDaSoundResource* pResource,
+ bool isPositional );
+
+ inline IRadSoundHalPositionalGroup* GetPositionalGroup( void );
+
+ void Play( void );
+ void UnCapture ( void );
+
+ inline void SetPositionAndVelocity(
+ const radSoundVector * pPosition,
+ const radSoundVector * pVelocity );
+
+ inline void SetMinMaxDistance( float min, float max );
+
+ inline void SetExternalTrim( float newTrim );
+ inline void SetGroupTrim( float newTrim );
+ inline void SetFaderGroupTrim( float newTrim );
+ inline void SetMasterTrim( float newTrim );
+
+ inline IDaSoundResource::Type GetPlayerType ( void );
+ daSoundGroup GetSoundGroup ( void );
+
+ void RegisterSoundPlayerStateCallback
+ (
+ IDaSoundPlayerState* pCallback,
+ void* pUserData
+ );
+ void UnregisterSoundPlayerStateCallback
+ (
+ IDaSoundPlayerState* pCallback,
+ void* pUserData
+ );
+
+ unsigned int GetPlaybackTimeInSamples ( void );
+
+ void OnStitch( IRadSoundHalDataSource **, unsigned int frameCount, void * pUserData );
+
+ const void GetFileName( char * pBuf, unsigned int max );
+
+private:
+
+ enum CueingState
+ {
+ CueingState_Null,
+ CueingState_Resource,
+ CueingState_Player,
+ CueingState_Cued
+ };
+
+ inline void CalculateCurrentTrim( void );
+ inline void CalculateCurrentPitch( void );
+ void HookUpAndCuePlayer( void );
+
+ void UpdateClip( void );
+ void UpdateStream( void );
+
+ //
+ // Get the randomized trim and pitch settings based on a
+ // min/max variance of the current resource
+ //
+ inline void CalculateNewVaryingTrim ( void );
+ inline void CalculateNewVaryingPitch ( void );
+
+ //
+ // Trim values
+ //
+ float m_Trim;
+ float m_GroupTrim;
+ float m_FaderGroupTrim;
+ float m_MasterTrim;
+ float m_StoppingTrim;
+ float m_VaryingTrim;
+ float m_CurrentTrim; // floating target
+
+ float m_VaryingPitch;
+ float m_Pitch;
+ float m_CurrentPitch; // floating target
+
+ //
+ // Sound player state
+ //
+ State m_State;
+ CueingState m_CueingState;
+
+ //
+ // Hold a capture counter
+ //
+ unsigned int m_CaptureCount;
+
+ //
+ // Hold a pause counter
+ //
+ unsigned int m_PauseCount;
+
+ //
+ // Store the allocated and normal resource
+ //
+ daSoundAllocatedResource* m_pAllocatedResource;
+ unsigned int m_AllocResInstanceID;
+ IDaSoundResource* m_pResource;
+
+ //
+ // The positional group that this player uses
+ //
+ IRadSoundHalPositionalGroup * m_pPositionalGroup;
+ bool m_IsPositional;
+
+ //
+ // Currently, only one callback is allowed at a time
+ //
+ IDaSoundPlayerState* m_pStateChangeCallback;
+ void* m_pStateChangeCallbackUserData;
+
+ //
+ // Store the various types of players based on the connected resource
+ //
+ union
+ {
+ struct
+ {
+ IRadSoundClipPlayer* m_pClipPlayer;
+ } m_ClipInfo;
+
+ struct
+ {
+ StreamerResources* m_pResources;
+ IRadSoundRsdFileDataSource* m_pRsdFileDataSource;
+ } m_StreamInfo;
+ };
+
+ IDaSoundResource::Type m_Type;
+};
+
+
+inline IDaSoundResource::Type daSoundClipStreamPlayer::GetPlayerType( void )
+{
+ return m_Type;
+}
+
+inline void daSoundClipStreamPlayer::SetExternalTrim( float newTrim )
+{
+ radSoundVerifyAnalogVolume( newTrim );
+
+ m_Trim = newTrim;
+
+}
+
+inline void daSoundClipStreamPlayer::SetGroupTrim( float newTrim )
+{
+ radSoundVerifyAnalogVolume( newTrim );
+
+ m_GroupTrim = newTrim;
+
+}
+
+inline void daSoundClipStreamPlayer::SetFaderGroupTrim( float newTrim )
+{
+ radSoundVerifyAnalogVolume( newTrim );
+
+ m_FaderGroupTrim = newTrim;
+}
+
+inline void daSoundClipStreamPlayer::SetMasterTrim( float newTrim )
+{
+ radSoundVerifyAnalogVolume( newTrim );
+
+ m_MasterTrim = newTrim;
+}
+
+inline void daSoundClipStreamPlayer::CalculateCurrentTrim( void)
+{
+ float oldTrim = m_CurrentTrim;
+
+ float newTrim =
+ m_VaryingTrim *
+ m_StoppingTrim *
+ m_Trim *
+ m_GroupTrim *
+ m_FaderGroupTrim *
+ m_MasterTrim;
+
+ if ( State_Playing == m_State || State_Stopping == m_State )
+ {
+ if ( newTrim >= oldTrim )
+ {
+ float dif = newTrim - oldTrim;
+
+ if ( dif >= radSoundVolumeChangeThreshold )
+ {
+ newTrim = oldTrim + radSoundVolumeChangeThreshold;
+ }
+ }
+ else
+ {
+ float dif = oldTrim - newTrim;
+
+ if ( dif >= radSoundVolumeChangeThreshold )
+ {
+ newTrim = oldTrim - radSoundVolumeChangeThreshold;
+ }
+ }
+ }
+
+ m_CurrentTrim = newTrim;
+
+ radSoundVerifyAnalogVolume( m_CurrentTrim );
+}
+
+inline void daSoundClipStreamPlayer::CalculateCurrentPitch( void )
+{
+ float oldPitch = m_CurrentPitch;
+
+ float newPitch = m_VaryingPitch * m_Pitch;
+
+ if ( m_State == State_Playing || m_State == State_Stopping )
+ {
+ if ( newPitch > oldPitch )
+ {
+ float dif = newPitch - oldPitch;
+
+ if( dif > radSoundPitchChangeThreshold )
+ {
+ newPitch = oldPitch + radSoundVolumeChangeThreshold;
+ }
+ }
+ else
+ {
+ float dif = oldPitch - newPitch;
+
+ if( dif > radSoundPitchChangeThreshold )
+ {
+ newPitch = oldPitch - radSoundVolumeChangeThreshold;
+ }
+ }
+ }
+
+ m_CurrentPitch = newPitch;
+
+ radSoundVerifyAnalogPitch( m_CurrentPitch );
+}
+
+inline void daSoundClipStreamPlayer::SetPitch( float pitch )
+{
+ if ( pitch <= 0.0f )
+ {
+ rDebugPrintf( "AUDIO: Error, pitch set to: [%f]\n", pitch );
+
+ pitch = 0.0f;
+ }
+
+ // radSoundVerifyAnalogPitch( pitch );
+
+ m_Pitch = pitch;
+}
+
+inline void daSoundClipStreamPlayer::CalculateNewVaryingTrim( void )
+{
+ float minTrim;
+ float maxTrim;
+
+ m_pResource->GetTrimRange( &minTrim, &maxTrim );
+
+ m_VaryingTrim = ::radSoundRandMinMax( minTrim, maxTrim );
+
+ radSoundVerifyAnalogVolume( m_VaryingTrim );
+}
+
+
+inline void daSoundClipStreamPlayer::CalculateNewVaryingPitch( void )
+{
+ float minPitch;
+ float maxPitch;
+
+ m_pResource->GetPitchRange( &minPitch, &maxPitch );
+
+ m_VaryingPitch = ::radSoundRandMinMax( minPitch, maxPitch );
+
+ radSoundVerifyAnalogPitch( m_VaryingPitch );
+}
+
+inline daSoundClipStreamPlayer::State daSoundClipStreamPlayer::GetState( void )
+{
+ return m_State;
+}
+
+inline void daSoundClipStreamPlayer::SetPositionAndVelocity(
+ const radSoundVector * pPosition,
+ const radSoundVector * pVelocity )
+{
+ m_pPositionalGroup->SetPosition( (radSoundVector*) pPosition );
+ m_pPositionalGroup->SetVelocity( (radSoundVector*) pVelocity );
+}
+
+inline void daSoundClipStreamPlayer::SetMinMaxDistance( float min, float max )
+{
+ m_pPositionalGroup->SetMinMaxDistance( min, max );
+}
+
+inline bool daSoundClipStreamPlayer::IsPaused( void )
+{
+ return m_PauseCount != 0;
+}
+
+
+inline IRadSoundHalPositionalGroup * daSoundClipStreamPlayer::GetPositionalGroup( void )
+{
+ if ( m_IsPositional )
+ {
+ return m_pPositionalGroup;
+ }
+
+ return NULL;
+}
+
+
+} // Sound Namespace
+#endif //_DASOUNDPLAYER_HPP
+
diff --git a/game/code/sound/soundrenderer/soundrenderingmanager.cpp b/game/code/sound/soundrenderer/soundrenderingmanager.cpp
new file mode 100644
index 0000000..167e871
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundrenderingmanager.cpp
@@ -0,0 +1,1545 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundrenderingmanager.cpp
+//
+// Subsystem: Dark Angel - Sound Manager System
+//
+// Description: Implementation of the sound manager
+//
+// Revisions:
+// + Created October 2, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radfile.hpp>
+
+
+#include <radmusic/radmusic.hpp>
+#include <radsound.hpp>
+
+#include <radobjectlist.hpp>
+#include <radscript.hpp>
+#include <radtypeinfo.hpp>
+#include <radtypeinfoutil.hpp>
+#include <radfactory.hpp>
+
+#include <memory/srrmemory.h>
+#include <loading/loadingmanager.h>
+#include <loading/soundfilehandler.h>
+
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundresource.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/playermanager.h>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <sound/soundrenderer/soundconstants.h>
+#include <sound/soundclusternameenum.h>
+#include <sound/soundmanager.h>
+#include <sound/soundrenderer/soundnucleus.hpp>
+#include <sound/dialog/dialogcoordinator.h>
+#include <radobjectbtree.hpp>
+#include <radmemorymonitor.hpp>
+
+#include <pddi/pddi.hpp>
+#include <p3d/utility.hpp>
+#include <p3d/p3dtypes.hpp>
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+//#define AUDIO_FILE_PERFORMANCE_LOG
+//#define AUDIO_FILE_PERFORMANCE_SPEW
+
+bool gDaSoundStats = false;
+bool gTuneSound = false;
+
+namespace Sound {
+
+const short MAX_BTREE_NODES = 5100;
+
+radObjectBTreeNode* gpBTreeNodePool = 0;
+
+//=============================================================================
+// Debug Information
+//=============================================================================
+
+//
+// Use this if you want to debug the sound tuner
+//
+#ifndef FINAL
+#ifndef NDEBUG
+
+// This is the type of debug information to output
+#define DASOUNDMANAGER_OUTPUTDEBUGINFO
+#ifdef DASOUNDMANAGER_OUTPUTDEBUGINFO
+//static DebugInfoType sg_DebugInfoType = DEBUG_RESOURCEINFO;
+#endif //DASOUNDMANAGER_OUTPUTDEBUGINFO
+
+#endif //NDEBUG
+#endif //FINAL
+
+
+//=============================================================================
+// Macros and Defines
+//=============================================================================
+
+//
+// THe sound memory size
+//
+
+//
+// Some directories
+//
+#define SOUND_ROOT_DIR "sound"
+#define SCRIPT_DIR SOUND_ROOT_DIR"\\scripts"
+#define TYPEINFO_DIR SOUND_ROOT_DIR"\\typ"
+
+unsigned int gTotalMicrosecondsWastedParsingScripts = 0;
+
+//=============================================================================
+// Constants
+//=============================================================================
+
+//
+// Custom memory management should not be handled by the sound system!
+//
+radMemoryAllocator DAMEMORY_ALLOC_SOUND = RADMEMORY_ALLOC_DEFAULT;
+
+//
+// The object list page size for the sound objects
+//
+static const unsigned int SoundObjectsListPageSize = 32;
+
+//
+// Flag used for file callback
+//
+static const bool LastScriptTrue = true;
+static const bool LastScriptFalse = false;
+
+//=============================================================================
+// Static Variables
+//=============================================================================
+
+//
+// The sound manager singleton class
+//
+daSoundRenderingManager* daSoundRenderingManager::s_Singleton = NULL;
+
+
+//=============================================================================
+// Local data
+//=============================================================================
+
+//
+// The name of our sound resource namespace
+//
+static const char s_SoundNamespace[ ] = "SoundGlobals";
+
+//
+// The name of our tuning object namespace
+//
+static const char s_TuningNamespace[] = "TuningGlobals";
+
+//
+// Base name for our character namespaces
+//
+static const char s_CharacterNamespace[] = "CharSounds";
+
+//
+// The name of the listener object
+//
+//static const char s_TheListenerName[ ] = "TheListener";
+
+//
+// Dialog cement file names
+//
+#if defined( RAD_XBOX )
+
+static const unsigned int s_NumDialogCementFiles = 3;
+
+static const char s_EnglishDialogue[] = "dialog0?.rcf";
+static const char s_FrenchDialogue[] = "dialogf0?.rcf";
+static const char s_GermanDialogue[] = "dialogg0?.rcf";
+static const char s_SpanishDialogue[] = "dialogs0?.rcf";
+static const char s_ItalianDialogue[] = "dialogi0?.rcf";
+
+#else
+
+static const unsigned int s_NumDialogCementFiles = 1;
+
+static const char s_EnglishDialogue[] = "dialog.rcf";
+static const char s_FrenchDialogue[] = "dialogf.rcf";
+static const char s_GermanDialogue[] = "dialogg.rcf";
+static const char s_SpanishDialogue[] = "dialogs.rcf";
+static const char s_ItalianDialogue[] = "dialogi.rcf";
+
+#endif
+
+//
+// Cement libraries associated with the Dark Angel sound system
+//
+struct DaSoundCementLibraryData
+{
+ const char* m_LibraryIDString;
+ const char* m_Filename;
+ unsigned int m_CacheSize;
+};
+
+//
+// Type info
+//
+struct DaSoundTypeinfoData
+{
+ const char* m_Filename;
+};
+static DaSoundTypeinfoData s_DaSoundTypeInfo =
+{
+ TYPEINFO_DIR"\\srrtypes.typ"
+};
+
+//
+// Radscripts associated wtih the DA sound system
+//
+struct DaSoundScriptData
+{
+ const char* m_Filename;
+};
+
+//
+// IMPORTANT CHANGE: The last script files listed will have its contents go
+// into the tuning namespace, not the sound namespace. This is to ensure
+// that everything in the sound namespace is a soundResourceData object
+// to allow me to search for dialog resources without an illegal downcast
+// (stinky downcasts, hate 'em).
+//
+static DaSoundScriptData s_DaSoundScripts[ ] =
+{
+ // Character sound scripts
+ { "\\Apu.spt" },
+ { "\\Bart.spt" },
+ { "\\Homer.spt" },
+ { "\\Lisa.spt" },
+ { "\\Marge.spt" },
+
+ // Level scripts
+ { "\\suburbs.spt" },
+ { "\\downtown.spt" },
+ { "\\seaside.spt" },
+ { "\\level1.spt" },
+ { "\\level2.spt" },
+ { "\\level3.spt" },
+ { "\\level4.spt" },
+ { "\\level5.spt" },
+ { "\\level6.spt" },
+ { "\\level7.spt" },
+ { "\\minigame.spt" },
+
+ // Sound effect resources
+ { "\\frontend.spt" },
+ { "\\collide.spt" },
+ { "\\carsound.spt" },
+ { "\\World.spt" },
+ { "\\positionalSounds.spt" },
+ { "\\interactive_props.spt" },
+
+ // Dialog
+ { "\\dialog.spt" },
+ { "\\nis.spt" },
+
+ // Cars
+ { "\\bart_v.spt" },
+ { "\\apu_v.spt" },
+ { "\\snake_v.spt" },
+ { "\\homer_v.spt" },
+ { "\\famil_v.spt" },
+ { "\\gramp_v.spt" },
+ { "\\cletu_v.spt" },
+ { "\\wiggu_v.spt" },
+ { "\\empty.spt" },
+ { "\\marge_v.spt" },
+ { "\\empty.spt" },
+ { "\\empty.spt" },
+ { "\\smith_v.spt" },
+ { "\\empty.spt" },
+ { "\\empty.spt" },
+ { "\\empty.spt" },
+ { "\\zombi_v.spt" },
+ { "\\empty.spt" },
+ { "\\empty.spt" },
+ { "\\cVan.spt" },
+ { "\\compactA.spt" },
+ { "\\comic_v.spt" },
+ { "\\skinn_v.spt" },
+ { "\\cCola.spt" },
+ { "\\cSedan.spt" },
+ { "\\cPolice.spt" },
+ { "\\cCellA.spt" },
+ { "\\cCellB.spt" },
+ { "\\cCellC.spt" },
+ { "\\cCellD.spt" },
+ { "\\minivanA_v.spt" },
+ { "\\pickupA.spt" },
+ { "\\taxiA_v.spt" },
+ { "\\sportsA.spt" },
+ { "\\sportsB.spt" },
+ { "\\SUVA.spt" },
+ { "\\wagonA.spt" },
+ { "\\hbike_v.spt" },
+ { "\\burns_v.spt" },
+ { "\\honor_v.spt" },
+ { "\\cArmor.spt" },
+ { "\\cCurator.spt" },
+ { "\\cHears.spt" },
+ { "\\cKlimo.spt" },
+ { "\\cLimo.spt" },
+ { "\\cNerd.spt" },
+ { "\\frink_v.spt" },
+ { "\\cMilk.spt" },
+ { "\\cDonut.spt" },
+ { "\\bbman_v.spt" },
+ { "\\bookb_v.spt" },
+ { "\\carhom_v.spt" },
+ { "\\elect_v.spt" },
+ { "\\fone_v.spt" },
+ { "\\gramR_v.spt" },
+ { "\\moe_v.spt" },
+ { "\\mrplo_v.spt" },
+ { "\\otto_v.spt" },
+ { "\\plowk_v.spt" },
+ { "\\scorp_v.spt" },
+ { "\\willi_v.spt" },
+ { "\\sedanA.spt" },
+ { "\\sedanB.spt" },
+ { "\\cBlbart.spt" },
+ { "\\cCube.spt" },
+ { "\\cDuff.spt" },
+ { "\\cNonup.spt" },
+ { "\\lisa_v.spt" },
+ { "\\krust_v.spt" },
+ { "\\coffin.spt" },
+ { "\\hallo.spt" },
+ { "\\ship.spt" },
+ { "\\witchcar.spt" },
+ { "\\huska.spt" },
+ { "\\atv_v.spt" },
+ { "\\dune_v.spt" },
+ { "\\hype_v.spt" },
+ { "\\knigh_v.spt" },
+ { "\\mono_v.spt" },
+ { "\\oblit_v.spt" },
+ { "\\rocke_v.spt" },
+ { "\\ambul.spt" },
+ { "\\burnsarm.spt" },
+ { "\\fishtruc.spt" },
+ { "\\garbage.spt" },
+ { "\\icecream.spt" },
+ { "\\istruck.spt" },
+ { "\\nuctruck.spt" },
+ { "\\pizza.spt" },
+ { "\\schoolbu.spt" },
+ { "\\votetruc.spt" },
+ { "\\glastruc.spt" },
+ { "\\cfire_v.spt" },
+ { "\\cBone.spt" },
+ { "\\redbrick.spt" },
+
+ // Tuning
+ { "\\car_tune.spt" },
+ { "\\positionalSettings.spt" },
+ { "\\global.spt" }
+};
+
+const unsigned int NumSoundScripts = sizeof( s_DaSoundScripts ) /
+ sizeof( DaSoundScriptData );
+
+const unsigned int NUM_TUNING_SCRIPTS = 3;
+const unsigned int NUM_CHARACTER_SCRIPTS = 5;
+const unsigned int INTERACTIVE_PROPS_SCRIPT_POSITION = 21;
+const unsigned int DIALOGUE_SCRIPT_POSITION = 22;
+const unsigned int NIS_SCRIPT_POSITION = 23;
+
+//
+// Array mapping scripts to sound clusters that their sounds should
+// be loaded/unloaded with.
+//
+// IMPORTANT: this array needs to be maintained to match the scripts
+// in s_DaSoundScripts up to the first car script. After that, we
+// do it programatically (I don't think that's actually a word).
+//
+static SoundClusterName s_ScriptClusters[] =
+{
+ SC_CHAR_APU,
+ SC_CHAR_BART,
+ SC_CHAR_HOMER,
+ SC_CHAR_LISA,
+ SC_CHAR_MARGE,
+ SC_LEVEL_SUBURBS,
+ SC_LEVEL_DOWNTOWN,
+ SC_LEVEL_SEASIDE,
+ SC_LEVEL1,
+ SC_LEVEL2,
+ SC_LEVEL3,
+ SC_LEVEL4,
+ SC_LEVEL5,
+ SC_LEVEL6,
+ SC_LEVEL7,
+ SC_MINIGAME,
+ SC_ALWAYS_LOADED,
+ SC_ALWAYS_LOADED,
+ SC_ALWAYS_LOADED,
+ SC_ALWAYS_LOADED,
+ SC_INGAME,
+ SC_INGAME,
+ SC_NEVER_LOADED,
+ SC_NEVER_LOADED,
+};
+const unsigned int NumClusterNames = sizeof( s_ScriptClusters ) /
+ sizeof( SoundClusterName );
+
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundRenderingManager Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundRenderingManager::daSoundRenderingManager
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundRenderingManager::daSoundRenderingManager( )
+ :
+ radRefCount( 0 ),
+ m_pScript( NULL ),
+ m_IsInitialized( false ),
+ m_pResourceNameSpace( NULL ),
+ m_pTuningNameSpace( NULL ),
+ m_pDynaLoadManager( NULL ),
+ m_pTuner( NULL ),
+ m_pResourceManager( NULL ),
+ m_pPlayerManager( NULL ),
+ m_scriptLoadCount( 0 ),
+ m_currentLanguage( DIALOGUE_LANGUAGE_ENGLISH ),
+ m_languageSelected( false )
+{
+ unsigned int i;
+
+ // Create the singleton
+ rAssert( s_Singleton == NULL );
+ s_Singleton = this;
+
+ for( i = 0; i < NUM_CHARACTER_NAMESPACES; i++ )
+ {
+ m_pCharacterNameSpace[i] = NULL;
+ }
+
+ for( i = 0; i < NUM_SOUND_CEMENT_FILES; i++ )
+ {
+ m_soundCementFileHandles[i] = 0;
+ }
+
+ m_LastPerformanceEventTime = radTimeGetMilliseconds( );
+ ::RadSoundSetFilePerformanceCallback( & daSoundRenderingManager::FilePerformanceEvent );
+
+ radDbgWatchAddBoolean(
+ & gDaSoundStats,
+ "DaSound Stats",
+ "Sound" );
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::~daSoundRenderingManager
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundRenderingManager::~daSoundRenderingManager( )
+{
+
+ radDbgWatchDelete( & gDaSoundStats );
+ ::RadSoundSetFilePerformanceCallback( NULL );
+
+ rAssert( !m_IsInitialized );
+
+ // Clear the singleton
+ s_Singleton = NULL;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetInstance
+//=============================================================================
+// Description: Get the singleton instance of this class
+//
+//-----------------------------------------------------------------------------
+
+daSoundRenderingManager* daSoundRenderingManager::GetInstance( void )
+{
+ return s_Singleton;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::Initialize
+//=============================================================================
+// Description: Initialize the sound manager with the stuff that we don't
+// need to do if we're muted.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManager::Initialize
+(
+ void
+)
+{
+ unsigned int i;
+ char nameBuffer[50];
+ int nameLength;
+
+ //
+ // Create namespaces
+ //
+ m_pResourceNameSpace = ::radNameSpaceCreate( GetThisAllocator( ) );
+ m_pResourceNameSpace->AddRef( );
+ m_pResourceNameSpace->SetName( s_SoundNamespace );
+
+ m_pTuningNameSpace = ::radNameSpaceCreate( GetThisAllocator( ) );
+ m_pTuningNameSpace->AddRef( );
+ m_pTuningNameSpace->SetName( s_TuningNamespace );
+
+ strcpy( nameBuffer, s_CharacterNamespace );
+ nameLength = strlen( s_CharacterNamespace );
+ for( i = 0; i < NUM_CHARACTER_NAMESPACES; i++ )
+ {
+ m_pCharacterNameSpace[i] = ::radNameSpaceCreate( GetThisAllocator() );
+ rAssert( m_pCharacterNameSpace[i] != NULL );
+
+ m_pCharacterNameSpace[i]->AddRef();
+
+ //
+ // Create a unique name
+ //
+ nameBuffer[nameLength] = static_cast<char>( '0' + i );
+ nameBuffer[nameLength+1] = '\0';
+ m_pCharacterNameSpace[i]->SetName( nameBuffer );
+ }
+
+ //
+ // Spawn other elements of the sound system (some of these depend on the namespace)
+ //
+ m_pDynaLoadManager = new ( GetThisAllocator( ) ) daSoundDynaLoadManager( );
+ m_pDynaLoadManager->AddRef( );
+ m_pResourceManager = new ( GetThisAllocator( ) ) daSoundResourceManager( );
+ m_pResourceManager->AddRef( );
+ m_pPlayerManager = new ( GetThisAllocator( ) ) daSoundPlayerManager( );
+ m_pPlayerManager->AddRef( );
+
+ Sound::daSoundTunerCreate ( &m_pTuner, GetThisAllocator( ) );
+
+ m_pPlayerManager->UglyHackPostInitialize( m_pTuner );
+
+ //
+ // Register some factories and some objects. Some of these object use
+ // the spawned systems.
+ //
+ ::radFactoryRegister(
+ "daSoundResourceData",
+ (radFactoryProc*) daSoundResourceManager::CreateResourceData );
+ rAssert( GetSoundNamespace( ) != NULL );
+ rAssert( GetTuningNamespace() != NULL );
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::IsInitialized
+//=============================================================================
+// Description: Use this to pull for the end of initialization
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundRenderingManager::IsInitialized( void )
+{
+ return m_IsInitialized;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::Terminate
+//=============================================================================
+// Description: Terminate the sound manager
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManager::Terminate( void )
+{
+ unsigned int i;
+
+ // Stop all the sounds in the game
+ GetPlayerManager( )->CancelPlayers( );
+
+ // Release the namespaces, must do this before killing resource manager
+ // some of the reference counting is not per-object.
+
+ m_pResourceNameSpace->Release( );
+ m_pTuningNameSpace->Release();
+
+ for( i = 0; i < NUM_CHARACTER_NAMESPACES; i++ )
+ {
+ m_pCharacterNameSpace[i]->Release();
+ }
+
+ // Destroy the sound systems created by the initalize
+ if( IsInitialized( ) )
+ {
+ //
+ // Detach the various systems spawned on creation
+ //
+ if( m_pPlayerManager != NULL )
+ {
+ m_pPlayerManager->Release( );
+ m_pPlayerManager = NULL;
+ }
+ if( m_pResourceManager != NULL )
+ {
+ m_pResourceManager->Release( );
+ m_pResourceManager = NULL;
+ }
+ if( m_pTuner != NULL )
+ {
+ m_pTuner->Release( );
+ m_pTuner = NULL;
+ }
+ if( m_pDynaLoadManager != NULL )
+ {
+ m_pDynaLoadManager->Release( );
+ m_pDynaLoadManager = NULL;
+ }
+
+#ifndef FINAL
+ if ( gTuneSound )
+ {
+ ::radRemoteScriptTerminate( );
+ }
+#endif
+ rAssert( m_pScript == NULL );
+ ::radScriptTerminate( );
+
+ //
+ // Release the cement file
+ //
+ for( i = 0; i < NUM_SOUND_CEMENT_FILES; i++ )
+ {
+ GetLoadingManager()->UnregisterCementLibrary( m_soundCementFileHandles[i] );
+ }
+
+ // Uninitialize
+ m_IsInitialized = false;
+ }
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::Service
+//=============================================================================
+// Description: Service the Dark Angel sound system. This call should be made
+// as often as possible.
+//
+// Parameters: none
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManager::Service( void )
+{
+ //
+ // Service the radsound system
+ //
+ ::radSoundHalSystemGet( )->Service( );
+ SoundNucleusServiceClipLoad( );
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the Dark Angel sound system. This call should be made
+// no more than once per frame or else performance may suffer.
+//
+// Parameters: none
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManager::ServiceOncePerFrame( unsigned int elapsedTime )
+{
+ //
+ // Service the radsound system
+ //
+ ::radSoundHalSystemGet( )->ServiceOncePerFrame( );
+
+ //
+ // Do nothing else until we're fully initialized
+ //
+ if( !IsInitialized( ) )
+ {
+ return;
+ }
+
+ // Service the dynamic loading system
+ if( GetDynaLoadManager( ) != NULL )
+ {
+ GetDynaLoadManager( )->ServiceOncePerFrame( );
+ }
+
+ // Service the tuner
+ if( GetTuner( ) != NULL )
+ {
+ GetTuner( )->ServiceOncePerFrame( elapsedTime );
+ }
+
+ // Service the player manager
+ if( GetPlayerManager( ) != NULL )
+ {
+ GetPlayerManager( )->ServiceOncePerFrame( );
+ }
+}
+
+//=============================================================================
+// daSoundRenderingManager::QueueCementFileRegistration
+//=============================================================================
+// Description: Set up the cement file registration with the loading manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::QueueCementFileRegistration()
+{
+ HeapMgr()->PushHeap (GMA_AUDIO_PERSISTENT);
+
+ //
+ // Queue requests for sound cement file registration
+ //
+ int i = s_NumDialogCementFiles;
+
+ if( !m_languageSelected )
+ {
+ registerDialogueCementFiles( s_EnglishDialogue );
+ m_languageSelected = true;
+ }
+
+#ifdef RAD_XBOX
+ //
+ // Register the music rcfs -- no localization needed.
+ //
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "music00.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "music01.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "music02.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "music03.rcf" );
+#else
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "music.rcf" );
+#endif
+
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "carsound.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "ambience.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "nis.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "soundfx.rcf" );
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( "scripts.rcf" );
+
+ HeapMgr()->PopHeap (GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// daSoundRenderingManager::SwitchDialogueCementFile
+//=============================================================================
+// Description: Switch the current language to the given language.
+//
+// Parameters: language - new language to use
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::SetLanguage( Scrooby::XLLanguage language )
+{
+ unsigned int i;
+ const char* cementFileName = s_EnglishDialogue;
+ DialogueLanguage oldLanguage = m_currentLanguage;
+
+ switch( language )
+ {
+ case Scrooby::XL_ENGLISH:
+ cementFileName = s_EnglishDialogue;
+ m_currentLanguage = DIALOGUE_LANGUAGE_ENGLISH;
+ break;
+
+ //**************************************************************************
+ // TEMPORARY: all dialog is English until we actually get localized dialogue
+ //**************************************************************************
+ case Scrooby::XL_FRENCH:
+ cementFileName = s_FrenchDialogue;
+ m_currentLanguage = DIALOGUE_LANGUAGE_FRENCH;
+ break;
+
+ case Scrooby::XL_GERMAN:
+ cementFileName = s_GermanDialogue;
+ m_currentLanguage = DIALOGUE_LANGUAGE_GERMAN;
+ break;
+
+ case Scrooby::XL_SPANISH:
+ cementFileName = s_SpanishDialogue;
+ m_currentLanguage = DIALOGUE_LANGUAGE_SPANISH;
+ break;
+
+ default:
+ rAssertMsg( false, "Language not supported by sound system" );
+ break;
+ }
+
+ if( m_currentLanguage == oldLanguage )
+ {
+ //
+ // Nothing needs to be done
+ //
+ return;
+ }
+
+ for( i = 0; i < s_NumDialogCementFiles; i++ )
+ {
+ GetLoadingManager()->UnregisterCementLibrary( m_soundCementFileHandles[i] );
+ }
+
+ registerDialogueCementFiles( cementFileName );
+
+ m_languageSelected = true;
+}
+
+//=============================================================================
+// daSoundRenderingManager::QueueRadscriptFileLoads
+//=============================================================================
+// Description: Set up the RadScript file loads with the loading manager
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::QueueRadscriptFileLoads()
+{
+ HeapMgr()->PushHeap (GMA_AUDIO_PERSISTENT);
+
+ unsigned int i;
+ char filename[100];
+ const char* scriptName;
+
+ //
+ // Queue up the RadScript file loading requests
+ //
+ GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, s_DaSoundTypeInfo.m_Filename, GMA_AUDIO_PERSISTENT );
+
+ for( i = 0; i < NumSoundScripts; i++ )
+ {
+ //
+ // Hack!
+ //
+ // Oops. Need to load the correct dialogue script depending on which language has been
+ // selected
+ //
+ if( i == DIALOGUE_SCRIPT_POSITION )
+ {
+ switch( m_currentLanguage )
+ {
+ case DIALOGUE_LANGUAGE_ENGLISH:
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+
+ case DIALOGUE_LANGUAGE_FRENCH:
+ scriptName = "\\dialogfr.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_GERMAN:
+ scriptName = "\\dialogge.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_SPANISH:
+ scriptName = "\\dialogsp.spt";
+ break;
+
+ default:
+ rAssert( false );
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+ }
+ }
+ else if( i == NIS_SCRIPT_POSITION )
+ {
+ switch( m_currentLanguage )
+ {
+ case DIALOGUE_LANGUAGE_ENGLISH:
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+
+ case DIALOGUE_LANGUAGE_FRENCH:
+ scriptName = "\\nisfr.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_GERMAN:
+ scriptName = "\\nisge.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_SPANISH:
+ scriptName = "\\nissp.spt";
+ break;
+
+ default:
+ rAssert( false );
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+ }
+ }
+ else if( i == INTERACTIVE_PROPS_SCRIPT_POSITION )
+ {
+ switch( m_currentLanguage )
+ {
+ case DIALOGUE_LANGUAGE_ENGLISH:
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+
+ case DIALOGUE_LANGUAGE_FRENCH:
+ scriptName = "\\interactive_propsfr.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_GERMAN:
+ scriptName = "\\interactive_propsge.spt";
+ break;
+
+ case DIALOGUE_LANGUAGE_SPANISH:
+ scriptName = "\\interactive_propssp.spt";
+ break;
+
+ default:
+ rAssert( false );
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ break;
+ }
+ }
+ else
+ {
+ scriptName = s_DaSoundScripts[i].m_Filename;
+ }
+ sprintf( filename, "%s%s", SCRIPT_DIR, scriptName );
+ GetLoadingManager()->AddRequest( FILEHANDLER_SOUND, filename, GMA_AUDIO_PERSISTENT );
+ }
+
+ HeapMgr()->PopHeap (GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// daSoundRenderingManager::LoadTypeInfoFile
+//=============================================================================
+// Description: Start the loading of the type info
+//
+// Parameters: filename - name of type info file
+// fileHandler - completion callback object
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::LoadTypeInfoFile( const char* filename, SoundFileHandler* fileHandler )
+{
+ m_soundFileHandler = fileHandler;
+
+ IRadTypeInfoSystem* pTypeInfoSystem = ::radTypeInfoSystemGet( );
+ rAssert( pTypeInfoSystem != NULL );
+ pTypeInfoSystem->AddRef( );
+ pTypeInfoSystem->LoadTypeInfo
+ (
+ gTuneSound ? GMA_AUDIO_PERSISTENT : GMA_TEMP,
+ filename,
+ daSoundRenderingManager::TypeInfoComplete,
+ (void*)false
+ );
+ pTypeInfoSystem->Release( );
+}
+
+//=============================================================================
+// daSoundRenderingManager::LoadScriptFile
+//=============================================================================
+// Description: Start the loading of a RadScript script file
+//
+// Parameters: filename - name of script file
+// fileHandler - completion callback object
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::LoadScriptFile( const char* filename, SoundFileHandler* fileHandler )
+{
+ const bool* lastScript;
+
+ m_soundFileHandler = fileHandler;
+
+ // Create the script object, if it hasn't been done yet
+ if( m_pScript == NULL )
+ {
+ m_pScript = ::radScriptCreateScript
+ (
+ RADMEMORY_ALLOC_TEMP
+ );
+ rAssert( m_pScript != NULL );
+ m_pScript->AddRef( );
+ }
+
+ m_pScript->SetAllocator( GetThisAllocator( ) );
+
+ //
+ // Pass a flag indicating if this is the last script as user info
+ //
+ if( m_scriptLoadCount < NUM_CHARACTER_SCRIPTS )
+ {
+ m_pScript->SetContext( GetCharacterNamespace( m_scriptLoadCount ) );
+ }
+ else if( m_scriptLoadCount >= NumSoundScripts - NUM_TUNING_SCRIPTS )
+ {
+ m_pScript->SetContext( GetTuningNamespace( ) );
+ }
+ else
+ {
+ m_pScript->SetContext( GetSoundNamespace( ) );
+ }
+
+ if( m_scriptLoadCount == NumSoundScripts - 1 )
+ {
+ lastScript = &LastScriptTrue;
+ }
+ else
+ {
+ lastScript = &LastScriptFalse;
+ }
+
+ // Load the script
+ m_pScript->Load
+ (
+ filename,
+ daSoundRenderingManager::ScriptComplete,
+ (void*)lastScript,
+ RADMEMORY_ALLOC_TEMP
+ );
+ }
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetSoundNamespace
+//=============================================================================
+// Description: Get the sound resource namespace
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the sound resource namespace
+//
+//-----------------------------------------------------------------------------
+
+IRadNameSpace* daSoundRenderingManager::GetSoundNamespace( void )
+{
+ return m_pResourceNameSpace;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetTuningNamespace
+//=============================================================================
+// Description: Get the sound tuning namespace
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the sound tuning namespace
+//
+//-----------------------------------------------------------------------------
+
+IRadNameSpace* daSoundRenderingManager::GetTuningNamespace( void )
+{
+ return m_pTuningNameSpace;
+}
+
+//=============================================================================
+// daSoundRenderingManager::GetCharacterNamespace
+//=============================================================================
+// Description: Get the specified character namespace
+//
+// Parameters: index - index into list of namespaces
+//
+// Return: Pointer to the desired namespace
+//
+//=============================================================================
+IRadNameSpace* daSoundRenderingManager::GetCharacterNamespace( unsigned int index )
+{
+ rAssert( index < NUM_CHARACTER_NAMESPACES );
+
+ return( m_pCharacterNameSpace[index] );
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetTheListener
+//=============================================================================
+// Description: Get the listener
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the listener
+//
+//-----------------------------------------------------------------------------
+
+IRadSoundHalListener* daSoundRenderingManager::GetTheListener( void )
+{
+ return ::radSoundHalListenerGet( );
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetDynaLoadManager
+//=============================================================================
+// Description: Get the dynamic loading manager
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the dynamic loading manager
+//
+//-----------------------------------------------------------------------------
+
+daSoundDynaLoadManager* daSoundRenderingManager::GetDynaLoadManager( void )
+{
+ return m_pDynaLoadManager;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetDialogManager
+//=============================================================================
+// Description: Get the dialog manager
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the dialog manager
+//
+//-----------------------------------------------------------------------------
+
+/*IDaSoundDialogManager* daSoundRenderingManager::GetDialogManager( void )
+{
+ return m_pDialogManager;
+}*/
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetTuner
+//=============================================================================
+// Description: Get the tuner
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the tuner
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundTuner* daSoundRenderingManager::GetTuner( void )
+{
+ return m_pTuner;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetObjectDataLibrary
+//=============================================================================
+// Description: Get the object data library
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the object data library
+//
+//-----------------------------------------------------------------------------
+
+/*IDaSoundObjectDataLibrary* daSoundRenderingManager::GetObjectDataLibrary( void )
+{
+ return m_pObjectDataLibrary;
+}*/
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetResourceManager
+//=============================================================================
+// Description: Get the resource manager
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the resource manager
+//
+//-----------------------------------------------------------------------------
+
+daSoundResourceManager* daSoundRenderingManager::GetResourceManager( void )
+{
+ return m_pResourceManager;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::GetPlayerManager
+//=============================================================================
+// Description: Get the player manager
+//
+// Parameters: none
+//
+// Returns: Returns a pointer to the player manager
+//
+//-----------------------------------------------------------------------------
+
+daSoundPlayerManager* daSoundRenderingManager::GetPlayerManager( void )
+{
+ return m_pPlayerManager;
+}
+
+//=============================================================================
+// Function: daSoundRenderingManager::TypeInfoComplete
+//=============================================================================
+// Description: Asynchronous file load complete callback. Redundant, but
+// RadScript requires a static function for callback
+//
+// Parameters: pUserData - some user data to pass on
+//
+// Note: This relies on the sound manager being a singleton
+//
+//-----------------------------------------------------------------------------
+void daSoundRenderingManager::TypeInfoComplete( void* pUserData )
+{
+ rAssert( s_Singleton != NULL );
+ s_Singleton->ProcessTypeInfo( pUserData );
+}
+
+//=============================================================================
+// daSoundRenderingManager::ScriptComplete
+//=============================================================================
+// Description: Asynchronous file load complete callback. Redundant, but
+// RadScript requires a static function for callback
+//
+// Parameters: pUserData - some user data to pass on
+//
+// Note: This relies on the sound manager being a singleton
+//
+//=============================================================================
+void daSoundRenderingManager::ScriptComplete( void* pUserData )
+{
+ rAssert( s_Singleton != NULL );
+ s_Singleton->ProcessScript( pUserData );
+}
+
+//=============================================================================
+// daSoundRenderingManager::SoundObjectCreated
+//=============================================================================
+// Description: RadScript callback function called when an object is created.
+// We use it to register the object for loading/unloading
+//
+// Parameters: objName - name of sound resource to load/unload
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::SoundObjectCreated( const char* objName, IRefCount* obj )
+{
+ bool added;
+ rAssert( NULL != dynamic_cast< daSoundResourceData*>( obj ) );
+ daSoundResourceData* resourceObj = static_cast<daSoundResourceData*>( obj );
+
+ //
+ // We only need to preload clips
+ //
+ if( resourceObj->GetStreaming() == false )
+ {
+ added = GetSoundManager()->GetSoundLoader()->AddResourceToCurrentCluster( objName );
+ rAssert( added );
+ }
+ else
+ {
+ volatile int x = 4;
+ }
+}
+
+//=============================================================================
+// daSoundRenderingManager::ProcessTypeInfo
+//=============================================================================
+// Description: Asynchronous file load complete callback.
+//
+// Parameters: ( void* pUserData )
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::ProcessTypeInfo( void* pUserData )
+{
+ m_soundFileHandler->LoadCompleted();
+}
+
+//=============================================================================
+// daSoundRenderingManager::ScriptComplete
+//=============================================================================
+// Description: Asynchronous script load callback
+//
+// Parameters: pUserData - some user data to pass on
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::ProcessScript( void* pUserData )
+{
+ ScriptObjCreateCallback* callbackPtr = NULL;
+ const bool* lastScript = reinterpret_cast<const bool*>( pUserData );
+
+ rAssert( m_pScript != NULL );
+
+ //
+ // Tell the sound manager which sound cluster we'll associate
+ // with the resources in this script
+ //
+ if( m_scriptLoadCount < NumSoundScripts - NUM_TUNING_SCRIPTS )
+ {
+ callbackPtr = SoundObjectCreated;
+
+ if( m_scriptLoadCount < NumClusterNames )
+ {
+ GetSoundManager()->GetSoundLoader()->SetCurrentCluster( s_ScriptClusters[m_scriptLoadCount] );
+ }
+ else
+ {
+ GetSoundManager()->GetSoundLoader()->SetCurrentCluster( static_cast<SoundClusterName>(SC_CAR_BASE + m_scriptLoadCount - NumClusterNames) );
+ }
+ }
+
+ // Execute script file
+
+ unsigned int start = radTimeGetMicroseconds( );
+ m_pScript->Run( callbackPtr );
+ unsigned int finished = radTimeGetMicroseconds( );
+ unsigned int dif = finished - start;
+
+ gTotalMicrosecondsWastedParsingScripts += dif;
+
+ if ( dif > 1000 )
+ {
+ //rTunePrintf( "\n\nAUDIO: Holy !@#$ script took [%d] ms to parse\n\n", dif / 1000 );
+ }
+
+ m_pScript->UnLoad( );
+
+ if( *lastScript )
+ {
+ rReleasePrintf( "\n\nAUDIO: Wasted [%d] ms of load time parsing scripts\n\n", gTotalMicrosecondsWastedParsingScripts / 1000);
+
+ // Free the script
+ rAssert( m_pScript != NULL );
+ m_pScript->Release( );
+ m_pScript = NULL;
+
+ //
+ // At this point the sound resources should be finalized, lets lock them down
+ // and then intialize some systems.
+ //
+
+ GetTuner( )->Initialize( );
+
+ // Initialize the dialog system
+
+ SoundManager::GetInstance( )->m_dialogCoordinator->Initialize( );
+
+ Sound::daSoundResourceManager::GetInstance( )->SetResourceLockdown( true );
+
+ m_pPlayerManager->Initialize( );
+
+ // We are now fully initialized
+ m_IsInitialized = true;
+
+ if ( ! gTuneSound )
+ {
+ radScriptUnLoadAllTypeInfo( );
+ }
+ }
+
+ ++m_scriptLoadCount;
+
+ m_soundFileHandler->LoadCompleted();
+}
+
+
+//=============================================================================
+// Public Functions
+//=============================================================================
+
+//=============================================================================
+// Function: ::daSoundRenderingManagerCreate
+//=============================================================================
+// Description: Create the sound manager
+//
+// Parameters: allocator - the memory allocator to use
+//
+// Preconditions:
+// In order to manage memory fragmentation issues, and to
+// allow a timely intialization of sound, this command should
+// be executed before any frontend or ingame structures have
+// been created.
+//
+// Postconditions:
+// This will generate any singleton classes related to the Dark
+// Angel sound system. It will register any appropriate
+// cement files to give access to sound, and it will parse
+// any sound scripts so that the sound system will be ready
+// to start recieving sound events.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManagerCreate( radMemoryAllocator allocator )
+{
+ rAssert( daSoundRenderingManager::GetInstance( ) == NULL );
+
+ // Create the sound manager
+ daSoundRenderingManager* pSoundManager = new ( allocator ) daSoundRenderingManager( );
+ rAssert( pSoundManager != NULL );
+ pSoundManager->AddRef( );
+ rAssert( pSoundManager == daSoundRenderingManager::GetInstance( ) );
+
+ rDebugChannelInitialize( GMA_MUSIC );
+ //rDebugChannelEnable( radmusic::debug_channel );
+
+ //
+ // Initialize some usefull systems
+ //
+ ::radScriptInitialize( allocator );
+#ifndef FINAL
+ if( gTuneSound )
+ {
+ ::radRemoteScriptInitialize( allocator );
+ }
+#endif
+
+ gpBTreeNodePool = (radObjectBTreeNode*) radMemoryAlloc(
+ allocator,
+ MAX_BTREE_NODES * sizeof( radObjectBTreeNode ) );
+
+ ::memset( gpBTreeNodePool, 0, MAX_BTREE_NODES * sizeof( radObjectBTreeNode ) );
+
+ radMemoryMonitorIdentifyAllocation( gpBTreeNodePool, "Global BTree Node Pool" );
+
+ radObjectBTree::Initialize( gpBTreeNodePool, MAX_BTREE_NODES );
+ // Initialize
+
+ SoundNucleusInitialize( allocator );
+}
+
+//=============================================================================
+// Function: ::daSoundRenderingManagerGet
+//=============================================================================
+// Description: Get a pointer to the sound manager singleton class
+//
+//-----------------------------------------------------------------------------
+
+daSoundRenderingManager* daSoundRenderingManagerGet( void )
+{
+ rAssert( daSoundRenderingManager::GetInstance( ) != NULL );
+ return
+ (
+ static_cast< daSoundRenderingManager* >( daSoundRenderingManager::GetInstance( ) )
+ );
+}
+
+void daSoundRenderingManager::FilePerformanceEvent(
+ bool start,
+ const char * pFile,
+ unsigned int bytes )
+{
+ daSoundRenderingManager * pThis = daSoundRenderingManager::GetInstance( );
+
+ unsigned int now = radTimeGetMilliseconds( );
+
+ if ( start )
+ {
+ pThis->m_LastPerformanceEventTime = now;
+
+ if ( CommandLineOptions::Get( CLO_AUDIO_LOADING_SPEW ) )
+ {
+ rTunePrintf( "<<START>> Async Loading: (Audio) %s Bytes: 0x%x\n", pFile, bytes );
+ }
+ }
+ else
+ {
+ unsigned int dif = now - pThis->m_LastPerformanceEventTime;
+
+ if ( CommandLineOptions::Get( CLO_AUDIO_LOADING_SPEW ) )
+ {
+ rTunePrintf( "<< END >> Async Loading: (Audio) %s (%d msecs)\n", pFile, dif );
+ }
+ }
+}
+
+void daSoundRenderingManager::Render( void )
+{
+ if ( gDaSoundStats )
+ {
+ m_pPlayerManager->Render( );
+ }
+}
+
+//=============================================================================
+// Function: ::daSoundRenderingManagerTerminate
+//=============================================================================
+// Description: Terminate the sound system
+//
+//-----------------------------------------------------------------------------
+
+void daSoundRenderingManagerTerminate( void )
+{
+ rAssert( daSoundRenderingManager::GetInstance( ) != NULL );
+ daSoundRenderingManager::GetInstance( )->Terminate( );
+ daSoundRenderingManager::GetInstance( )->Release( );
+ rAssert( daSoundRenderingManager::GetInstance( ) == NULL );
+
+ SoundNucleusTerminate( );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// daSoundRenderingManager::registerDialogueCementFiles
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( const char* cementFilename )
+//
+// Return: void
+//
+//=============================================================================
+void daSoundRenderingManager::registerDialogueCementFiles( const char* cementFilename )
+{
+#if defined( RAD_XBOX )
+ char dialogNameBuffer[ 16 ];
+ int i = 0;
+
+ strcpy( dialogNameBuffer, cementFilename );
+ char* numberPosition = strchr( dialogNameBuffer, '?' );
+ for ( unsigned int j = 0; j < s_NumDialogCementFiles; j++ )
+ {
+ *numberPosition = j + '0';
+ m_soundCementFileHandles[i++] = GetLoadingManager()->RegisterCementLibrary( dialogNameBuffer );
+ }
+#else
+ rAssert( s_NumDialogCementFiles == 1 );
+ m_soundCementFileHandles[0] = GetLoadingManager()->RegisterCementLibrary( cementFilename );
+#endif
+}
+
+} // Sound Namespace
+
diff --git a/game/code/sound/soundrenderer/soundrenderingmanager.h b/game/code/sound/soundrenderer/soundrenderingmanager.h
new file mode 100644
index 0000000..a77ac7c
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundrenderingmanager.h
@@ -0,0 +1,187 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundrenderingmanager.hpp
+//
+// Subsystem: Dark Angel - Sound Rendering Manager System
+//
+// Description: Description of the DA sound manager
+//
+// Revisions:
+// + Created October 2, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _SOUNDRENDERINGMANAGER_HPP
+#define _SOUNDRENDERINGMANAGER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radfile.hpp>
+#include <enums.h>
+#include <radsound.hpp>
+#include <radscript.hpp>
+
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/playermanager.h>
+
+//=============================================================================
+// Global namespace forward declarations
+//=============================================================================
+
+
+class SoundFileHandler;
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundRenderingManager;
+class daSoundDynaLoadManager;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+static const unsigned int NUM_CHARACTER_NAMESPACES = 5;
+
+//
+// Language enumeration
+//
+enum DialogueLanguage
+{
+ DIALOGUE_LANGUAGE_ENGLISH,
+ DIALOGUE_LANGUAGE_FRENCH,
+ DIALOGUE_LANGUAGE_GERMAN,
+ DIALOGUE_LANGUAGE_SPANISH
+};
+
+//
+// The sound manger
+//
+class daSoundRenderingManager : public radRefCount
+{
+public:
+ IMPLEMENT_REFCOUNTED( "daSoundManager" );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundRenderingManager( );
+ virtual ~daSoundRenderingManager( );
+
+ //
+ // Get the singleton
+ //
+ static daSoundRenderingManager* GetInstance( void );
+
+ //
+ // Terminate
+ //
+ void Terminate( void );
+
+ void QueueCementFileRegistration();
+ void QueueRadscriptFileLoads();
+ void LoadTypeInfoFile( const char* filename, SoundFileHandler* fileHandler );
+ void LoadScriptFile( const char* filename, SoundFileHandler* fileHandler );
+
+ void SetLanguage( Scrooby::XLLanguage language );
+
+ void ProcessTypeInfo( void* pUserData );
+ void ProcessScript( void* pUserData );
+
+ //
+ // IDaSoundManager
+ //
+ void Initialize( void );
+ bool IsInitialized( void );
+ void Service( void );
+ void ServiceOncePerFrame( unsigned int elapsedTime );
+ void Render( void );
+
+ IRadNameSpace* GetSoundNamespace( void );
+ IRadNameSpace* GetTuningNamespace( void );
+ IRadNameSpace* GetCharacterNamespace( unsigned int index );
+ IRadSoundHalListener* GetTheListener( void );
+
+ daSoundDynaLoadManager* GetDynaLoadManager( void );
+ IDaSoundTuner* GetTuner( void );
+ daSoundResourceManager* GetResourceManager( void );
+ daSoundPlayerManager* GetPlayerManager( void );
+
+protected:
+
+ static void TypeInfoComplete( void* pUserData );
+ static void ScriptComplete( void* pUserData );
+ static void SoundObjectCreated( const char* objName, IRefCount* obj );
+
+private:
+
+ static void FilePerformanceEvent( bool start, const char * pFile, unsigned int bytes );
+
+ void registerDialogueCementFiles( const char* cementFilename );
+
+ // The singleton instance
+ static daSoundRenderingManager* s_Singleton;
+
+ IRadScript* m_pScript;
+ bool m_IsInitialized;
+
+ //
+ // Our namespaces
+ //
+ IRadNameSpace* m_pResourceNameSpace;
+ IRadNameSpace* m_pTuningNameSpace;
+
+ IRadNameSpace* m_pCharacterNameSpace[NUM_CHARACTER_NAMESPACES];
+
+ //
+ // Store the various related systems
+ //
+ daSoundDynaLoadManager* m_pDynaLoadManager;
+ IDaSoundTuner* m_pTuner;
+ daSoundResourceManager* m_pResourceManager;
+ daSoundPlayerManager* m_pPlayerManager;
+
+ //
+ // Loading system callback
+ //
+ SoundFileHandler* m_soundFileHandler;
+
+ //
+ // Cement file handles, in case we want to release them
+ //
+#ifdef RAD_XBOX
+ static const unsigned int NUM_SOUND_CEMENT_FILES = 12;
+#else
+ static const unsigned int NUM_SOUND_CEMENT_FILES = 7;
+#endif
+ unsigned int m_soundCementFileHandles[NUM_SOUND_CEMENT_FILES];
+
+ //
+ // Script loading count, so we can tell which namespace to put stuff in
+ //
+ unsigned int m_scriptLoadCount;
+
+ unsigned int m_LastPerformanceEventTime;
+
+ //
+ // Language
+ //
+ DialogueLanguage m_currentLanguage;
+ bool m_languageSelected;
+};
+
+} // Sound Namespace
+
+#endif //_SOUNDRENDERINGMANAGER_HPP
diff --git a/game/code/sound/soundrenderer/soundresource.cpp b/game/code/sound/soundrenderer/soundresource.cpp
new file mode 100644
index 0000000..ff39f81
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundresource.cpp
@@ -0,0 +1,555 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundresource.cpp
+//
+// Subsystem: Dark Angel - Sound resources
+//
+// Description: Implements sound resources
+//
+// Modification History:
+// + Created October 11, 2001 -- aking
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundplayer.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/playermanager.h>
+
+#include <sound/soundrenderer/soundresourcemanager.h>
+
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundresource.h>
+
+#include <sound/soundmanager.h>
+#include <memory/srrmemory.h>
+
+//=============================================================================
+// Static Variables
+//=============================================================================
+
+//=============================================================================
+// daSoundResourceData Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundResourceData::daSoundResourceData
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+
+inline unsigned char vol_f_to_c( float f )
+{
+ return (unsigned char) radSoundFloatToUInt( f * 255.0f );
+}
+
+inline float vol_c_to_f( unsigned char c )
+{
+ return radSoundUIntToFloat( (unsigned int) c ) / 255.0f;
+}
+
+inline unsigned short pitch_f_to_s( float f )
+{
+ return (unsigned short) radSoundFloatToUInt( f * 6553.0f );
+}
+
+inline float pitch_s_to_f( unsigned short c )
+{
+ return radSoundUIntToFloat( (unsigned short) c ) / 6553.0f;
+}
+
+const int FLAG_LOOPING = 1 << 0;
+const int FLAG_STREAMING = 1 << 1;
+
+daSoundResourceData::daSoundResourceData( )
+{
+ m_NumFiles = 0;
+
+ m_MinTrim = vol_f_to_c( 1.0f );
+ m_MaxTrim = vol_f_to_c( 1.0f );
+ m_MinPitch = pitch_f_to_s( 1.0f );
+ m_MaxPitch = pitch_f_to_s( 1.0f );
+
+ m_SoundGroup = Sound::MASTER;
+ m_CaptureCount = 0;
+
+ m_Flags = 0;
+
+ m_pFileIds = 0;
+}
+
+//=============================================================================
+// Function: daSoundResourceData::~daSoundResourceData
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundResourceData::~daSoundResourceData( )
+{
+
+}
+
+//=============================================================================
+// Function: daSoundResourceData::AddFilename
+//=============================================================================
+// Description: Add a file to this resource
+//
+// Parameters: newFileName - the new file name
+// trim - the trim for this file
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::AddFilename
+(
+ const char* newFileName,
+ float trim
+)
+{
+ rAssert( false == Sound::daSoundResourceManager::GetInstance( )->GetResourceLockdown( ) );
+
+ // very lazy indeed.
+
+ if ( m_pFileIds == 0 )
+ {
+ m_pFileIds = (FileId*) radMemoryAlloc( GMA_DEFAULT, sizeof( FileId ) * DASound_MaxNumSoundResourceFiles );
+ }
+
+ rAssert( Sound::daSoundResourceManager::GetInstance( ) != NULL );
+ rAssert( m_NumFiles < DASound_MaxNumSoundResourceFiles );
+
+ m_pFileIds[ m_NumFiles ].m_pName = (char*) radMemoryAlloc( GMA_DEFAULT, strlen( newFileName ) + 1 );
+ strcpy( m_pFileIds[ m_NumFiles ].m_pName, newFileName );
+ m_NumFiles++;
+}
+
+
+//=============================================================================
+// Function: daSoundResourceData::GetFilenameAt
+//=============================================================================
+// Description: Get the resource file at the given index
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::GetFileNameAt( unsigned int index, char* buffer, unsigned int max )
+{
+ rTuneAssert( false == Sound::daSoundResourceManager::GetInstance( )->GetResourceLockdown( ) );
+ rTuneAssert( index < m_NumFiles );
+
+ strcpy( buffer, m_pFileIds[ index ].m_pName );
+}
+
+void daSoundResourceData::GetFileKeyAt( unsigned int index, char* buffer, unsigned int max )
+{
+ rTuneAssert( index < m_NumFiles );
+ KeyToStringKey32( buffer, m_pFileIds[ index ].m_Key );
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetPitchRange
+//=============================================================================
+// Description: Set the pitch range for this resource
+//
+// Parameters: minPitch - the minimum pitch value
+// maxPitch - the maximum pitch value
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetPitchRange
+(
+ Sound::daPitchValue minPitch,
+ Sound::daPitchValue maxPitch
+)
+{
+ m_MinPitch = pitch_f_to_s( minPitch );
+ m_MaxPitch = pitch_f_to_s( maxPitch );
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetPitchRange
+//=============================================================================
+// Description: Get the pitch range for this resource
+//
+// Parameters: *MinPitch - (out )the minimum pitch value
+// *MaxPitch - (out) the maximum pitch value
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::GetPitchRange
+(
+ Sound::daPitchValue* pMinPitch,
+ Sound::daPitchValue* pMaxPitch
+)
+{
+ if( pMinPitch != NULL )
+ {
+ *pMinPitch = pitch_s_to_f( m_MinPitch );
+ }
+ if( pMaxPitch != NULL )
+ {
+ *pMaxPitch = pitch_s_to_f( m_MaxPitch );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetTrimRange
+//=============================================================================
+// Description: Set the trim range for this resource
+//
+// Parameters: minTrim - the minimum trim value
+// maxTrim - the maximum trim value
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetTrimRange
+(
+ float minTrim,
+ float maxTrim
+)
+{
+ m_MinTrim = vol_f_to_c( minTrim );
+ m_MaxTrim = vol_f_to_c( maxTrim );
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetTrim
+//=============================================================================
+// Description: Set the trim for this resource
+//
+// Parameters: trim - the trim value
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetTrim
+(
+ float trim
+)
+{
+ m_MinTrim = vol_f_to_c( trim );
+ m_MaxTrim = vol_f_to_c( trim );
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetTrimRange
+//=============================================================================
+// Description: Get the trim range for this resource
+//
+// Parameters: *MinTrim - (out )the minimum trim value
+// *MaxTrim - (out) the maximum trim value
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::GetTrimRange
+(
+ float* pMinTrim,
+ float* pMaxTrim
+)
+{
+ if( pMinTrim != NULL )
+ {
+ *pMinTrim = vol_c_to_f( m_MinTrim );
+ }
+ if( pMaxTrim != NULL )
+ {
+ *pMaxTrim = vol_c_to_f( m_MaxTrim );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetStreaming
+//=============================================================================
+// Description: Set this as a streaming resource
+//
+// Parameters: streaming - should streaming be on or off
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetStreaming( bool streaming )
+{
+ if( streaming )
+ {
+ m_Flags |= FLAG_STREAMING;
+ }
+ else
+ {
+ m_Flags &= ~FLAG_STREAMING;
+ }
+
+ if( IsCaptured( ) )
+ {
+ rReleaseString
+ (
+ "Streaming will not immediately "
+ "affect a captured resource\n"
+ );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetStreaming
+//=============================================================================
+// Description: Get whether or not this is a streaming resource
+//
+// Parameters: none
+//
+// Returns: Returns true if this resource streams, otherwise false
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundResourceData::GetStreaming( void )
+{
+ return ( m_Flags & FLAG_STREAMING ) != 0;
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetLooping
+//=============================================================================
+// Description: Set this as a looping resource
+//
+// Parameters: looping - should looping be on or off
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetLooping( bool looping )
+{
+ if( looping )
+ {
+ m_Flags |= FLAG_LOOPING;
+ }
+ else
+ {
+ m_Flags &= ~FLAG_LOOPING;
+ }
+
+ if( IsCaptured( ) )
+ {
+ rReleaseString
+ (
+ "Looping will not immediately "
+ "affect a captured resource\n"
+ );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetLooping
+//=============================================================================
+// Description: Get whether or not this is a looping resource
+//
+// Parameters: none
+//
+// Returns: Returns true if this resource loops, otherwise false
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundResourceData::GetLooping( void )
+{
+ return ( m_Flags & FLAG_LOOPING ) != 0;
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetType
+//=============================================================================
+// Description: Find out what kind of resource this is
+//
+// Parameters: none
+//
+// Returns: Returns the type of resource
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundResource::Type daSoundResourceData::GetType
+(
+ void
+)
+{
+ IDaSoundResource::Type resourceType = UNKNOWN;
+
+ if( GetStreaming( ) )
+ {
+ resourceType = STREAM;
+ }
+ else
+ {
+ resourceType = CLIP;
+ }
+
+ return resourceType;
+}
+
+//=============================================================================
+// Function: daSoundResourceData::SetSoundGroup
+//=============================================================================
+// Description: Set the sound group that this resource belongs to
+//
+// Parameters: soundGroup - the sound group to associate with this resource
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::SetSoundGroup
+(
+ Sound::daSoundGroup soundGroup
+)
+{
+ m_SoundGroup = soundGroup;
+}
+
+//=============================================================================
+// Function: daSoundResourceData::GetSoundGroup
+//=============================================================================
+// Description: Get the sound group that this resource belongs to
+//
+// Parameters: none
+//
+// Returns: Returns the sound group that this resource belongs to.
+//
+//-----------------------------------------------------------------------------
+
+Sound::daSoundGroup daSoundResourceData::GetSoundGroup( void )
+{
+ return static_cast<Sound::daSoundGroup>(m_SoundGroup);
+}
+
+//=============================================================================
+// Function: daSoundResourceData::CaptureResource
+//=============================================================================
+// Description: Capture this resource
+//
+// Parameters: none
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::CaptureResource( void )
+{
+ rAssert( Sound::daSoundResourceManager::GetInstance( ) != NULL );
+ bool wasCaptured = IsCaptured( );
+ ++m_CaptureCount;
+ if( !wasCaptured )
+ {
+ // Inform the resource manager
+ Sound::daSoundResourceManager::GetInstance( )->
+ AllocateResource( this );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::IsCaptured
+//=============================================================================
+// Description: Is this resource captured?
+//
+// Parameters: none
+//
+// Returns: Returns true if the resource is captured, otherwise false.
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundResourceData::IsCaptured( void )
+{
+ return( m_CaptureCount > 0 );
+}
+
+//=============================================================================
+// Function: daSoundResourceData::ReleaseResource
+//=============================================================================
+// Description: Release this resource
+//
+// Parameters: none
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::ReleaseResource( void )
+{
+ rAssertMsg( m_CaptureCount > 0, "Cannot release uncaptured resource" );
+ rAssert( Sound::daSoundResourceManager::GetInstance( ) != NULL );
+
+ --m_CaptureCount;
+ if( m_CaptureCount == 0 )
+ {
+ // Inform the resource manager
+ Sound::daSoundResourceManager::GetInstance( )->
+ DeallocateResource( this );
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceData::ReleaseResource
+//=============================================================================
+// Description: Plays this resource
+//
+// Notes: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// THIS IS FOR COMPOSERS ONLY. DO NOT USE IT.
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceData::Play( void )
+{
+ if( Sound::daSoundRenderingManagerGet( )->GetResourceManager( )->GetResourceLockdown( ) )
+ {
+ // Play it
+ // DO NOT USE THIS COMMAND IF YOU ARE NOT IN RADTUNER / SOUNDTUNER / etc.
+ Sound::daSoundClipStreamPlayer* pPlayer = NULL;
+ Sound::daSoundRenderingManagerGet( )->GetPlayerManager( )->CaptureFreePlayer
+ (
+ &pPlayer,
+ this,
+ false );
+
+ if( pPlayer != NULL )
+ {
+ pPlayer->Play( );
+ }
+ }
+ else
+ {
+ // You shouldn't have left play commands in the composer script
+ rDebugString( "Can't play sounds before resources are locked down.\n" );
+ }
+}
+
+//=============================================================================
+// Public functions
+//=============================================================================
+
+void daSoundResourceData::AddRef( void )
+{
+ //Sound::daSoundResourceManager::GetInstance( )->AddRef( );
+}
+
+void daSoundResourceData::Release( void )
+{
+ //Sound::daSoundResourceManager::GetInstance( )->Release( );
+}
+
+
+
diff --git a/game/code/sound/soundrenderer/soundresource.h b/game/code/sound/soundrenderer/soundresource.h
new file mode 100644
index 0000000..30abb0f
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundresource.h
@@ -0,0 +1,152 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundresource.hpp
+//
+// Subsystem: Dark Angel - Sound Resources
+//
+// Description: Defines sound resource
+//
+// Modification History:
+// + Created October 11, 2001 -- aking
+//
+//=============================================================================
+
+#ifndef _SOUNDRESOURCE_HPP
+#define _SOUNDRESOURCE_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/idasoundresource.h>
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundResourceData;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+//
+// This contains the type of resource.
+//
+class daSoundResourceData
+ :
+ public IDaSoundResource
+{
+public:
+
+ virtual void AddRef( void );
+ virtual void Release( void );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundResourceData( );
+ virtual ~daSoundResourceData( );
+
+ //
+ // IDaSoundResourceData and IDaSoundResource
+ //
+ virtual void AddFilename
+ (
+ const char* newFileName,
+ float trim
+ );
+
+ inline virtual unsigned int GetNumFiles( void );
+
+ virtual void GetFileNameAt( unsigned int index, char* buffer, unsigned int max );
+ virtual void GetFileKeyAt( unsigned int index, char * buffer, unsigned int max );
+
+ virtual void SetPitchRange
+ (
+ float minPitch,
+ float maxPitch
+ );
+ virtual void GetPitchRange
+ (
+ float* pMinPitch,
+ float* pMaxPitch
+ );
+
+ virtual void SetTrimRange
+ (
+ float minTrim,
+ float maxTrim
+ );
+ virtual void GetTrimRange
+ (
+ float* pMinTrim,
+ float* pMaxTrim
+ );
+
+ virtual void SetTrim( float trim );
+
+ virtual void SetStreaming( bool streaming );
+ virtual bool GetStreaming( void );
+
+ virtual void SetLooping( bool looping );
+ virtual bool GetLooping( void );
+
+ virtual Type GetType( void );
+ virtual void SetSoundGroup( Sound::daSoundGroup soundGroup );
+ virtual Sound::daSoundGroup GetSoundGroup( void );
+
+ virtual void CaptureResource( void );
+ virtual bool IsCaptured( void );
+ virtual void ReleaseResource( void );
+
+ // COMPOSERS ONLY!!
+ virtual void Play( void );
+
+ //
+ // The pitch variation
+ //
+ short m_MinPitch;
+ short m_MaxPitch;
+
+ //
+ // The sound files for this resource
+ //
+
+ union FileId {
+ char * m_pName;
+ radKey32 m_Key;
+ };
+
+ FileId * m_pFileIds;
+
+
+ //
+ // The trim variation
+ //
+ unsigned char m_MinTrim;
+ unsigned char m_MaxTrim;
+
+ unsigned char m_Flags;
+
+ unsigned char m_NumFiles;
+
+ //
+ // Hold a capture counter
+ //
+ unsigned char m_CaptureCount;
+ unsigned char m_SoundGroup;
+};
+
+inline unsigned int daSoundResourceData::GetNumFiles( void )
+{
+ return m_NumFiles;
+}
+
+#endif //_SOUNDRESOURCE_HPP
+
diff --git a/game/code/sound/soundrenderer/soundresourcemanager.cpp b/game/code/sound/soundrenderer/soundresourcemanager.cpp
new file mode 100644
index 0000000..5fdc5f6
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundresourcemanager.cpp
@@ -0,0 +1,527 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundresourcemanager.cpp
+//
+// Subsystem: Dark Angel - Sound Resource Manager
+//
+// Description: Implementation of the sound resource manager
+//
+// Revisions:
+// + Created October 11, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radkey.hpp>
+#include <radobjectbtree.hpp>
+#include <radnamespace.hpp>
+#include <radsound.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/soundresource.h>
+#include <sound/soundrenderer/soundallocatedresource.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+
+#include <memory/srrmemory.h>
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Static Variables
+//=============================================================================
+
+daSoundResourceManager* daSoundResourceManager::s_pSingleton = NULL;
+
+//=============================================================================
+// Constants
+//=============================================================================
+
+//
+// The maximum number of sound resource files (not the resources, but the
+// the actual files)
+//
+const unsigned int MaxNumResourceFiles = 512;
+
+#if defined( RAD_XBOX ) || defined( RAD_WIN32 )
+ const IRadSoundHalAudioFormat::Encoding DEFAULT_ENCODING = IRadSoundHalAudioFormat::PCM;
+#elif defined RAD_PS2
+ const IRadSoundHalAudioFormat::Encoding DEFAULT_ENCODING = IRadSoundHalAudioFormat::VAG;
+#elif defined RAD_GAMECUBE
+ const IRadSoundHalAudioFormat::Encoding DEFAULT_ENCODING = IRadSoundHalAudioFormat::PCM_BIGENDIAN;
+#else
+ Uh oh.
+#endif
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundResourceManager Implementation
+//=============================================================================
+
+
+//=============================================================================
+// Function: daSoundResourceManager::daSoundResourceManager
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundResourceManager::daSoundResourceManager( )
+ :
+ radRefCount( 0 ),
+ m_pSoundNamespace( NULL ),
+ m_ResourceLockdown( false ),
+ m_secondaryNamespace( NULL )
+
+{
+ m_pFileIdMemory = 0;
+
+ m_NumResourceDatas = 0;
+
+ // Create the singleton
+ rAssert( s_pSingleton == NULL );
+ s_pSingleton = this;
+
+ // Remember the sound namespace
+ m_pSoundNamespace = Sound::daSoundRenderingManagerGet( )->GetSoundNamespace( );
+ if( m_pSoundNamespace != NULL )
+ {
+ m_pSoundNamespace->AddRef( );
+ }
+
+ m_xIOL_AllocatedResources = new ( GetThisAllocator( )) radObjectBTree( );
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::~daSoundResourceManager
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundResourceManager::~daSoundResourceManager( )
+{
+ // Release the allocated sound resources
+ m_xIOL_AllocatedResources = NULL;
+
+ // Release the sound namespace
+ if( m_pSoundNamespace != NULL )
+ {
+ m_pSoundNamespace->Release( );
+ m_pSoundNamespace = NULL;
+ }
+
+ // Remove the singleton
+ rAssert( s_pSingleton != NULL );
+ s_pSingleton = NULL;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::AllocateResource
+//=============================================================================
+// Description: Allocate a resource
+//
+// Parameters: pResource - the resource to allocate
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceManager::AllocateResource
+(
+ IDaSoundResource* pResource
+)
+{
+ rAssert( pResource != NULL );
+
+ //
+ // Allocate this resource
+ //
+ radKey32 soundKey = (radKey32) pResource;
+
+ // Find out if it already exists...
+ daSoundAllocatedResource* pAllocatedResource =
+ FindAllocatedResource( pResource );
+ if( pAllocatedResource == NULL )
+ {
+ pAllocatedResource = new ( GetThisAllocator( ) ) daSoundAllocatedResource;
+ pAllocatedResource->AddRef( );
+ pAllocatedResource->Initialize( pResource );
+
+ // Add it to our allocated resource manager
+ m_xIOL_AllocatedResources->AddObject (
+ soundKey,
+ pAllocatedResource
+ );
+
+ // Release our version
+ pAllocatedResource->Release( );
+ }
+
+ rAssert( pAllocatedResource != NULL );
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::DeallocateResource
+//=============================================================================
+// Description: Allocate a resource
+//
+// Parameters: pResource - the resource to allocate
+//
+//-----------------------------------------------------------------------------
+
+void daSoundResourceManager::DeallocateResource
+(
+ IDaSoundResource* pResource
+)
+{
+ rAssert( pResource != NULL );
+
+ //
+ // Deallocate the resource
+ //
+ radKey32 soundKey = (radKey32) pResource;
+
+ bool result = m_xIOL_AllocatedResources->RemoveObject( soundKey );
+ rAssertMsg( result, "Resource deallocated prematurely?" );
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::FindResource
+//=============================================================================
+// Description: Find a resource.
+//
+// Parameters: resourceName - the name of the resource to find
+//
+// Returns: Returns a pointer to the appropriate resource or NULL if none
+// found.
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundResource* daSoundResourceManager::FindResource
+(
+ daResourceName resourceName
+)
+{
+ IDaSoundResource* pResource;
+
+ pResource = reinterpret_cast< IDaSoundResource* >(
+ m_pSoundNamespace->GetInstance( resourceName ) );
+
+ if( ( pResource == NULL ) && ( m_secondaryNamespace != NULL ) )
+ {
+ // Search secondary namespace
+ pResource = reinterpret_cast< IDaSoundResource* >
+ (
+ m_secondaryNamespace->GetInstance( resourceName )
+ );
+ }
+
+ return pResource;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::FindResource
+//=============================================================================
+// Description: Find a resource by its key.
+//
+// Parameters: resourceKey - the key for the resource to find
+//
+// Returns: Returns a pointer to the appropriate resource or NULL if none
+// found.
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundResource* daSoundResourceManager::FindResource
+(
+ daResourceKey resourceKey
+)
+{
+ IDaSoundResource* pResource;
+
+ pResource = reinterpret_cast< IDaSoundResource* >
+ (
+ m_pSoundNamespace->GetInstance( resourceKey )
+ );
+ if( ( pResource == NULL ) && ( m_secondaryNamespace != NULL ) )
+ {
+ // Search secondary namespace
+ pResource = reinterpret_cast< IDaSoundResource* >
+ (
+ m_secondaryNamespace->GetInstance( resourceKey )
+ );
+ }
+
+ return pResource;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::FindAllocatedResource
+//=============================================================================
+// Description: Find an allocated resource
+//
+// Parameters: pResource - the resource associated with an allocated resource
+//
+// Note: Calling this command on a given resource is not guarenteed
+// to always return the same allocated resource. In fact,
+// it randomly choose which of the possible file variations
+// it should use.
+//
+//-----------------------------------------------------------------------------
+
+daSoundAllocatedResource* daSoundResourceManager::FindAllocatedResource
+(
+ IDaSoundResource* pResource
+)
+{
+ rAssert( pResource != NULL );
+
+ // Generate a key based on the resource
+ radKey32 soundKey = (radKey32) pResource;
+
+ // Find the allocated resource for the resource
+ daSoundAllocatedResource* pAllocatedResource =
+ reinterpret_cast< daSoundAllocatedResource* >
+ (
+ m_xIOL_AllocatedResources->FindObject( soundKey )
+ );
+
+ return pAllocatedResource;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::SetResourceLockdown
+//=============================================================================
+// Description: Set the lockdown state for resources
+//
+// Notes: When the resources are locked down, no new resources
+// can be created. This is so that the tuner's wiring
+// of the sound system can successively map all available
+// resources to sound groups.
+//
+//-----------------------------------------------------------------------------
+
+void FlipSlashes( char * pString )
+{
+ while (*pString != 0 )
+ {
+ if ( *pString == '/' )
+ {
+ *pString = '\\';
+ }
+ pString++;
+ }
+}
+
+void daSoundResourceManager::SetResourceLockdown( bool lockdown )
+{
+ // Currently we may only lock down the resources
+ rAssert( lockdown == true );
+ m_ResourceLockdown = lockdown;
+
+ unsigned int totalFiles = 0;
+
+ for( unsigned int r = 0; r < m_NumResourceDatas; r ++ )
+ {
+ daSoundResourceData * pRd = this->m_ResourceData + r;
+
+ totalFiles += pRd->m_NumFiles;
+ }
+
+ m_pFileIdMemory = (radKey32*) radMemoryAlloc( GMA_PERSISTENT, sizeof( radKey32 ) * totalFiles );
+
+ radKey32* pCurrent = m_pFileIdMemory;
+
+ for( unsigned int r = 0; r < MAX_SOUND_DATA_RESOURCES; r ++ )
+ {
+ daSoundResourceData * pRd = this->m_ResourceData + r;
+
+ for( unsigned int f = 0; f < pRd->m_NumFiles; f ++ )
+ {
+ FlipSlashes( pRd->m_pFileIds[ f ].m_pName );
+
+ pCurrent[ f ] = ::radMakeCaseInsensitiveKey32( pRd->m_pFileIds[ f ].m_pName );
+ radMemoryFree( pRd->m_pFileIds[ f ].m_pName );
+ }
+
+ radMemoryFree( pRd->m_pFileIds );
+ pRd->m_pFileIds = (daSoundResourceData::FileId*)pCurrent;
+ pCurrent += pRd->m_NumFiles;
+ }
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetResourceLockdown
+//=============================================================================
+// Description: Get the lockdown state for resources
+//-----------------------------------------------------------------------------
+
+bool daSoundResourceManager::GetResourceLockdown( void )
+{
+ return m_ResourceLockdown;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetLargestFileSize
+//=============================================================================
+// Description: Get the state of a resource
+//
+// Parameters: pResource - the resource to get the state of
+//
+// Returns: Returns the state of the resource
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundResourceManager::GetLargestFileSize
+(
+ IDaSoundResource* pResource
+)
+{
+ return 0;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetTotalSize
+//=============================================================================
+// Description: Get the state of a resource
+//
+// Parameters: pResource - the resource to get the state of
+//
+// Returns: Returns the state of the resource
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundResourceManager::GetTotalSize
+(
+ IDaSoundResource* pResource
+)
+{
+ return 0;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetSoundFileSize
+//=============================================================================
+// Description: Get debug information from resource manager
+//
+// Parameters: pFile - the file to find the size of
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundResourceManager::GetSoundFileSize
+(
+ const char* filename
+)
+{
+ // TODO : Don't use this unless it is not synchronous
+ rDebugString( "BAD SOUND FUNCTION BEING USED\n" );
+ unsigned int fileSize = 0;
+ IRadFile* pMyFile = NULL;
+ ::radFileOpen( &pMyFile, filename );
+ rAssert( pMyFile != NULL );
+ pMyFile->GetSizeAsync( &fileSize );
+ pMyFile->WaitForCompletion( );
+ pMyFile->Release( );
+ return fileSize;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetNumResources
+//=============================================================================
+// Description: Get the number of resources
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundResourceManager::GetNumResourceDatas( void )
+{
+ return m_NumResourceDatas;
+}
+
+//=============================================================================
+// Function: daSoundResourceManager::GetNumAllocatedResources
+//=============================================================================
+// Description: Get the number of allocated resources
+//
+//-----------------------------------------------------------------------------
+
+unsigned int daSoundResourceManager::GetNumAllocatedResources( void )
+{
+ return m_xIOL_AllocatedResources->GetSize( );
+}
+
+//=============================================================================
+// daSoundResourceManager::SetActiveResource
+//=============================================================================
+// Description: Set a secondary namespace for us to search for resources.
+// NOTE: a more robust implementation would have us storing a list
+// of these things, but I know for Simpsons that we'll only need
+// one and I want to keep the searches fast
+//
+// Parameters: activeNamespace - secondary namespace
+//
+// Return: void
+//
+//=============================================================================
+void daSoundResourceManager::SetActiveResource( IRadNameSpace* activeNamespace )
+{
+ if( activeNamespace != m_pSoundNamespace )
+ {
+ m_secondaryNamespace = activeNamespace;
+ }
+}
+
+//=============================================================================
+// daSoundResourceManager::ReleaseActiveResource
+//=============================================================================
+// Description: Lose our reference to the secondary namespace, probably because
+// the in-game resources are being released.
+//
+// Parameters: inactiveNamespace - only used to make sure we aren't releasing
+// the main sound namespace
+//
+// Return: void
+//
+//=============================================================================
+void daSoundResourceManager::ReleaseActiveResource( IRadNameSpace* inactiveNamespace )
+{
+ if( inactiveNamespace != m_pSoundNamespace )
+ {
+ m_secondaryNamespace = NULL;
+ }
+}
+
+daSoundResourceData * daSoundResourceManager::GetResourceDataAt( unsigned int i )
+{
+ rAssert( i < m_NumResourceDatas );
+
+ return m_ResourceData + i;
+}
+
+daSoundResourceData * daSoundResourceManager::CreateResourceData( void )
+{
+ daSoundResourceManager * pThis = daSoundResourceManager::GetInstance( );
+
+ rAssert( false == pThis->m_ResourceLockdown );
+
+ rAssert( pThis->m_NumResourceDatas < MAX_SOUND_DATA_RESOURCES );
+
+ daSoundResourceData * pRd = pThis->m_ResourceData + pThis->m_NumResourceDatas;
+
+ pThis->m_NumResourceDatas++;
+
+ return pRd;
+}
+
+} // Sound Namespace
+
diff --git a/game/code/sound/soundrenderer/soundresourcemanager.h b/game/code/sound/soundrenderer/soundresourcemanager.h
new file mode 100644
index 0000000..3a290c1
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundresourcemanager.h
@@ -0,0 +1,164 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundresourcemanager.hpp
+//
+// Subsystem: Dark Angel - Sound Resource Management System
+//
+// Description: Description of the DA sound resource manager
+//
+// Revisions:
+// + Created October 11, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _SOUNDRESOURCEMANAGER_HPP
+#define _SOUNDRESOURCEMANAGER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundresource.h>
+
+//=============================================================================
+// Global namespace forward declarations
+//=============================================================================
+
+class radObjectBTree;
+
+//=============================================================================
+// Namespace
+//=============================================================================
+
+namespace Sound {
+
+const unsigned int MAX_SOUND_DATA_RESOURCES = 5000;
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundResourceManager;
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+class daSoundAllocatedResource;
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+//
+// The sound player manager passes information into the various sound
+// players. It also keeps track of these players, gives them to people
+// who ask for them, and makes sure they do not cause to much trouble :)
+//
+class daSoundResourceManager : public IRefCount,
+ public radRefCount
+{
+public:
+ IMPLEMENT_REFCOUNTED( "daSoundResourceManager" );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundResourceManager( void );
+
+ virtual ~daSoundResourceManager( );
+
+ inline static daSoundResourceManager* GetInstance( void );
+
+ // Controlled by the resource data
+ void AllocateResource( IDaSoundResource* pResource );
+ void DeallocateResource( IDaSoundResource* pResource );
+
+ // Resource lockdown
+ void SetResourceLockdown( bool lockdown );
+
+ // Allocated resources
+ daSoundAllocatedResource* FindAllocatedResource
+ (
+ IDaSoundResource* pResource
+ );
+
+ // Get a sound file's size
+ unsigned int GetSoundFileSize
+ (
+ const char* filename
+ );
+
+ //
+ // IDaSoundResourceManager
+ //
+ IDaSoundResource* FindResource(
+ daResourceName resourceName );
+
+ IDaSoundResource* FindResource(
+ daResourceKey resourceKey );
+
+ unsigned int GetLargestFileSize( IDaSoundResource* pResource );
+ unsigned int GetTotalSize( IDaSoundResource* pResource );
+
+
+ bool GetResourceLockdown( void );
+
+ void SetActiveResource( IRadNameSpace* activeNamespace );
+ void ReleaseActiveResource( IRadNameSpace* inactiveNamespace );
+
+ unsigned int GetNumResourceDatas( void );
+ daSoundResourceData* GetResourceDataAt( unsigned int );
+ static daSoundResourceData* CreateResourceData( void );
+
+protected:
+ //
+ // Calculate some debug info
+ //
+
+ unsigned int GetNumAllocatedResources( );
+
+private:
+ // This is a singleton
+ static daSoundResourceManager* s_pSingleton;
+
+ //
+ // Store the sound namespace
+ //
+ IRadNameSpace* m_pSoundNamespace;
+
+ //
+ // Store all allocated resources (referenced by the resource's
+ // address cast to a radkey)
+ //
+ ref< radObjectBTree > m_xIOL_AllocatedResources;
+
+ //
+ // Are the resources locked down?
+ //
+ bool m_ResourceLockdown;
+
+ //
+ // Store active secondary namespace
+ //
+ IRadNameSpace* m_secondaryNamespace;
+
+ daSoundResourceData m_ResourceData[ MAX_SOUND_DATA_RESOURCES ];
+ unsigned int m_NumResourceDatas;
+
+ radKey32 * m_pFileIdMemory;
+};
+
+inline daSoundResourceManager* daSoundResourceManager::GetInstance( void )
+{
+ return s_pSingleton;
+}
+
+} // Sound Namespace
+#endif //_SOUNDRESOURCEMANAGER_HPP
+
+
diff --git a/game/code/sound/soundrenderer/soundsystem.h b/game/code/sound/soundrenderer/soundsystem.h
new file mode 100644
index 0000000..b0557ff
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundsystem.h
@@ -0,0 +1,118 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundsystem.hpp
+//
+// Subsystem: Dark Angel - Sound System
+//
+// Description: General declarations relating to the Dark Angel sound system
+//
+// Notes: This is the only file that may be loaded by non sound related
+// components of the game.
+//
+// Revisions: October 2, 2001 Creation BJR
+//
+//=============================================================================
+
+#ifndef _SOUNDSYSTEM_HPP
+#define _SOUNDSYSTEM_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radkey.hpp>
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+class daSoundRenderingManager;
+
+//=============================================================================
+// Constants, Definitions and Macros
+//=============================================================================
+
+// The sound memory allocator
+extern radMemoryAllocator DAMEMORY_ALLOC_SOUND;
+
+// One aux send channels will be used for spacial effects
+#define DA_SPACIAL_EFFECT_AUX_SEND 0
+#define DA_MISC_AUX_SEND 1
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+struct IDaSoundPlayerState;
+struct IDaSoundFadeState;
+struct IDaSoundSoundState;
+
+//=============================================================================
+// Typedefs and Enumerations
+//=============================================================================
+
+//
+// This is a sound resource name and key
+//
+typedef const char* daResourceName;
+typedef radKey32 daResourceKey;
+
+//
+// These are the sound values
+//
+typedef float daPitchValue;
+typedef float daTrimValue;
+
+//=============================================================================
+// Interfaces
+//=============================================================================
+
+//
+// Sound player state
+//
+struct IDaSoundPlayerState : public IRefCount
+{
+ virtual void OnSoundReady( void* pData ) = 0;
+ virtual void OnSoundDone( void* pData ) = 0;
+};
+
+//
+// Fade state
+//
+struct IDaSoundFadeState : public IRefCount
+{
+ virtual void OnFadeDone( void* pData ) = 0;
+};
+
+//
+// A sound object
+//
+struct IDaSoundObject : public IRefCount
+{
+ // Left intentionally blank
+};
+
+//=============================================================================
+// Public Functions
+//=============================================================================
+
+//
+// Set some global sound flags
+//
+void daSoundSetSoundOn( bool soundOn );
+
+//
+// Work indirectly with the sound manager
+//
+void daSoundRenderingManagerCreate( radMemoryAllocator allocator );
+daSoundRenderingManager* daSoundRenderingManagerGet( void );
+void daSoundRenderingManagerTerminate( void );
+
+} // Namespace
+#endif //_SOUNDSYSTEM_HPP
+
diff --git a/game/code/sound/soundrenderer/soundtuner.cpp b/game/code/sound/soundrenderer/soundtuner.cpp
new file mode 100644
index 0000000..7aaed29
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundtuner.cpp
@@ -0,0 +1,1241 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundtuner.cpp
+//
+// Subsystem: Dark Angel - Sound Tuner System
+//
+// Description: Implementation of the sound tuner
+//
+// Revisions:
+// + Created October 4, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+#include <radnamespace.hpp>
+
+#include <radsound.hpp>
+#include <radsound_hal.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/idasoundresource.h>
+#include <sound/soundrenderer/soundrenderingmanager.h>
+#include <sound/soundrenderer/soundresourcemanager.h>
+#include <sound/soundrenderer/playermanager.h>
+#include <sound/soundrenderer/soundtuner.h>
+
+#include <sound/soundmanager.h>
+
+#include <memory/srrmemory.h>
+
+//=============================================================================
+// Static Variables (outside namespace)
+//=============================================================================
+
+short Sound::daSoundTuner::s_groupWirings[NUM_SOUND_GROUPS];
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Class Implementations
+//=============================================================================
+
+//=============================================================================
+// daSoundTuner_ActiveFadeInfo Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundTuner_ActiveFadeInfo::daSoundTuner_ActiveFadeInfo
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundTuner_ActiveFadeInfo::daSoundTuner_ActiveFadeInfo
+(
+ Fader* pFader,
+ bool fadingIn,
+ IDaSoundFadeState* pDoneCallback,
+ void* pCallbackUserData,
+ DuckVolumeSet* initialVolumes,
+ DuckVolumeSet* targetVolumes
+)
+ :
+ m_pFader( pFader ),
+ m_FadingIn( fadingIn ),
+ m_pDoneCallback( pDoneCallback ),
+ m_pCallbackUserData( pCallbackUserData )
+{
+ // Reference count some items
+ rAssert( m_pFader != NULL );
+
+ m_pFader->AddRef( );
+ if( m_pDoneCallback != NULL )
+ {
+ m_pDoneCallback->AddRef( );
+ }
+
+ // Invoke the fader
+ m_pFader->Fade( m_FadingIn, initialVolumes, targetVolumes );
+}
+
+
+//=============================================================================
+// Function: daSoundTuner_ActiveFadeInfo::~daSoundTuner_ActiveFadeInfo
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundTuner_ActiveFadeInfo::~daSoundTuner_ActiveFadeInfo( )
+{
+ // Release our objects
+ rAssert( m_pFader != NULL );
+
+ m_pFader->Stop();
+ m_pFader->Release( );
+ if( m_pDoneCallback != NULL )
+ {
+ m_pDoneCallback->Release( );
+ }
+}
+
+//=============================================================================
+// Function: daSoundTuner_ActiveFadeInfo::ProcessFader
+//=============================================================================
+// Description: Process a fader's state progress
+//
+// Returns: true if we're done with the fader and are ready for destruction,
+// false otherwise
+//
+//-----------------------------------------------------------------------------
+
+bool daSoundTuner_ActiveFadeInfo::ProcessFader()
+{
+ // Is the fader done fading yet?
+ bool doneFading = false;
+ switch( m_pFader->GetState( ) )
+ {
+ case Fader::FadedIn:
+ case Fader::FadedOut:
+ {
+ // Must be done (what ever it was)
+ doneFading = true;
+ break;
+ }
+ case Fader::FadingIn:
+ {
+ // If we're supposed to be fading out, we must be done
+ if( !m_FadingIn )
+ {
+ doneFading = true;
+ }
+ break;
+ }
+ case Fader::FadingOut:
+ {
+ // If we're supposed to be fading in, we must be done
+ if( m_FadingIn )
+ {
+ doneFading = true;
+ }
+ break;
+ }
+ default:
+ rAssert( 0 );
+ break;
+ }
+
+ // If done, disconnect it, destroy it, and call its callback
+ if( doneFading )
+ {
+ // Remember the callback
+ IDaSoundFadeState* pCallback = m_pDoneCallback;
+ void* pUserData = m_pCallbackUserData;
+ if( pCallback != NULL )
+ {
+ pCallback->AddRef( );
+ }
+
+ // Call the callback
+ if( pCallback != NULL )
+ {
+ pCallback->OnFadeDone( pUserData );
+ pCallback->Release( );
+ }
+ }
+
+ return( doneFading );
+}
+
+void daSoundTuner_ActiveFadeInfo::StoreCurrentVolumes( DuckVolumeSet& volumeSet )
+{
+ unsigned int i;
+
+ rAssert( m_pFader != NULL );
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ volumeSet.duckVolume[i] = m_pFader->GetCurrentVolume( static_cast<DuckVolumes>(i) );
+ }
+}
+
+void daSoundTuner_ActiveFadeInfo::StoreTargetSettings( DuckVolumeSet& volumeSet )
+{
+ unsigned int i;
+
+ rAssert( m_pFader != NULL );
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ volumeSet.duckVolume[i] = m_pFader->GetTargetSettings( static_cast<DuckVolumes>(i) );
+ }
+}
+
+//=============================================================================
+// daSoundTuner Implementation
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundTuner::daSoundTuner
+//=============================================================================
+// Description: Constructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundTuner::daSoundTuner( )
+ :
+ radRefCount( 0 ),
+ m_pDuckFade( NULL ),
+ m_MasterVolume( 1.0f ),
+ m_activeFadeInfo( NULL ),
+ m_NISTrim( 1.0f )
+{
+ daSoundPlayerManager* playerMgr;
+ int i, j;
+
+ //
+ // The tuner makes use of several fader objects. These objects may be
+ // customized by scripts, so they must be added to the sound namespace.
+ //
+
+ // Duck fader
+ playerMgr = daSoundRenderingManagerGet()->GetPlayerManager();
+ rAssert( playerMgr != NULL );
+
+ m_pDuckFade = new( GetThisAllocator() ) Fader( NULL, DUCK_FULL_FADE, *playerMgr, *this );
+ rAssert( m_pDuckFade != NULL );
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ m_situationFaders[i] = NULL;
+ }
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ m_userVolumes.duckVolume[i] = 1.0f;
+ m_finalDuckLevels.duckVolume[i] = 1.0f;
+ }
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ for( j = 0; j < NUM_DUCK_VOLUMES; j++ )
+ {
+ m_duckLevels[i].duckVolume[j] = 1.0f;
+ }
+ }
+
+ //
+ // Initialize the sound group wirings (IMPORTANT: this assumes that
+ // daSoundTuner is a singleton, we only want to do this once)
+ //
+ for( i = 0; i < NUM_SOUND_GROUPS; i++ )
+ {
+ s_groupWirings[i] = ( 1 << i ) | ( 1 << MASTER );
+ }
+}
+
+//=============================================================================
+// Function: daSoundTuner::~daSoundTuner
+//=============================================================================
+// Description: Destructor
+//
+//-----------------------------------------------------------------------------
+
+daSoundTuner::~daSoundTuner( )
+{
+ int i;
+
+ // Release our duck faders
+ if( m_pDuckFade != NULL )
+ {
+ m_pDuckFade->Release( );
+ m_pDuckFade = NULL;
+ }
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ if( m_situationFaders[i] != NULL )
+ {
+ m_situationFaders[i]->Release( );
+ m_situationFaders[i] = NULL;
+ }
+ }
+
+ if( m_activeFadeInfo != NULL )
+ {
+ delete m_activeFadeInfo;
+ }
+}
+
+//=============================================================================
+// Function: daSoundTuner::Initialize
+//=============================================================================
+// Description: Initialize the sound tuner. This can only be done once
+// resources have been locked down.
+//
+// Parameters: outputMode - the output mode desired
+//
+// Returns: n/a
+//
+// Notes: This class does not support re-initialization
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::Initialize( void )
+{
+ // Make sure resources are locked down
+ //rAssert( Sound::daSoundRenderingManagerGet( )->GetResourceManager( )->GetResourceLockdown( ) );
+
+ // Generate each of the wiring groups
+ Sound::daSoundTunerWireSystem( this );
+}
+
+//=============================================================================
+// daSoundTuner::PostScriptLoadInitialize
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ()
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::PostScriptLoadInitialize()
+{
+ IRadNameSpace* nameSpace;
+ globalSettings* settingsObj;
+ daSoundPlayerManager* playerMgr;
+ int i;
+
+ playerMgr = daSoundRenderingManagerGet()->GetPlayerManager();
+ rAssert( playerMgr != NULL );
+
+ //
+ // Get the globalSettings object for Fader use
+ //
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ settingsObj = reinterpret_cast<globalSettings*>( nameSpace->GetInstance( "tuner" ) );
+ rAssert( settingsObj != NULL );
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ m_situationFaders[i] = new( GetThisAllocator() ) Fader( settingsObj,
+ static_cast<DuckSituations>(i),
+ *playerMgr,
+ *this );
+ rAssert( m_situationFaders[i] != NULL );
+ }
+
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ m_debugPage.LazyInitialization( 4, GetSoundManager()->GetDebugDisplay() );
+#endif
+}
+
+//=============================================================================
+// Function: daSoundTuner::ServiceOncePerFrame
+//=============================================================================
+// Description: Service the sound tuner. This should be done once per frame.
+//
+// Parameters: none
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::ServiceOncePerFrame( unsigned int elapsedTime )
+{
+ bool faderDone;
+
+ //
+ // Process the faders
+ //
+ Fader::UpdateAllFaders( elapsedTime );
+
+ //
+ // Process the fade info stuff that monitors the faders (hmmm, this is
+ // looking like a pretty lightweight class these days. Candidate for
+ // removal?)
+ //
+ if( m_activeFadeInfo != NULL )
+ {
+ faderDone = m_activeFadeInfo->daSoundTuner_ActiveFadeInfo::ProcessFader();
+
+ if( faderDone )
+ {
+ delete m_activeFadeInfo;
+ m_activeFadeInfo = NULL;
+ }
+ }
+
+ serviceDebugInfo();
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetSoundOutputMode
+//=============================================================================
+// Description: Set the sound system output mode (stereo, mono, surround)
+//
+// Parameters: outputMode - the output mode desired
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetSoundOutputMode
+(
+ IDaSoundTuner::SoundOutputMode outputMode
+)
+{
+ radSoundOutputMode rsdOutputMode = radSoundOutputMode_Stereo;
+ if( outputMode == MONO )
+ {
+ rsdOutputMode = radSoundOutputMode_Mono;
+ }
+ else if( outputMode == STEREO )
+ {
+ rsdOutputMode = radSoundOutputMode_Stereo;
+ }
+ else if( outputMode == SURROUND )
+ {
+ rsdOutputMode = radSoundOutputMode_Surround;
+ }
+ else
+ {
+ rAssertMsg( 0, "Invalid sound output mode" );
+ }
+
+ ::radSoundHalSystemGet( )->SetOutputMode( rsdOutputMode );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetSoundOutputMode
+//=============================================================================
+// Description: Get the sound system output mode (stereo, mono, surround)
+//
+// Parameters: none
+//
+// Returns: Returns the current sound output mode
+//
+//-----------------------------------------------------------------------------
+
+IDaSoundTuner::SoundOutputMode daSoundTuner::GetSoundOutputMode
+(
+ void
+)
+{
+ IDaSoundTuner::SoundOutputMode outputMode = STEREO;
+ radSoundOutputMode rsdOutputMode =
+ ::radSoundHalSystemGet( )->GetOutputMode( );
+ if( rsdOutputMode == radSoundOutputMode_Mono )
+ {
+ outputMode = MONO;
+ }
+ else if( rsdOutputMode == radSoundOutputMode_Stereo )
+ {
+ outputMode = STEREO;
+ }
+ else if( rsdOutputMode == radSoundOutputMode_Surround )
+ {
+ outputMode = SURROUND;
+ }
+ else
+ {
+ rAssertMsg( 0, "Unrecognized sound output mode" );
+ }
+
+ return outputMode;
+}
+
+//=============================================================================
+// Function: daSoundTuner::ActivateDuck
+//=============================================================================
+// Description: Start/stop ducking of sounds
+//
+// Parameters: pObject - the object to receive fade state events
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::ActivateDuck
+(
+ IDaSoundFadeState* pObject,
+ void* pUserData,
+ bool fadeIn
+)
+{
+ activateDuckInternal( pObject, pUserData, fadeIn, m_pDuckFade );
+}
+
+//=============================================================================
+// Function: daSoundTuner::StartSituationalDuck
+//=============================================================================
+// Description: Start ducking of sounds
+//
+// Parameters: pObject - the object to receive fade state events
+//
+// Returns: n/a
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::ActivateSituationalDuck( IDaSoundFadeState* pObject,
+ DuckSituations situation,
+ void* pUserData,
+ bool fadeIn )
+{
+ activateDuckInternal( pObject, pUserData, fadeIn, m_situationFaders[situation] );
+}
+
+//=============================================================================
+// daSoundTuner::ResetDuck
+//=============================================================================
+// Description: Stop all ducking
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::ResetDuck()
+{
+ unsigned int i, j;
+
+ //
+ // Return all the duck values to max, then do a fade in
+ //
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ for( j = 0; j < NUM_DUCK_SITUATIONS; j++ )
+ {
+ m_duckLevels[j].duckVolume[i] = 1.0f;
+ }
+ }
+
+ activateDuckInternal( NULL, NULL, true, m_pDuckFade );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetMasterVolume
+//=============================================================================
+// Description: Set the master volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetMasterVolume
+(
+ daTrimValue volume
+)
+{
+ m_MasterVolume = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( MASTER, m_MasterVolume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetMasterVolume
+//=============================================================================
+// Description: Get the master volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetMasterVolume( void )
+{
+ return( m_MasterVolume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetDialogueVolume
+//=============================================================================
+// Description: Set the dialogue volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetDialogueVolume
+(
+ daTrimValue volume
+)
+{
+ m_userVolumes.duckVolume[DUCK_DIALOG] = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( DIALOGUE, volume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetDialogueVolume
+//=============================================================================
+// Description: Get the dialogue volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetDialogueVolume( void )
+{
+ return( m_userVolumes.duckVolume[DUCK_DIALOG] );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetMusicVolume
+//=============================================================================
+// Description: Set the music volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetMusicVolume
+(
+ daTrimValue volume
+)
+{
+ m_userVolumes.duckVolume[DUCK_MUSIC] = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( MUSIC, volume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetMusicVolume
+//=============================================================================
+// Description: Get the music volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetMusicVolume( void )
+{
+ return( m_userVolumes.duckVolume[DUCK_MUSIC] );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetAmbienceVolume
+//=============================================================================
+// Description: Set the music volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetAmbienceVolume
+(
+ daTrimValue volume
+)
+{
+ m_userVolumes.duckVolume[DUCK_AMBIENCE] = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( AMBIENCE, volume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetAmbienceVolume
+//=============================================================================
+// Description: Get the music volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetAmbienceVolume( void )
+{
+ return( m_userVolumes.duckVolume[DUCK_AMBIENCE] );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetSfxVolume
+//=============================================================================
+// Description: Set the sound effects volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetSfxVolume
+(
+ daTrimValue volume
+)
+{
+ m_userVolumes.duckVolume[DUCK_SFX] = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( SOUND_EFFECTS, volume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetSfxVolume
+//=============================================================================
+// Description: Get the sound effects volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetSfxVolume( void )
+{
+ return( m_userVolumes.duckVolume[DUCK_SFX] );
+}
+
+//=============================================================================
+// Function: daSoundTuner::SetCarVolume
+//=============================================================================
+// Description: Set the sound effects volume
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::SetCarVolume( daTrimValue volume )
+{
+ m_userVolumes.duckVolume[DUCK_CAR] = volume;
+
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( CARSOUND, volume );
+}
+
+//=============================================================================
+// Function: daSoundTuner::GetCarVolume
+//=============================================================================
+// Description: Get the sound effects volume
+//
+//-----------------------------------------------------------------------------
+
+daTrimValue daSoundTuner::GetCarVolume( void )
+{
+ return( m_userVolumes.duckVolume[DUCK_CAR] );
+}
+
+//=============================================================================
+// Function: daSoundTuner::FadeSounds
+//=============================================================================
+// Description: Fade a particular group of sounds
+//
+// Parameters: pKnob - the knob to fade
+// pObject - the fade state change object
+// pUserData - user data for the state change callback
+// pFader - a pointer to an actual fader to use
+// fadeIn - true if we are fading in
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::FadeSounds
+(
+ IDaSoundFadeState* pObject,
+ void* pUserData,
+ Fader* pFader,
+ bool fadeIn,
+ DuckVolumeSet* initialVolumes
+)
+{
+ unsigned int i;
+ DuckVolumeSet currentVolumes;
+ DuckVolumeSet* initVolumePtr = initialVolumes;
+ DuckVolumeSet targetVolumes;
+
+ rAssert( m_activeFadeInfo == NULL );
+ rAssert( pFader != NULL );
+ if( pFader == NULL )
+ {
+ return;
+ }
+
+ HeapMgr()->PushHeap( static_cast<GameMemoryAllocator>(GetThisAllocator()) );
+
+ //
+ // Store the intended targets for this fader.
+ //
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ if( fadeIn )
+ {
+ m_duckLevels[pFader->GetSituation()].duckVolume[i] = 1.0f;
+ }
+ else
+ {
+ m_duckLevels[pFader->GetSituation()].duckVolume[i] =
+ pFader->GetTargetSettings( static_cast<Sound::DuckVolumes>(i) );
+ }
+ }
+
+ if( initVolumePtr == NULL )
+ {
+ //
+ // Initial volumes aren't supplied, so use the current settings
+ // as we've recorded them here
+ //
+ initVolumePtr = &currentVolumes;
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ currentVolumes.duckVolume[i] = m_userVolumes.duckVolume[i];
+ }
+ }
+
+ calculateDuckedVolumes( targetVolumes );
+
+ // Create the temporary fade object. It will destroy itself when done
+ m_activeFadeInfo = new daSoundTuner_ActiveFadeInfo
+ (
+ pFader,
+ fadeIn,
+ pObject,
+ pUserData,
+ initialVolumes,
+ &targetVolumes
+ );
+
+ HeapMgr()->PopHeap( static_cast<GameMemoryAllocator>( GetThisAllocator() ) );
+}
+
+
+//=============================================================================
+// Function: daSoundTuner::WireKnobToPathHelper
+//=============================================================================
+// Description: Helper function to wire a knob to a path for a resource.
+// This function is automattically called on every
+// sound resource. If the path matches that of a file
+// in the resource, the resource's sound group is automattically
+// wired to the sound group specified by the user data.
+//
+// Notes: Trying to put a resource in more than one group will not work!
+// If a resource contains files from more than one fundamental
+// path and its wiring must reflect this, then a new
+// allocation stratagy should be used.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::WireKnobToPathHelper
+(
+ IDaSoundResource* pRes,
+ void* pUserData
+)
+{
+ char filenameBuffer[256];
+
+ // Get the wiring info
+ WirePathInfo* pInfo = (WirePathInfo*)pUserData;
+
+ unsigned int i = 0;
+ for( i = 0; i < pRes->GetNumFiles( ); i++ )
+ {
+ pRes->GetFileNameAt( i, filenameBuffer, 256 );
+ unsigned int j = 0;
+ bool match = true;
+ for( j = 0; j < pInfo->m_PathLen; j++ )
+ {
+ char a = filenameBuffer[j];
+ char b = pInfo->m_Path[j];
+
+ if( a == '/' )
+ {
+ a = '\\';
+ }
+ if( b == '/' )
+ {
+ b = '\\';
+ }
+ if( a != b )
+ {
+ // Notice that this supports the case when the length
+ // of the filename is less than the test path because,
+ // in that case, the '\0' character won't match
+ match = false;
+ break;
+ }
+ }
+ if( match )
+ {
+ pRes->SetSoundGroup( pInfo->m_SoundGroup );
+ break;
+ }
+ }
+}
+
+//=============================================================================
+// Function: daSoundTuner::WirePath
+//=============================================================================
+// Description: Wire a path to a particular sound group
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTuner::WirePath
+(
+ daSoundGroup soundGroup,
+ const char* path
+)
+{
+ // Find all resource that are in this path and relate them to this knob
+ WirePathInfo wirePathInfo;
+ wirePathInfo.m_Path = path;
+ wirePathInfo.m_PathLen = strlen( wirePathInfo.m_Path );
+ wirePathInfo.m_SoundGroup = soundGroup;
+
+ unsigned int numResources =
+ daSoundResourceManager::GetInstance( )->GetNumResourceDatas( );
+
+ for( unsigned int r = 0; r < numResources; r ++ )
+ {
+ WireKnobToPathHelper(
+ daSoundResourceManager::GetInstance( )->GetResourceDataAt( r ),
+ & wirePathInfo );
+ }
+}
+
+//=============================================================================
+// daSoundTuner::WireGroup
+//=============================================================================
+// Description: Mark a sound group as changing in sync with the master group
+//
+// Parameters: slaveGroup - slave that changes with master group
+// masterGroup - controller group
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::WireGroup( daSoundGroup slaveGroup, daSoundGroup masterGroup )
+{
+ unsigned int i;
+
+ for( i = 0; i < NUM_SOUND_GROUPS; i++ )
+ {
+ if( s_groupWirings[i] & ( 1 << slaveGroup ) )
+ {
+ s_groupWirings[i] |= 1 << masterGroup;
+ }
+ }
+}
+
+//=============================================================================
+// daSoundTuner::IsSlaveGroup
+//=============================================================================
+// Description: Indicates whether one group is slaved to another
+//
+// Parameters: slave - proposed slave sound group
+// master - proposed master sound group
+//
+// Return: True if slave is affected by master, false otherwise
+//
+//=============================================================================
+bool daSoundTuner::IsSlaveGroup( daSoundGroup slave, daSoundGroup master )
+{
+ if( s_groupWirings[slave] & ( 1 << master ) )
+ {
+ return( true );
+ }
+
+ return( false );
+}
+
+//=============================================================================
+// daSoundTuner::GetGroupTrim
+//=============================================================================
+// Description: Get the trim associated with a particular sound group.
+// Actually, our "group" is currently one of four settings,
+// even though we break it down more in daSoundGroup for
+// future expansion.
+//
+// Parameters: group - group that we want trim for
+//
+// Return: trim value for that group, or 1.0f (max) if it doesn't fit
+//
+//=============================================================================
+daTrimValue daSoundTuner::GetGroupTrim( daSoundGroup group )
+{
+ if( IsSlaveGroup( group, SOUND_EFFECTS ) )
+ {
+ return( m_userVolumes.duckVolume[DUCK_SFX] );
+ }
+ else if( IsSlaveGroup( group, MUSIC ) )
+ {
+ return( m_userVolumes.duckVolume[DUCK_MUSIC] );
+ }
+ else if( IsSlaveGroup( group, DIALOGUE ) )
+ {
+ return( m_userVolumes.duckVolume[DUCK_DIALOG] );
+ }
+ else if( IsSlaveGroup( group, AMBIENCE ) )
+ {
+ return( m_userVolumes.duckVolume[DUCK_AMBIENCE] );
+ }
+ else if( IsSlaveGroup( group, CARSOUND ) )
+ {
+ return( m_userVolumes.duckVolume[DUCK_CAR] );
+ }
+ else if( IsSlaveGroup( group, OPTIONS_MENU_STINGERS ) )
+ {
+ //
+ // Special group for options menu, not affected by ducking
+ //
+ return( 1.0f );
+ }
+ else
+ {
+ //
+ // None of the above. We shouldn't get here
+ //
+ rAssert( false );
+ return( 1.0f );
+ }
+}
+
+//=============================================================================
+// daSoundTuner::SetFaderGroupTrim
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( Sound::DuckVolumes group, daTrimValue trim )
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::SetFaderGroupTrim( Sound::DuckVolumes group, daTrimValue trim )
+{
+ m_finalDuckLevels.duckVolume[group] = trim;
+}
+
+//=============================================================================
+// daSoundTuner::GetFaderGroupTrim
+//=============================================================================
+// Description: Get the fader trim associated with a particular sound group.
+// Actually, our "group" is currently one of four settings,
+// even though we break it down more in daSoundGroup for
+// future expansion.
+//
+// Parameters: group - group that we want trim for
+//
+// Return: trim value for that group, or 1.0f (max) if it doesn't fit
+//
+//=============================================================================
+daTrimValue daSoundTuner::GetFaderGroupTrim( daSoundGroup group )
+{
+ if( IsSlaveGroup( group, SOUND_EFFECTS ) )
+ {
+ return( m_finalDuckLevels.duckVolume[DUCK_SFX] );
+ }
+ else if( IsSlaveGroup( group, MUSIC ) )
+ {
+ return( m_finalDuckLevels.duckVolume[DUCK_MUSIC] );
+ }
+ else if( IsSlaveGroup( group, DIALOGUE ) )
+ {
+ return( m_finalDuckLevels.duckVolume[DUCK_DIALOG] );
+ }
+ else if( IsSlaveGroup( group, AMBIENCE ) )
+ {
+ return( m_finalDuckLevels.duckVolume[DUCK_AMBIENCE] );
+ }
+ else if( IsSlaveGroup( group, CARSOUND ) )
+ {
+ return( m_finalDuckLevels.duckVolume[DUCK_CAR] );
+ }
+ else if( IsSlaveGroup( group, OPTIONS_MENU_STINGERS ) )
+ {
+ //
+ // Special group for options menu, not affected by ducking
+ //
+ return( 1.0f );
+ }
+ else
+ {
+ //
+ // None of the above. We shouldn't get here
+ //
+ rAssert( false );
+ return( 1.0f );
+ }
+}
+
+void daSoundTuner::MuteNIS()
+{
+ m_NISTrim = GetGroupTrim( NIS );
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( NIS, 0.0f );
+}
+
+void daSoundTuner::UnmuteNIS()
+{
+ daSoundRenderingManagerGet()->GetPlayerManager()->PlayerVolumeChange( NIS, m_NISTrim );
+}
+
+//=============================================================================
+// Private functions
+//=============================================================================
+
+void daSoundTuner::activateDuckInternal( IDaSoundFadeState* pObject,
+ void* pUserData,
+ bool fadeOut,
+ Fader* faderObj )
+{
+ DuckVolumeSet currentVolumes;
+
+#ifndef RAD_RELEASE
+ //
+ // Hack for fader tuning. The tuners usually only read the fader
+ // settings at startup, but we want them to pick up changes in radTuner
+ // on the fly. We'll make it refresh on each duck attempt in debug
+ // and tune builds.
+ //
+ refreshFaderSettings();
+#endif
+
+ if( m_activeFadeInfo != NULL )
+ {
+ //
+ // Get the current fader's settings and throw it on the stack
+ //
+ m_activeFadeInfo->StoreCurrentVolumes( currentVolumes );
+
+ //
+ // Now we can get rid of the old fader
+ //
+ delete m_activeFadeInfo;
+ m_activeFadeInfo = NULL;
+ }
+ else
+ {
+ calculateDuckedVolumes( currentVolumes );
+ }
+
+ // Use our duck fader...
+ FadeSounds( pObject,
+ pUserData,
+ faderObj,
+ fadeOut,
+ &currentVolumes );
+}
+
+//=============================================================================
+// daSoundTuner::calculateDuckedVolumes
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( DuckVolumeSet& volumes )
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::calculateDuckedVolumes( DuckVolumeSet& volumes )
+{
+ unsigned int i, j;
+
+ //
+ // Calculate target volumes
+ //
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ volumes.duckVolume[i] = 1.0f;
+ }
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ for( j = 0; j < NUM_DUCK_SITUATIONS; j++ )
+ {
+ if( m_duckLevels[j].duckVolume[i] < volumes.duckVolume[i] )
+ {
+ volumes.duckVolume[i] = m_duckLevels[j].duckVolume[i];
+ }
+ }
+ }
+}
+
+//=============================================================================
+// daSoundTuner::refreshFaderSettings
+//=============================================================================
+// Description: Reset the duck settings for each fader
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::refreshFaderSettings()
+{
+ IRadNameSpace* nameSpace;
+ globalSettings* settingsObj;
+ unsigned int i;
+
+ nameSpace = Sound::daSoundRenderingManagerGet()->GetTuningNamespace();
+ rAssert( nameSpace != NULL );
+
+ settingsObj = reinterpret_cast<globalSettings*>( nameSpace->GetInstance( "tuner" ) );
+ rAssert( settingsObj != NULL );
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ m_situationFaders[i]->ReinitializeFader( settingsObj );
+ }
+}
+
+//=============================================================================
+// daSoundTuner::serviceDebugInfo
+//=============================================================================
+// Description: Send some debug stuff to be dumped on the screen
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void daSoundTuner::serviceDebugInfo()
+{
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ unsigned int i;
+ unsigned int j;
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ for( j = 0; j < NUM_DUCK_VOLUMES; j++ )
+ {
+ m_debugPage.SetDuckLevel( static_cast<Sound::DuckSituations>(i),
+ static_cast<Sound::DuckVolumes>(j),
+ m_duckLevels[i].duckVolume[j] );
+ }
+ }
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ m_debugPage.SetFinalDuckLevel( static_cast<Sound::DuckVolumes>(i), m_finalDuckLevels.duckVolume[i] );
+ }
+
+ for( i = 0; i < NUM_DUCK_VOLUMES; i++ )
+ {
+ m_debugPage.SetUserVolume( static_cast<Sound::DuckVolumes>(i), m_userVolumes.duckVolume[i] );
+ }
+#endif
+}
+
+//=============================================================================
+// Factory functions
+//=============================================================================
+
+//=============================================================================
+// Function: daSoundTunerCreate
+//=============================================================================
+// Description: Create the tuner
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTunerCreate
+(
+ IDaSoundTuner** ppTuner,
+ radMemoryAllocator allocator
+)
+{
+ rAssert( ppTuner != NULL );
+ (*ppTuner) = new ( allocator ) daSoundTuner( );
+ (*ppTuner)->AddRef( );
+}
+
+} // Sound Namespace
diff --git a/game/code/sound/soundrenderer/soundtuner.h b/game/code/sound/soundrenderer/soundtuner.h
new file mode 100644
index 0000000..93aa9f9
--- /dev/null
+++ b/game/code/sound/soundrenderer/soundtuner.h
@@ -0,0 +1,253 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundtuner.hpp
+//
+// Subsystem: Dark Angel - Sound Tuner System
+//
+// Description: Description of the DA sound tuner
+//
+// Revisions:
+// + Created October 4, 2001 -- breimer
+//
+//=============================================================================
+
+#ifndef _SOUNDTUNER_HPP
+#define _SOUNDTUNER_HPP
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <raddebug.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/soundrenderer/dasoundgroup.h>
+
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/fader.h>
+#include <sound/soundrenderer/tunerdebugpage.h>
+
+//=============================================================================
+// Global namespace forward declarations
+//=============================================================================
+
+struct IDaSoundResource;
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Prototypes
+//=============================================================================
+
+class daSoundTuner;
+
+//=============================================================================
+// Forward declarations
+//=============================================================================
+
+//=============================================================================
+// Class Declarations
+//=============================================================================
+
+//
+// A fade state information structure stores necessary information about
+// an active fade.
+//
+class daSoundTuner_ActiveFadeInfo
+{
+public:
+
+ // Constructor and destructor
+ daSoundTuner_ActiveFadeInfo
+ (
+ Fader* pFader,
+ bool pFadingIn,
+ IDaSoundFadeState* pDoneCallback,
+ void* pCallbackUserData,
+ DuckVolumeSet* initialVolumes,
+ DuckVolumeSet* targetVolumes
+ );
+ virtual ~daSoundTuner_ActiveFadeInfo( );
+
+ // Process the fader
+ bool ProcessFader();
+
+ void StoreCurrentVolumes( DuckVolumeSet& volumeSet );
+ void StoreTargetSettings( DuckVolumeSet& volumeSet );
+
+ Sound::DuckSituations GetSituation() { return( m_pFader->GetSituation() ); }
+
+private:
+ // Store the raw data
+ Fader* m_pFader;
+ bool m_FadingIn;
+ IDaSoundFadeState* m_pDoneCallback;
+ void* m_pCallbackUserData;
+};
+
+//
+// The sound tuner. All controls associated with the tuner have
+// a scripted sister componenet available for composers to modify
+// using radtuner.
+//
+class daSoundTuner : public IDaSoundTuner,
+ public radRefCount
+{
+public:
+ IMPLEMENT_REFCOUNTED( "daSoundTuner" );
+
+ //
+ // Constructor and destructor
+ //
+ daSoundTuner( );
+ virtual ~daSoundTuner( );
+
+ //
+ // IDaSoundTuner
+ //
+ void Initialize( void );
+ void PostScriptLoadInitialize();
+ void ServiceOncePerFrame( unsigned int elapsedTime );
+
+ void SetSoundOutputMode
+ (
+ SoundOutputMode outputMode
+ );
+ SoundOutputMode GetSoundOutputMode( void );
+
+ void ActivateDuck
+ (
+ IDaSoundFadeState* pObject,
+ void* pUserData,
+ bool fadeIn
+ );
+
+ void ActivateSituationalDuck( IDaSoundFadeState* pObject,
+ DuckSituations situation,
+ void* pUserData,
+ bool fadeIn );
+
+ void ResetDuck();
+
+ void SetMasterVolume( daTrimValue volume );
+ daTrimValue GetMasterVolume( void );
+
+ void SetDialogueVolume( daTrimValue volume );
+ daTrimValue GetDialogueVolume( void );
+
+ void SetMusicVolume( daTrimValue volume );
+ daTrimValue GetMusicVolume( void );
+
+ void SetAmbienceVolume( daTrimValue volume );
+ daTrimValue GetAmbienceVolume( void );
+
+ void SetSfxVolume( daTrimValue volume );
+ daTrimValue GetSfxVolume( void );
+
+ void SetCarVolume( daTrimValue volume );
+ daTrimValue GetCarVolume( void );
+
+ daTrimValue GetGroupTrim( daSoundGroup group );
+ daTrimValue GetFaderGroupTrim( daSoundGroup group );
+
+ void MuteNIS();
+ void UnmuteNIS();
+
+ void SetFaderGroupTrim( Sound::DuckVolumes group, daTrimValue trim );
+
+ void FadeSounds( IDaSoundFadeState* pObject,
+ void* pUserData,
+ Fader* pFader,
+ bool fadeIn,
+ DuckVolumeSet* initialVolumes = NULL );
+
+ //
+ // IDaSoundWiring
+ //
+ void WirePath
+ (
+ daSoundGroup soundGroup,
+ const char* path
+ );
+
+ void WireGroup( daSoundGroup slaveGroup, daSoundGroup masterGroup );
+
+ //
+ // Sound group info
+ //
+ bool IsSlaveGroup( daSoundGroup slave, daSoundGroup master );
+
+protected:
+ //
+ // Helper function for wiring knob paths
+ //
+ struct WirePathInfo
+ {
+ const char* m_Path;
+ size_t m_PathLen;
+ daSoundGroup m_SoundGroup;
+ };
+ static void WireKnobToPathHelper
+ (
+ IDaSoundResource* pRes,
+ void* pUserData
+ );
+
+private:
+
+ void activateDuckInternal( IDaSoundFadeState* pObject,
+ void* pUserData,
+ bool fadeOut,
+ Fader* faderObj );
+ void calculateDuckedVolumes( DuckVolumeSet& volumes );
+
+ void refreshFaderSettings();
+
+ void serviceDebugInfo();
+
+#ifdef SOUND_DEBUG_INFO_ENABLED
+ TunerDebugPage m_debugPage;
+#endif
+
+ //
+ // How many ducks to we have in progress?
+ //
+ DuckVolumeSet m_duckLevels[NUM_DUCK_SITUATIONS];
+
+ DuckVolumeSet m_finalDuckLevels;
+
+ //
+ // Store our duck faders
+ //
+ Fader* m_pDuckFade;
+
+ Fader* m_situationFaders[NUM_DUCK_SITUATIONS];
+
+ //
+ // Group volume settings
+ //
+ float m_MasterVolume;
+
+ DuckVolumeSet m_userVolumes;
+
+ //
+ // Our static sound group wirings
+ //
+ static short s_groupWirings[NUM_SOUND_GROUPS];
+
+ daSoundTuner_ActiveFadeInfo* m_activeFadeInfo;
+
+ //
+ // NIS hack
+ //
+ float m_NISTrim;
+};
+
+} // Sound Namespace
+#endif //_SOUNDTUNER_HPP
+
diff --git a/game/code/sound/soundrenderer/tunerdebugpage.cpp b/game/code/sound/soundrenderer/tunerdebugpage.cpp
new file mode 100644
index 0000000..a792952
--- /dev/null
+++ b/game/code/sound/soundrenderer/tunerdebugpage.cpp
@@ -0,0 +1,231 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: tunerdebugpage.cpp
+//
+// Description: Displays debug info for the sound tuner
+//
+// History: 6/11/2003 + Created -- NAME
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundrenderer/tunerdebugpage.h>
+
+const char* s_duckNames[Sound::NUM_DUCK_SITUATIONS] =
+{
+ "Full fade",
+ "Pause",
+ "Mission",
+ "Letterbox",
+ "Dialogue",
+ "Store",
+ "On foot",
+ "Minigame",
+ "Just Music",
+ "Credits"
+};
+
+//*****************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// Public Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// TunerDebugPage::TunerDebugPage
+//=============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+TunerDebugPage::TunerDebugPage()
+{
+ unsigned int i, j;
+
+ //
+ // Zero out the tuner values
+ //
+ for( i = 0; i < Sound::NUM_DUCK_SITUATIONS; i++ )
+ {
+ for( j = 0; j < Sound::NUM_DUCK_VOLUMES; j++ )
+ {
+ m_duckLevels[i].duckVolume[j] = 0.0f;
+ }
+ }
+
+ for( i = 0; i < Sound::NUM_DUCK_VOLUMES; i++ )
+ {
+ m_userVolumes.duckVolume[i] = 0.0f;
+ }
+}
+
+//=============================================================================
+// TunerDebugPage::~TunerDebugPage
+//=============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//=============================================================================
+TunerDebugPage::~TunerDebugPage()
+{
+}
+
+//=============================================================================
+// TunerDebugPage::SetDuckLevel
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( DuckSituations situation, DuckVolumes volumeType, float volume )
+//
+// Return: void
+//
+//=============================================================================
+void TunerDebugPage::SetDuckLevel( Sound::DuckSituations situation,
+ Sound::DuckVolumes volumeType,
+ float volume )
+{
+ m_duckLevels[situation].duckVolume[volumeType] = volume;
+}
+
+//=============================================================================
+// TunerDebugPage::SetFinalDuckLevel
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( DuckVolumes volumeType, float volume )
+//
+// Return: void
+//
+//=============================================================================
+void TunerDebugPage::SetFinalDuckLevel( Sound::DuckVolumes volumeType, float volume )
+{
+ m_finalDuckLevel.duckVolume[volumeType] = volume;
+}
+
+//=============================================================================
+// TunerDebugPage::SetUserVolume
+//=============================================================================
+// Description: Comment
+//
+// Parameters: ( DuckVolumes volumeType, float volume )
+//
+// Return: void
+//
+//=============================================================================
+void TunerDebugPage::SetUserVolume( Sound::DuckVolumes volumeType, float volume )
+{
+ m_userVolumes.duckVolume[volumeType] = volume;
+}
+
+//*****************************************************************************
+//
+// Protected Member Functions
+//
+//*****************************************************************************
+
+//=============================================================================
+// TunerDebugPage::fillLineBuffer
+//=============================================================================
+// Description: Fill the given buffer with text to display on the screen
+// at the given line
+//
+// Parameters: lineNum - line number on screen where buffer will be displayed
+// buffer - to be filled in with text to display
+//
+// Return: void
+//
+//=============================================================================
+void TunerDebugPage::fillLineBuffer( int lineNum, char* buffer )
+{
+ switch( lineNum )
+ {
+ case 0:
+ strcpy( buffer, "Ducking volumes:" );
+ break;
+
+ case 1:
+ strcpy( buffer, " SFX Car Music Dialog Ambience" );
+ break;
+
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ sprintf( buffer, "%s: %0.2f %0.2f %0.2f %0.2f %0.2f",
+ s_duckNames[lineNum-2],
+ m_duckLevels[lineNum-2].duckVolume[0],
+ m_duckLevels[lineNum-2].duckVolume[1],
+ m_duckLevels[lineNum-2].duckVolume[2],
+ m_duckLevels[lineNum-2].duckVolume[3],
+ m_duckLevels[lineNum-2].duckVolume[4] );
+ break;
+
+ case 13:
+ sprintf( buffer, "Final duck volumes: %0.2f %0.2f %0.2f %0.2f %0.2f",
+ m_finalDuckLevel.duckVolume[0],
+ m_finalDuckLevel.duckVolume[1],
+ m_finalDuckLevel.duckVolume[2],
+ m_finalDuckLevel.duckVolume[3],
+ m_finalDuckLevel.duckVolume[4] );
+ break;
+
+ case 15:
+ sprintf( buffer, "User volumes: %0.2f %0.2f %0.2f %0.2f %0.2f",
+ m_userVolumes.duckVolume[0],
+ m_userVolumes.duckVolume[1],
+ m_userVolumes.duckVolume[2],
+ m_userVolumes.duckVolume[3],
+ m_userVolumes.duckVolume[4] );
+ break;
+
+ default:
+ buffer[0] = '\0';
+ break;
+ }
+}
+
+//=============================================================================
+// DialogSoundDebugPage::getNumLines
+//=============================================================================
+// Description: Returns number of lines that we'll display on screen
+//
+// Parameters: None
+//
+// Return: Line count
+//
+//=============================================================================
+int TunerDebugPage::getNumLines()
+{
+ return( 16 );
+}
+
+//*****************************************************************************
+//
+// Private Member Functions
+//
+//*****************************************************************************
diff --git a/game/code/sound/soundrenderer/tunerdebugpage.h b/game/code/sound/soundrenderer/tunerdebugpage.h
new file mode 100644
index 0000000..b48797c
--- /dev/null
+++ b/game/code/sound/soundrenderer/tunerdebugpage.h
@@ -0,0 +1,68 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: tunerdebugpage.h
+//
+// Description: Displays debug info for the sound tuner
+//
+// History: 6/11/2003 + Created -- Esan
+//
+//=============================================================================
+
+#ifndef TUNERDEBUGPAGE_H
+#define TUNERDEBUGPAGE_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <sound/sounddebug/sounddebugpage.h>
+
+#include <sound/soundrenderer/dasoundgroup.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: TunerDebugPage
+//
+//=============================================================================
+
+class TunerDebugPage : public SoundDebugPage
+{
+ public:
+ TunerDebugPage();
+ virtual ~TunerDebugPage();
+
+ void SetDuckLevel( Sound::DuckSituations situation, Sound::DuckVolumes volumeType, float volume );
+ void SetFinalDuckLevel( Sound::DuckVolumes volumeType, float volume );
+ void SetUserVolume( Sound::DuckVolumes volumeType, float volume );
+
+ protected:
+ //
+ // Pure virtual functions from SoundDebugPage
+ //
+ void fillLineBuffer( int lineNum, char* buffer );
+ int getNumLines();
+
+ private:
+ //Prevent wasteful constructor creation.
+ TunerDebugPage( const TunerDebugPage& tunerdebugpage );
+ TunerDebugPage& operator=( const TunerDebugPage& tunerdebugpage );
+
+ //
+ // Ducking info
+ //
+ Sound::DuckVolumeSet m_duckLevels[Sound::NUM_DUCK_SITUATIONS];
+ Sound::DuckVolumeSet m_finalDuckLevel;
+ Sound::DuckVolumeSet m_userVolumes;
+};
+
+//*****************************************************************************
+//
+//Inline Public Member Functions
+//
+//*****************************************************************************
+
+#endif //TUNERDEBUGPAGE_H
diff --git a/game/code/sound/soundrenderer/wireplayers.cpp b/game/code/sound/soundrenderer/wireplayers.cpp
new file mode 100644
index 0000000..c63b138
--- /dev/null
+++ b/game/code/sound/soundrenderer/wireplayers.cpp
@@ -0,0 +1 @@
+// This page made intentially empty. \ No newline at end of file
diff --git a/game/code/sound/soundrenderer/wiresystem.cpp b/game/code/sound/soundrenderer/wiresystem.cpp
new file mode 100644
index 0000000..6582a16
--- /dev/null
+++ b/game/code/sound/soundrenderer/wiresystem.cpp
@@ -0,0 +1,104 @@
+//=============================================================================
+// Copyright (C) 2001 Radical Entertainment Ltd. All rights reserved.
+//
+// File: wiresystem.cpp
+//
+// Subsystem: Dark Angel - Sound Tuner System
+//
+// Description: Wire the tuner
+//
+// Revisions:
+// + Created October 24, 2001 -- breimer
+//
+//=============================================================================
+
+//=============================================================================
+// Included Files
+//=============================================================================
+
+#include <radobject.hpp>
+#include <raddebug.hpp>
+
+#include <radsound.hpp>
+#include <radsound_hal.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+#include <sound/soundrenderer/idasoundtuner.h>
+#include <sound/soundrenderer/soundtuner.h>
+
+//=============================================================================
+// Define Owning Namespace
+//=============================================================================
+
+namespace Sound {
+
+//=============================================================================
+// Public functions
+//=============================================================================
+
+//=============================================================================
+// Function: ::daSoundTunerWireSystem
+//=============================================================================
+// Description: Wire the sound system
+//
+// NOTE: Music and ambience are ignored here, because they're controlled by
+// Radmusic and not us.
+//
+//-----------------------------------------------------------------------------
+
+void daSoundTunerWireSystem
+(
+ IDaSoundWiring* pWiring
+)
+{
+ // PATHS //////////////////////////////////////////////////////////////////
+
+ //
+ // Start by wiring up everything as dialogue by default. This is because
+ // we strip a little path info out of the dialogue files, so that we can
+ // easily switch between languages.
+ //
+ pWiring->WirePath( DIALOGUE, "" );
+
+ // Character
+ pWiring->WirePath
+ (
+ CARSOUND,
+ "sound\\carsound"
+ );
+
+ // Collision
+ pWiring->WirePath
+ (
+ NIS,
+ "sound\\nis"
+ );
+
+ pWiring->WirePath
+ (
+ SOUND_EFFECTS,
+ "sound\\soundfx"
+ );
+
+ pWiring->WirePath
+ (
+ OPTIONS_MENU_STINGERS,
+ "sound\\soundfx\\optionsmenu"
+ );
+
+ // SPECIAL GROUPS /////////////////////////////////////////////////////////
+
+ pWiring->WireGroup( NIS, DIALOGUE );
+
+ pWiring->WireGroup( DIALOGUE, DUCKABLE );
+ pWiring->WireGroup( SOUND_EFFECTS, DUCKABLE );
+ pWiring->WireGroup( CARSOUND, DUCKABLE );
+ pWiring->WireGroup( OPTIONS_MENU_STINGERS, DUCKABLE );
+
+ pWiring->WireGroup( DIALOGUE, DIALOGUE_TUNE );
+ pWiring->WireGroup( SOUND_EFFECTS, SOUND_EFFECTS_TUNE );
+ pWiring->WireGroup( MASTER, MASTER_TUNE );
+}
+
+
+} // Sound Namespace
diff --git a/game/code/sound/soundrenderercallback.cpp b/game/code/sound/soundrenderercallback.cpp
new file mode 100644
index 0000000..9f2cfb3
--- /dev/null
+++ b/game/code/sound/soundrenderercallback.cpp
@@ -0,0 +1,181 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundrenderercallback.cpp
+//
+// Description: Implement SoundRenderingPlayerCallback
+//
+// History: 06/07/2002 + Created -- NAME
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/soundrenderercallback.h>
+
+#include <sound/simpsonssoundplayer.h>
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Initialially the list is empty
+//
+SoundRenderingPlayerCallback* radLinkedClass< SoundRenderingPlayerCallback >::s_pLinkedClassHead = NULL;
+SoundRenderingPlayerCallback* radLinkedClass< SoundRenderingPlayerCallback >::s_pLinkedClassTail = NULL;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// SoundRenderingPlayerCallback::SoundRenderingPlayerCallback
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundRenderingPlayerCallback::SoundRenderingPlayerCallback( SimpsonsSoundPlayer& playerObj,
+ SimpsonsSoundPlayerCallback* callbackObj ) :
+ m_callbackObj( callbackObj ),
+ m_playerObj( &playerObj )
+{
+}
+
+//==============================================================================
+// SoundRenderingPlayerCallback::~SoundRenderingPlayerCallback
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+SoundRenderingPlayerCallback::~SoundRenderingPlayerCallback()
+{
+}
+
+//=============================================================================
+// SoundRenderingPlayerCallback::CancelGameCallbackAndRelease
+//=============================================================================
+// Description: Called from the model layer when we're no longer interested
+// in callbacks, probably because the sound player is stopping.
+// Empty out the callback member and release.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundRenderingPlayerCallback::CancelGameCallbackAndRelease()
+{
+ m_callbackObj = NULL;
+ m_playerObj = NULL;
+ Release();
+}
+
+//=============================================================================
+// SoundRenderingPlayerCallback::OnSoundReady
+//=============================================================================
+// Description: Implements function for IDaSoundSoundState interface. Called
+// when the sound renderer player has a sound cued and ready to
+// play.
+//
+// Parameters: pData - user data
+//
+// Return: void
+//
+// Return: void
+//
+//=============================================================================
+void SoundRenderingPlayerCallback::OnSoundReady( void* pData )
+{
+ //
+ // Let the client know that the sound is ready for immediate playback
+ //
+ if( m_callbackObj != NULL )
+ {
+ m_callbackObj->OnSoundReady();
+ }
+}
+
+//=============================================================================
+// SoundRenderingPlayerCallback::OnSoundDone
+//=============================================================================
+// Description: Implements function for IDaSoundSoundState interface. Called
+// when the sound renderer player is finished playing something.
+//
+// Parameters: pData - user data
+//
+// Return: void
+//
+//=============================================================================
+void SoundRenderingPlayerCallback::OnSoundDone( void* pData )
+{
+ SimpsonsSoundPlayerCallback* callbackObj = m_callbackObj;
+
+ //
+ // AddRef so that none of the callback stuff below can wipe us out until
+ // we're done
+ //
+ AddRef();
+
+ //
+ // Trigger the player callback first so that it can clean itself up and
+ // make itself available for the client receiving the callback. Save
+ // a copy of the client callback, since the player might ask us to
+ // wipe it out
+ //
+ if( m_playerObj != NULL )
+ {
+ m_playerObj->OnPlaybackComplete();
+ }
+
+ //
+ // Now the client, who can reuse the same player now
+ //
+ if( callbackObj != NULL )
+ {
+ callbackObj->OnPlaybackComplete();
+ }
+
+ Release();
+}
+
+//=============================================================================
+// SoundRenderingPlayerCallback::CompletionCheck
+//=============================================================================
+// Description: A sanity check, usable by anyone who wants to ensure that all
+// sound players are closed and nobody is waiting around for
+// callbacks anymore. If any SoundRenderingPlayerCallback objects
+// are still kicking around, we fail.
+//
+// Parameters: None
+//
+// Return: void
+//
+//=============================================================================
+void SoundRenderingPlayerCallback::CompletionCheck()
+{
+ rAssertMsg( GetLinkedClassHead() == NULL, "GAAAAAK!! Sound renderer players are still running when they're not supposed to be!\n" );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
diff --git a/game/code/sound/soundrenderercallback.h b/game/code/sound/soundrenderercallback.h
new file mode 100644
index 0000000..e0a4744
--- /dev/null
+++ b/game/code/sound/soundrenderercallback.h
@@ -0,0 +1,70 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: soundrenderercallback.h
+//
+// Description: Declaration of SoundRenderingPlayerCallback class. Used from
+// sound renderer for player-related callbacks.
+//
+// History: 06/07/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef SOUNDRENDERERCALLBACK_H
+#define SOUNDRENDERERCALLBACK_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+#include <radlinkedclass.hpp>
+
+#include <sound/soundrenderer/soundsystem.h>
+
+//========================================
+// Forward References
+//========================================
+
+struct SimpsonsSoundPlayerCallback;
+class SimpsonsSoundPlayer;
+
+//=============================================================================
+//
+// Synopsis: SoundRenderingPlayerCallback
+//
+//=============================================================================
+
+class SoundRenderingPlayerCallback : public Sound::IDaSoundPlayerState,
+ public radLinkedClass< SoundRenderingPlayerCallback >,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "SoundRenderingPlayerCallback" );
+
+ SoundRenderingPlayerCallback( SimpsonsSoundPlayer& playerObj,
+ SimpsonsSoundPlayerCallback* callbackObj );
+ virtual ~SoundRenderingPlayerCallback();
+
+ void CancelGameCallbackAndRelease();
+
+ static void CompletionCheck();
+
+ // Currently unused
+ void OnSoundReady( void* pData );
+
+ // Called when sound renderer player has completed playback
+ void OnSoundDone( void* pData );
+
+ private:
+ //Prevent wasteful constructor creation.
+ SoundRenderingPlayerCallback();
+ SoundRenderingPlayerCallback( const SoundRenderingPlayerCallback& original );
+ SoundRenderingPlayerCallback& operator=( const SoundRenderingPlayerCallback& rhs );
+
+ SimpsonsSoundPlayerCallback* m_callbackObj;
+ SimpsonsSoundPlayer* m_playerObj;
+};
+
+
+#endif // SOUNDRENDERERCALLBACK_H
+
diff --git a/game/code/sound/tuning/allsoundtuning.cpp b/game/code/sound/tuning/allsoundtuning.cpp
new file mode 100644
index 0000000..325a1ca
--- /dev/null
+++ b/game/code/sound/tuning/allsoundtuning.cpp
@@ -0,0 +1 @@
+#include <sound/tuning/globalsettings.cpp>
diff --git a/game/code/sound/tuning/globalsettings.cpp b/game/code/sound/tuning/globalsettings.cpp
new file mode 100644
index 0000000..f6193fc
--- /dev/null
+++ b/game/code/sound/tuning/globalsettings.cpp
@@ -0,0 +1,467 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: globalsettings.cpp
+//
+// Description: Implementation of globalSettings, which sets global sound values
+// in the game (e.g. master volume, sound defaults). Created
+// using RadScript, hence the lower-case g.
+//
+// History: 07/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+//========================================
+// System Includes
+//========================================
+
+//========================================
+// Project Includes
+//========================================
+#include <sound/tuning/globalsettings.h>
+
+#include <sound/soundmanager.h>
+#include <memory/srrmemory.h>
+
+using namespace Sound;
+
+//******************************************************************************
+//
+// Global Data, Local Data, Local Classes
+//
+//******************************************************************************
+
+//
+// Initialially the list is empty
+//
+globalSettings* radLinkedClass< globalSettings >::s_pLinkedClassHead = NULL;
+globalSettings* radLinkedClass< globalSettings >::s_pLinkedClassTail = NULL;
+
+//******************************************************************************
+//
+// Public Member Functions
+//
+//******************************************************************************
+
+//==============================================================================
+// globalSettings::globalSettings
+//==============================================================================
+// Description: Constructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+globalSettings::globalSettings() :
+ radRefCount( 0 ),
+ m_peeloutMin( 0.0f ),
+ m_peeloutMax( 1.0f ),
+ m_peeloutMaxTrim( 1.0f ),
+ m_roadSkidClip( NULL ),
+ m_dirtSkidClip( NULL ),
+ m_roadFootstepClip( NULL ),
+ m_metalFootstepClip( NULL ),
+ m_woodFootstepClip( NULL ),
+ m_coinPitchCount( 0 ),
+ m_ambienceVolume( 0.0f ),
+ m_musicVolume( 0.0f ),
+ m_sfxVolume( 0.0f ),
+ m_dialogueVolume( 0.0f ),
+ m_carVolume( 0.0f )
+{
+ unsigned int i, j;
+
+ for( i = 0; i < NUM_DUCK_SITUATIONS; i++ )
+ {
+ for( j = 0; j < NUM_DUCK_VOLUMES; j++ )
+ {
+ m_duckVolumes[i].duckVolume[j] = 0.0f;
+ }
+ }
+
+ for( i = 0; i < s_maxCoinPitches; i++ )
+ {
+ m_coinPitches[i] = 1.0f;
+ }
+}
+
+//==============================================================================
+// globalSettings::~globalSettings
+//==============================================================================
+// Description: Destructor.
+//
+// Parameters: None.
+//
+// Return: N/A.
+//
+//==============================================================================
+globalSettings::~globalSettings()
+{
+ if( m_roadSkidClip != NULL )
+ {
+ delete( GMA_AUDIO_PERSISTENT, m_roadSkidClip );
+ }
+ if( m_dirtSkidClip != NULL )
+ {
+ delete( GMA_AUDIO_PERSISTENT, m_dirtSkidClip );
+ }
+
+ if( m_roadFootstepClip != NULL )
+ {
+ delete( GMA_AUDIO_PERSISTENT, m_roadFootstepClip );
+ }
+ if( m_metalFootstepClip != NULL )
+ {
+ delete( GMA_AUDIO_PERSISTENT, m_metalFootstepClip );
+ }
+ if( m_woodFootstepClip != NULL )
+ {
+ delete( GMA_AUDIO_PERSISTENT, m_woodFootstepClip );
+ }
+}
+
+//=============================================================================
+// globalSettings::SetMasterVolume
+//=============================================================================
+// Description: Sets master volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetMasterVolume( float volume )
+{
+ GetSoundManager()->SetMasterVolume( volume );
+}
+
+//=============================================================================
+// globalSettings::SetSfxVolume
+//=============================================================================
+// Description: Sets sfx volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetSfxVolume( float volume )
+{
+ m_sfxVolume = volume;
+}
+
+//=============================================================================
+// globalSettings::SetCarVolume
+//=============================================================================
+// Description: Sets car volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetCarVolume( float volume )
+{
+ m_carVolume = volume;
+}
+
+//=============================================================================
+// globalSettings::SetMusicVolume
+//=============================================================================
+// Description: Sets music volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetMusicVolume( float volume )
+{
+ m_musicVolume = volume;
+}
+
+//=============================================================================
+// globalSettings::SetDialogueVolume
+//=============================================================================
+// Description: Sets dialogue volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetDialogueVolume( float volume )
+{
+ m_dialogueVolume = volume;
+}
+
+//=============================================================================
+// globalSettings::SetAmbienceVolume
+//=============================================================================
+// Description: Sets ambience volume, obviously
+//
+// Parameters: volume - new volume level
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetAmbienceVolume( float volume )
+{
+ m_ambienceVolume = volume;
+}
+
+//=============================================================================
+// globalSettings::SetPeeloutMin
+//=============================================================================
+// Description: Set minimum peelout value at which we play sound
+//
+// Parameters: min - peelout value, 0-1
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetPeeloutMin( float min )
+{
+ rAssert( min >= 0.0f );
+ rAssert( min <= 1.0f );
+
+ m_peeloutMin = min;
+}
+
+//=============================================================================
+// globalSettings::SetPeeloutMax
+//=============================================================================
+// Description: Set peelout value at which sound is at maximum volume
+//
+// Parameters: max - peelout value, 0-1
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetPeeloutMax( float max )
+{
+ rAssert( max >= 0.0f );
+ rAssert( max <= 1.0f );
+
+ m_peeloutMax = max;
+}
+
+//=============================================================================
+// globalSettings::SetPeeloutMaxTrim
+//=============================================================================
+// Description: Set maximum trim applied to peelout sound
+//
+// Parameters: trim - max trim value
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetPeeloutMaxTrim( float trim )
+{
+ rAssert( trim >= 0.0f );
+
+ m_peeloutMaxTrim = trim;
+}
+
+//=============================================================================
+// globalSettings::SetSkidRoadClipName
+//=============================================================================
+// Description: Set name of sound resource for road skids
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetSkidRoadClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_roadSkidClip = new char[strlen(clipName)+1];
+ strcpy( m_roadSkidClip, clipName );
+
+ HeapMgr()->PopHeap(GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// globalSettings::SetSkidDirtClipName
+//=============================================================================
+// Description: Set name of sound resource for dirt skids
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetSkidDirtClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_dirtSkidClip = new char[strlen(clipName)+1];
+ strcpy( m_dirtSkidClip, clipName );
+
+ HeapMgr()->PopHeap(GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// globalSettings::SetFootstepRoadClipName
+//=============================================================================
+// Description: Set name of sound resource for footsteps on road surfaces
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetFootstepRoadClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_roadFootstepClip = new char[strlen(clipName)+1];
+ strcpy( m_roadFootstepClip, clipName );
+
+ HeapMgr()->PopHeap(GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// globalSettings::SetFootstepMetalClipName
+//=============================================================================
+// Description: Set name of sound resource for footsteps on metal surfaces
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetFootstepMetalClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_metalFootstepClip = new char[strlen(clipName)+1];
+ strcpy( m_metalFootstepClip, clipName );
+
+ HeapMgr()->PopHeap(GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// globalSettings::SetFootstepWoodClipName
+//=============================================================================
+// Description: Set name of sound resource for footsteps on wood surfaces
+//
+// Parameters: clipName - name of sound resource
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetFootstepWoodClipName( const char* clipName )
+{
+ rAssert( clipName != NULL );
+
+ HeapMgr()->PushHeap( GMA_AUDIO_PERSISTENT );
+
+ m_woodFootstepClip = new char[strlen(clipName)+1];
+ strcpy( m_woodFootstepClip, clipName );
+
+ HeapMgr()->PopHeap(GMA_AUDIO_PERSISTENT);
+}
+
+//=============================================================================
+// globalSettings::SetCoinPitch
+//=============================================================================
+// Description: Set pitch for coin pickup sound in sequence (so we can make
+// a tune out of the coin sounds or something)
+//
+// Parameters: pitch - pitch for next coin playback in sequence
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::SetCoinPitch( float pitch )
+{
+ if( m_coinPitchCount < s_maxCoinPitches )
+ {
+ m_coinPitches[m_coinPitchCount++] = pitch;
+ }
+ else
+ {
+ rDebugString( "Too many coin pitches specified in script\n" );
+ }
+}
+
+//=============================================================================
+// globalSettings::GetCoinPitch
+//=============================================================================
+// Description: Get a particular pitch within coin sequence
+//
+// Parameters: index - index into coin pitch sequence
+//
+// Return: the pitch
+//
+//=============================================================================
+float globalSettings::GetCoinPitch( unsigned int index )
+{
+ rAssert( index < s_maxCoinPitches );
+
+ return( m_coinPitches[index] );
+}
+
+//******************************************************************************
+//
+// Private Member Functions
+//
+//******************************************************************************
+
+//=============================================================================
+// globalSettings::setDuckVolume
+//=============================================================================
+// Description: Store the ducking volume for a particular volume setting and
+// ducking situation
+//
+// Parameters: situation - ducking situation
+// volumeToSet - which volume to set within that situation
+// volume - volume value to set
+//
+// Return: void
+//
+//=============================================================================
+void globalSettings::setDuckVolume( DuckSituations situation, DuckVolumes volumeToSet, float volume )
+{
+ m_duckVolumes[situation].duckVolume[volumeToSet] = volume;
+}
+
+//******************************************************************************
+// Factory functions
+//******************************************************************************
+
+//==============================================================================
+// GlobalSettingsObjCreate
+//==============================================================================
+// Description: Factory function for creating globalSettings objects.
+// Called by RadScript.
+//
+// Parameters: ppParametersObj - Address of ptr to new object
+// allocator - FTT pool to allocate object within
+//
+// Return: N/A.
+//
+//==============================================================================
+void GlobalSettingsObjCreate
+(
+ IGlobalSettings** ppParametersObj,
+ radMemoryAllocator allocator
+)
+{
+ rAssert( ppParametersObj != NULL );
+ (*ppParametersObj) = new ( allocator ) globalSettings( );
+ (*ppParametersObj)->AddRef( );
+}
+
diff --git a/game/code/sound/tuning/globalsettings.h b/game/code/sound/tuning/globalsettings.h
new file mode 100644
index 0000000..13b8417
--- /dev/null
+++ b/game/code/sound/tuning/globalsettings.h
@@ -0,0 +1,224 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: globalsettings.h
+//
+// Description: Declaration of globalSettings, which sets global sound values
+// in the game (e.g. master volume, sound defaults). Created
+// using RadScript, hence the lower-case g.
+//
+// History: 07/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef GLOBALSETTINGS_H
+#define GLOBALSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radlinkedclass.hpp>
+
+#include <sound/tuning/iglobalsettings.h>
+#include <sound/soundrenderer/dasoundgroup.h>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: globalSettings
+//
+//=============================================================================
+
+class globalSettings : public IGlobalSettings,
+ public radLinkedClass< globalSettings >,
+ public radRefCount
+{
+ public:
+ IMPLEMENT_REFCOUNTED( "globalSettings" );
+
+ globalSettings();
+ virtual ~globalSettings();
+
+ //
+ // Volume controls
+ //
+ void SetMasterVolume( float volume );
+
+ void SetSfxVolume( float volume );
+ float GetSfxVolume() { return( m_sfxVolume ); }
+
+ void SetCarVolume( float volume );
+ float GetCarVolume() { return( m_carVolume ); }
+
+ void SetMusicVolume( float volume );
+ float GetMusicVolume() { return( m_musicVolume ); }
+
+ void SetDialogueVolume( float volume );
+ float GetDialogueVolume() { return( m_dialogueVolume ); }
+
+ void SetAmbienceVolume( float volume );
+ float GetAmbienceVolume() { return( m_ambienceVolume ); }
+
+ //
+ // Ducking controls
+ //
+ float GetDuckVolume( Sound::DuckSituations situation, Sound::DuckVolumes volume ) { return( m_duckVolumes[situation].duckVolume[volume] ); }
+
+ void SetPauseSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_PAUSE, Sound::DUCK_SFX, volume ); }
+ void SetPauseCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_PAUSE, Sound::DUCK_CAR, volume ); }
+ void SetPauseMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_PAUSE, Sound::DUCK_MUSIC, volume ); }
+ void SetPauseDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_PAUSE, Sound::DUCK_DIALOG, volume ); }
+ void SetPauseAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_PAUSE, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetMissionScreenSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MISSION, Sound::DUCK_SFX, volume ); }
+ void SetMissionScreenCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MISSION, Sound::DUCK_CAR, volume ); }
+ void SetMissionScreenMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MISSION, Sound::DUCK_MUSIC, volume ); }
+ void SetMissionScreenDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MISSION, Sound::DUCK_DIALOG, volume ); }
+ void SetMissionScreenAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MISSION, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetLetterboxSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_LETTERBOX, Sound::DUCK_SFX, volume ); }
+ void SetLetterboxCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_LETTERBOX, Sound::DUCK_CAR, volume ); }
+ void SetLetterboxMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_LETTERBOX, Sound::DUCK_MUSIC, volume ); }
+ void SetLetterboxDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_LETTERBOX, Sound::DUCK_DIALOG, volume ); }
+ void SetLetterboxAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_LETTERBOX, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetDialogueSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_DIALOG, Sound::DUCK_SFX, volume ); }
+ void SetDialogueCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_DIALOG, Sound::DUCK_CAR, volume ); }
+ void SetDialogueMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_DIALOG, Sound::DUCK_MUSIC, volume ); }
+ void SetDialogueDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_DIALOG, Sound::DUCK_DIALOG, volume ); }
+ void SetDialogueAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_DIALOG, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetStoreSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_STORE, Sound::DUCK_SFX, volume ); }
+ void SetStoreCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_STORE, Sound::DUCK_CAR, volume ); }
+ void SetStoreMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_STORE, Sound::DUCK_MUSIC, volume ); }
+ void SetStoreDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_STORE, Sound::DUCK_DIALOG, volume ); }
+ void SetStoreAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_STORE, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetOnFootSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_ONFOOT, Sound::DUCK_SFX, volume ); }
+ void SetOnFootCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_ONFOOT, Sound::DUCK_CAR, volume ); }
+ void SetOnFootMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_ONFOOT, Sound::DUCK_MUSIC, volume ); }
+ void SetOnFootDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_ONFOOT, Sound::DUCK_DIALOG, volume ); }
+ void SetOnFootAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_ONFOOT, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetMinigameSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MINIGAME, Sound::DUCK_SFX, volume ); }
+ void SetMinigameCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MINIGAME, Sound::DUCK_CAR, volume ); }
+ void SetMinigameMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MINIGAME, Sound::DUCK_MUSIC, volume ); }
+ void SetMinigameDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MINIGAME, Sound::DUCK_DIALOG, volume ); }
+ void SetMinigameAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_MINIGAME, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetJustMusicSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_JUST_MUSIC, Sound::DUCK_SFX, volume ); }
+ void SetJustMusicCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_JUST_MUSIC, Sound::DUCK_CAR, volume ); }
+ void SetJustMusicMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_JUST_MUSIC, Sound::DUCK_MUSIC, volume ); }
+ void SetJustMusicDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_JUST_MUSIC, Sound::DUCK_DIALOG, volume ); }
+ void SetJustMusicAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_JUST_MUSIC, Sound::DUCK_AMBIENCE, volume ); }
+
+ void SetCreditsSfxVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_CREDITS, Sound::DUCK_SFX, volume ); }
+ void SetCreditsCarVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_CREDITS, Sound::DUCK_CAR, volume ); }
+ void SetCreditsMusicVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_CREDITS, Sound::DUCK_MUSIC, volume ); }
+ void SetCreditsDialogueVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_CREDITS, Sound::DUCK_DIALOG, volume ); }
+ void SetCreditsAmbienceVolume( float volume ) { setDuckVolume( Sound::DUCK_SIT_CREDITS, Sound::DUCK_AMBIENCE, volume ); }
+
+ //
+ // Car controls
+ //
+ void SetPeeloutMin( float min );
+ float GetPeeloutMin() { return( m_peeloutMin ); }
+
+ void SetPeeloutMax( float max );
+ float GetPeeloutMax() { return( m_peeloutMax ); }
+
+ void SetPeeloutMaxTrim( float trim );
+ float GetPeeloutMaxTrim() { return( m_peeloutMaxTrim ); }
+
+ void SetSkidRoadClipName( const char* clipName );
+ const char* GetSkidRoadClipName() { return( m_roadSkidClip ); }
+
+ void SetSkidDirtClipName( const char* clipName );
+ const char* GetSkidDirtClipName() { return( m_dirtSkidClip ); }
+
+ //
+ // Footstep sounds
+ //
+ void SetFootstepRoadClipName( const char* clipName );
+ const char* GetFootstepRoadClipName() { return( m_roadFootstepClip ); }
+
+ void SetFootstepMetalClipName( const char* clipName );
+ const char* GetFootstepMetalClipName() { return( m_metalFootstepClip ); }
+
+ void SetFootstepWoodClipName( const char* clipName );
+ const char* GetFootstepWoodClipName() { return( m_woodFootstepClip ); }
+
+ //
+ // Coin pitches
+ //
+ void SetCoinPitch( float pitch );
+ float GetCoinPitch( unsigned int index );
+ unsigned int GetNumCoinPitches() { return( m_coinPitchCount ); }
+
+ private:
+
+ //Prevent wasteful constructor creation.
+ globalSettings( const globalSettings& original );
+ globalSettings& operator=( const globalSettings& rhs );
+
+ void setDuckVolume( Sound::DuckSituations situation, Sound::DuckVolumes volumeToSet, float volume );
+
+ //
+ // Ducking settings
+ //
+ Sound::DuckVolumeSet m_duckVolumes[Sound::NUM_DUCK_SITUATIONS];
+
+ //
+ // Car settings
+ //
+ float m_peeloutMin;
+ float m_peeloutMax;
+ float m_peeloutMaxTrim;
+
+ char* m_roadSkidClip;
+ char* m_dirtSkidClip;
+
+ //
+ // Footsteps
+ //
+ char* m_roadFootstepClip;
+ char* m_metalFootstepClip;
+ char* m_woodFootstepClip;
+
+ //
+ // Coin pitches
+ //
+ static const unsigned int s_maxCoinPitches = 10;
+ float m_coinPitches[s_maxCoinPitches];
+ unsigned int m_coinPitchCount;
+
+ //
+ // Hack!!
+ //
+ float m_ambienceVolume;
+ float m_musicVolume;
+ float m_sfxVolume;
+ float m_dialogueVolume;
+ float m_carVolume;
+};
+
+//=============================================================================
+// Factory Functions
+//=============================================================================
+
+//
+// Create a CarSoundParameters object
+//
+void GlobalSettingsObjCreate
+(
+ IGlobalSettings** ppSoundResource,
+ radMemoryAllocator allocator
+);
+
+
+
+#endif // GLOBALSETTINGS_H
+
diff --git a/game/code/sound/tuning/iglobalsettings.h b/game/code/sound/tuning/iglobalsettings.h
new file mode 100644
index 0000000..3fac89c
--- /dev/null
+++ b/game/code/sound/tuning/iglobalsettings.h
@@ -0,0 +1,128 @@
+//=============================================================================
+// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
+//
+// File: iglobalsettings.h
+//
+// Description: Declaration of interface class IGlobalSettings, which sets
+// global sound values in the game (e.g. master volume,
+// sound defaults). Created using RadScript.
+//
+// History: 07/08/2002 + Created -- Darren
+//
+//=============================================================================
+
+#ifndef IGLOBALSETTINGS_H
+#define IGLOBALSETTINGS_H
+
+//========================================
+// Nested Includes
+//========================================
+#include <radobject.hpp>
+
+//========================================
+// Forward References
+//========================================
+
+//=============================================================================
+//
+// Synopsis: IGlobalSettings
+//
+//=============================================================================
+
+class IGlobalSettings : public IRefCount
+{
+ public:
+ //
+ // Volume controls
+ //
+ virtual void SetMasterVolume( float volume ) = 0;
+
+ virtual void SetSfxVolume( float volume ) = 0;
+ virtual void SetCarVolume( float volume ) = 0;
+ virtual void SetMusicVolume( float volume ) = 0;
+ virtual void SetDialogueVolume( float volume ) = 0;
+ virtual void SetAmbienceVolume( float volume ) = 0;
+
+ //
+ // Ducking controls
+ //
+ virtual void SetPauseSfxVolume( float volume ) = 0;
+ virtual void SetPauseCarVolume( float volume ) = 0;
+ virtual void SetPauseMusicVolume( float volume ) = 0;
+ virtual void SetPauseDialogueVolume( float volume ) = 0;
+ virtual void SetPauseAmbienceVolume( float volume ) = 0;
+
+ virtual void SetMissionScreenSfxVolume( float volume ) = 0;
+ virtual void SetMissionScreenCarVolume( float volume ) = 0;
+ virtual void SetMissionScreenMusicVolume( float volume ) = 0;
+ virtual void SetMissionScreenDialogueVolume( float volume ) = 0;
+ virtual void SetMissionScreenAmbienceVolume( float volume ) = 0;
+
+ virtual void SetLetterboxSfxVolume( float volume ) = 0;
+ virtual void SetLetterboxCarVolume( float volume ) = 0;
+ virtual void SetLetterboxMusicVolume( float volume ) = 0;
+ virtual void SetLetterboxDialogueVolume( float volume ) = 0;
+ virtual void SetLetterboxAmbienceVolume( float volume ) = 0;
+
+ virtual void SetDialogueSfxVolume( float volume ) = 0;
+ virtual void SetDialogueCarVolume( float volume ) = 0;
+ virtual void SetDialogueMusicVolume( float volume ) = 0;
+ virtual void SetDialogueDialogueVolume( float volume ) = 0;
+ virtual void SetDialogueAmbienceVolume( float volume ) = 0;
+
+ virtual void SetStoreSfxVolume( float volume ) = 0;
+ virtual void SetStoreCarVolume( float volume ) = 0;
+ virtual void SetStoreMusicVolume( float volume ) = 0;
+ virtual void SetStoreDialogueVolume( float volume ) = 0;
+ virtual void SetStoreAmbienceVolume( float volume ) = 0;
+
+ virtual void SetOnFootSfxVolume( float volume ) = 0;
+ virtual void SetOnFootCarVolume( float volume ) = 0;
+ virtual void SetOnFootMusicVolume( float volume ) = 0;
+ virtual void SetOnFootDialogueVolume( float volume ) = 0;
+ virtual void SetOnFootAmbienceVolume( float volume ) = 0;
+
+ virtual void SetMinigameSfxVolume( float volume ) = 0;
+ virtual void SetMinigameCarVolume( float volume ) = 0;
+ virtual void SetMinigameMusicVolume( float volume ) = 0;
+ virtual void SetMinigameDialogueVolume( float volume ) = 0;
+ virtual void SetMinigameAmbienceVolume( float volume ) = 0;
+
+ virtual void SetJustMusicSfxVolume( float volume ) = 0;
+ virtual void SetJustMusicCarVolume( float volume ) = 0;
+ virtual void SetJustMusicMusicVolume( float volume ) = 0;
+ virtual void SetJustMusicDialogueVolume( float volume ) = 0;
+ virtual void SetJustMusicAmbienceVolume( float volume ) = 0;
+
+ virtual void SetCreditsSfxVolume( float volume ) = 0;
+ virtual void SetCreditsCarVolume( float volume ) = 0;
+ virtual void SetCreditsMusicVolume( float volume ) = 0;
+ virtual void SetCreditsDialogueVolume( float volume ) = 0;
+ virtual void SetCreditsAmbienceVolume( float volume ) = 0;
+
+ //
+ // Car controls
+ //
+ virtual void SetPeeloutMin( float min ) = 0;
+ virtual void SetPeeloutMax( float max ) = 0;
+ virtual void SetPeeloutMaxTrim( float trim ) = 0;
+
+ virtual void SetSkidRoadClipName( const char* clipName ) = 0;
+ virtual void SetSkidDirtClipName( const char* clipName ) = 0;
+
+ //
+ // Footstep sounds
+ //
+ virtual void SetFootstepRoadClipName( const char* clipName ) = 0;
+ virtual void SetFootstepMetalClipName( const char* clipName ) = 0;
+ virtual void SetFootstepWoodClipName( const char* clipName ) = 0;
+
+ //
+ // Coin pitches
+ //
+ virtual void SetCoinPitch( float pitch ) = 0;
+};
+
+
+#endif // IGLOBALSETTINGS_H
+