diff options
Diffstat (limited to 'game/code/sound/soundrenderer')
32 files changed, 12006 insertions, 0 deletions
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 = ¤tVolumes; + + 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, + ¤tVolumes ); +} + +//============================================================================= +// 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 |