You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
16 KiB
510 lines
16 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "engine/IEngineSound.h" |
|
#include "tier0/dbg.h" |
|
#include "sound.h" |
|
#include "client.h" |
|
#include "vox.h" |
|
#include "icliententity.h" |
|
#include "icliententitylist.h" |
|
#include "enginesingleuserfilter.h" |
|
#include "snd_audio_source.h" |
|
#if defined(_X360) |
|
#include "xmp.h" |
|
#endif |
|
#include "tier0/vprof.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// HACK: expose in sound.h maybe? |
|
void DSP_FastReset(int dsp); |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// Client-side implementation of the engine sound interface |
|
// |
|
//----------------------------------------------------------------------------- |
|
class CEngineSoundClient : public IEngineSound |
|
{ |
|
public: |
|
// constructor, destructor |
|
CEngineSoundClient(); |
|
virtual ~CEngineSoundClient(); |
|
|
|
virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound ); |
|
virtual bool IsSoundPrecached( const char *pSample ); |
|
virtual void PrefetchSound( const char *pSample ); |
|
|
|
virtual float GetSoundDuration( const char *pSample ); |
|
|
|
virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 ); |
|
|
|
virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 ); |
|
|
|
virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, |
|
float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 ); |
|
|
|
virtual void StopSound( int iEntIndex, int iChannel, const char *pSample ); |
|
|
|
virtual void StopAllSounds(bool bClearBuffers); |
|
|
|
virtual void SetRoomType( IRecipientFilter& filter, int roomType ); |
|
virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset ); |
|
|
|
virtual void EmitAmbientSound( const char *pSample, float flVolume, |
|
int iPitch, int flags, float soundtime = 0.0f ); |
|
|
|
virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist ); |
|
|
|
// Client .dll only functions |
|
virtual int GetGuidForLastSoundEmitted(); |
|
virtual bool IsSoundStillPlaying( int guid ); |
|
virtual void StopSoundByGuid( int guid ); |
|
// Set's master volume (0.0->1.0) |
|
virtual void SetVolumeByGuid( int guid, float fvol ); |
|
|
|
// Retrieves list of all active sounds |
|
virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist ); |
|
|
|
virtual void PrecacheSentenceGroup( const char *pGroupName ); |
|
virtual void NotifyBeginMoviePlayback(); |
|
virtual void NotifyEndMoviePlayback(); |
|
|
|
private: |
|
void EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 ); |
|
|
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Client-server neutral sound interface accessor |
|
//----------------------------------------------------------------------------- |
|
static CEngineSoundClient s_EngineSoundClient; |
|
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundClient, IEngineSound, |
|
IENGINESOUND_CLIENT_INTERFACE_VERSION, s_EngineSoundClient ); |
|
|
|
IEngineSound *EngineSoundClient() |
|
{ |
|
return &s_EngineSoundClient; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// constructor, destructor |
|
//----------------------------------------------------------------------------- |
|
CEngineSoundClient::CEngineSoundClient() |
|
{ |
|
} |
|
|
|
CEngineSoundClient::~CEngineSoundClient() |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Precache a particular sample |
|
//----------------------------------------------------------------------------- |
|
bool CEngineSoundClient::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound ) |
|
{ |
|
CSfxTable *pTable = S_PrecacheSound( pSample ); |
|
if ( pTable ) |
|
{ |
|
if ( bIsUISound ) |
|
{ |
|
S_MarkUISound( pTable ); |
|
} |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pSample - |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::PrefetchSound( const char *pSample ) |
|
{ |
|
S_PrefetchSound( pSample, true ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pSample - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CEngineSoundClient::IsSoundPrecached( const char *pSample ) |
|
{ |
|
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) ) |
|
{ |
|
return true; |
|
} |
|
|
|
int idx = cl.LookupSoundIndex( pSample ); |
|
if ( idx == -1 ) |
|
return false; |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Actually does the work of emitting a sound |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ ) |
|
{ |
|
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); |
|
if (flVolume < 0 || flVolume > 1) |
|
{ |
|
Warning ("EmitSound: volume out of bounds = %f\n", flVolume); |
|
return; |
|
} |
|
|
|
if ( ( iSoundLevel < soundlevel_t(MIN_SNDLVL_VALUE) ) || ( iSoundLevel > soundlevel_t(MAX_SNDLVL_VALUE) ) ) |
|
{ |
|
Warning ("EmitSound: soundlevel out of bounds = %d\n", iSoundLevel); |
|
return; |
|
} |
|
|
|
if (iPitch < 0 || iPitch > 255) |
|
{ |
|
Warning ("EmitSound: pitch out of bounds = %i\n", iPitch); |
|
return; |
|
} |
|
|
|
int iSoundSource = iEntIndex; |
|
|
|
// Handle client UI sounds |
|
if ( iSoundSource != SOUND_FROM_UI_PANEL ) |
|
{ |
|
if (iSoundSource < 0) |
|
iSoundSource = cl.m_nViewEntity; |
|
|
|
// See if local player is a recipient |
|
int i = 0; |
|
int c = filter.GetRecipientCount(); |
|
for ( ; i < c ; i++ ) |
|
{ |
|
int index = filter.GetRecipientIndex( i ); |
|
if ( index == cl.m_nPlayerSlot + 1 ) |
|
break; |
|
} |
|
|
|
// Local player not receiving sound |
|
if ( i >= c ) |
|
return; |
|
} |
|
|
|
CSfxTable *pSound = S_PrecacheSound(pSample); |
|
if (!pSound) |
|
return; |
|
|
|
Vector vecDummyOrigin; |
|
Vector vecDirection; |
|
if ( iSoundSource == SOUND_FROM_UI_PANEL ) |
|
{ |
|
vecDummyOrigin.Init(); |
|
vecDirection.Init(); |
|
pOrigin = &vecDummyOrigin; |
|
pDirection = &vecDirection; |
|
} |
|
else |
|
{ |
|
// Point at origin if they didn't specify a sound source. |
|
if (!pOrigin) |
|
{ |
|
// Try to use the origin of the entity |
|
IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex ); |
|
// don't update position if we stop this sound |
|
if (pEnt && !(iFlags & SND_STOP) ) |
|
{ |
|
vecDummyOrigin = pEnt->GetRenderOrigin(); |
|
} |
|
else |
|
{ |
|
vecDummyOrigin.Init(); |
|
} |
|
|
|
pOrigin = &vecDummyOrigin; |
|
} |
|
|
|
if (!pDirection) |
|
{ |
|
IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex ); |
|
if (pEnt && !(iFlags & SND_STOP)) |
|
{ |
|
QAngle angles; |
|
angles = pEnt->GetAbsAngles(); |
|
AngleVectors( angles, &vecDirection ); |
|
} |
|
else |
|
{ |
|
vecDirection.Init(); |
|
} |
|
|
|
pDirection = &vecDirection; |
|
} |
|
} |
|
|
|
if ( pUtlVecOrigins ) |
|
{ |
|
(*pUtlVecOrigins).AddToTail( *pOrigin ); |
|
} |
|
|
|
float delay = 0.0f; |
|
if ( soundtime != 0.0f ) |
|
{ |
|
// this sound was played directly on the client, use its clock sync |
|
delay = S_ComputeDelayForSoundtime( soundtime, CLOCK_SYNC_CLIENT ); |
|
#if 0 |
|
static float lastSoundTime = 0; |
|
Msg("[%.3f] Play %s at %.3f %.1fsms delay\n", soundtime - lastSoundTime, pSample, soundtime, delay * 1000.0f ); |
|
lastSoundTime = soundtime; |
|
#endif |
|
// anything over 250ms is assumed to be intentional skipping |
|
if ( delay <= 0 && delay > -0.250f ) |
|
{ |
|
// leave a little delay to flag the channel in the low-level sound system |
|
delay = 1e-6f; |
|
} |
|
} |
|
|
|
StartSoundParams_t params; |
|
params.staticsound = iChannel == CHAN_STATIC; |
|
params.soundsource = iSoundSource; |
|
params.entchannel = iChannel; |
|
params.pSfx = pSound; |
|
params.origin = *pOrigin; |
|
params.direction = *pDirection; |
|
params.bUpdatePositions = bUpdatePositions; |
|
params.fvol = flVolume; |
|
params.soundlevel = iSoundLevel; |
|
params.flags = iFlags; |
|
params.pitch = iPitch; |
|
params.specialdsp = iSpecialDSP; |
|
params.fromserver = false; |
|
params.delay = delay; |
|
params.speakerentity = speakerentity; |
|
|
|
S_StartSound( params ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Plays a sentence |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, |
|
int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePosition, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ ) |
|
{ |
|
if ( iSentenceIndex >= 0 ) |
|
{ |
|
char pName[8]; |
|
Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex ); |
|
EmitSoundInternal( filter, iEntIndex, iChannel, pName, flVolume, iSoundLevel, |
|
iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePosition, soundtime, speakerentity ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Emits a sound |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ ) |
|
{ |
|
VPROF( "CEngineSoundClient::EmitSound" ); |
|
EmitSound( filter, iEntIndex, iChannel, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), iFlags, |
|
iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity ); |
|
|
|
} |
|
|
|
|
|
void CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample, |
|
float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP, |
|
const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ ) |
|
{ |
|
VPROF( "CEngineSoundClient::EmitSound" ); |
|
if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) ) |
|
{ |
|
int iSentenceIndex = -1; |
|
VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex ); |
|
if (iSentenceIndex >= 0) |
|
{ |
|
EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume, |
|
iSoundLevel, iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity ); |
|
} |
|
else |
|
{ |
|
DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample)); |
|
} |
|
} |
|
else |
|
{ |
|
EmitSoundInternal( filter, iEntIndex, iChannel, pSample, flVolume, iSoundLevel, |
|
iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Stops a sound |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::StopSound( int iEntIndex, int iChannel, const char *pSample ) |
|
{ |
|
CEngineSingleUserFilter filter( cl.m_nPlayerSlot + 1 ); |
|
EmitSound( filter, iEntIndex, iChannel, pSample, 0, SNDLVL_NONE, SND_STOP, PITCH_NORM, 0, |
|
NULL, NULL, NULL, true ); |
|
} |
|
|
|
|
|
void CEngineSoundClient::SetRoomType( IRecipientFilter& filter, int roomType ) |
|
{ |
|
extern ConVar dsp_room; |
|
dsp_room.SetValue( roomType ); |
|
} |
|
|
|
void CEngineSoundClient::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset ) |
|
{ |
|
extern ConVar dsp_player; |
|
dsp_player.SetValue( dspType ); |
|
if ( fastReset ) |
|
{ |
|
DSP_FastReset( dspType ); |
|
} |
|
} |
|
|
|
|
|
void CEngineSoundClient::EmitAmbientSound( const char *pSample, float flVolume, |
|
int iPitch, int flags, float soundtime /*= 0.0f*/ ) |
|
{ |
|
float delay = 0.0f; |
|
if ( soundtime != 0.0f ) |
|
{ |
|
delay = soundtime - cl.m_flLastServerTickTime; |
|
} |
|
|
|
CSfxTable *pSound = S_PrecacheSound(pSample); |
|
|
|
StartSoundParams_t params; |
|
params.staticsound = true; |
|
params.soundsource = SOUND_FROM_LOCAL_PLAYER; |
|
params.entchannel = CHAN_STATIC; |
|
params.pSfx = pSound; |
|
params.origin = vec3_origin; |
|
params.fvol = flVolume; |
|
params.soundlevel = SNDLVL_NONE; |
|
params.flags = flags; |
|
params.pitch = iPitch; |
|
params.specialdsp = 0; |
|
params.fromserver = false; |
|
params.delay = delay; |
|
|
|
S_StartSound( params ); |
|
} |
|
|
|
void CEngineSoundClient::StopAllSounds(bool bClearBuffers) |
|
{ |
|
S_StopAllSounds( bClearBuffers ); |
|
} |
|
|
|
float CEngineSoundClient::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist ) |
|
{ |
|
return S_GetGainFromSoundLevel( soundlevel, dist ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : *pSample - |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float CEngineSoundClient::GetSoundDuration( const char *pSample ) |
|
{ |
|
return AudioSource_GetSoundDuration( pSample ); |
|
} |
|
|
|
// Client .dll only functions |
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int CEngineSoundClient::GetGuidForLastSoundEmitted() |
|
{ |
|
return S_GetGuidForLastSoundEmitted(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : guid - |
|
// Output : Returns true on success, false on failure. |
|
//----------------------------------------------------------------------------- |
|
bool CEngineSoundClient::IsSoundStillPlaying( int guid ) |
|
{ |
|
return S_IsSoundStillPlaying( guid ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : guid - |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::StopSoundByGuid( int guid ) |
|
{ |
|
S_StopSoundByGuid( guid ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Retrieves list of all active sounds |
|
// Input : sndlist - |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::GetActiveSounds( CUtlVector< SndInfo_t >& sndlist ) |
|
{ |
|
S_GetActiveSounds( sndlist ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set's master volume (0.0->1.0) |
|
// Input : guid - |
|
// fvol - |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::SetVolumeByGuid( int guid, float fvol ) |
|
{ |
|
S_SetVolumeByGuid( guid, fvol ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CEngineSoundClient::PrecacheSentenceGroup( const char *pGroupName ) |
|
{ |
|
VOX_PrecacheSentenceGroup( this, pGroupName ); |
|
} |
|
|
|
void CEngineSoundClient::NotifyBeginMoviePlayback() |
|
{ |
|
StopAllSounds(true); |
|
#if _X360 |
|
XMPOverrideBackgroundMusic(); |
|
#endif |
|
} |
|
|
|
void CEngineSoundClient::NotifyEndMoviePlayback() |
|
{ |
|
#if _X360 |
|
XMPRestoreBackgroundMusic(); |
|
#endif |
|
} |
|
|
|
|