summaryrefslogtreecommitdiff
path: root/engine/engsoundservice.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/engsoundservice.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/engsoundservice.cpp')
-rw-r--r--engine/engsoundservice.cpp539
1 files changed, 539 insertions, 0 deletions
diff --git a/engine/engsoundservice.cpp b/engine/engsoundservice.cpp
new file mode 100644
index 0000000..079910f
--- /dev/null
+++ b/engine/engsoundservice.cpp
@@ -0,0 +1,539 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Engine implementation of services required by the audio subsystem
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "quakedef.h"
+#include "soundservice.h"
+#include "zone.h"
+#include "cdll_engine_int.h"
+#include "gl_model_private.h"
+#include "icliententity.h"
+#include "icliententitylist.h"
+#include "mouthinfo.h"
+#include "host.h"
+#include "vstdlib/random.h"
+#include "tier0/icommandline.h"
+#include "igame.h"
+#include "client.h"
+#include "server.h"
+#include "filesystem.h"
+#include "filesystem_engine.h"
+#include "sound.h"
+#include "vgui_controls/Controls.h"
+#include "vgui/ILocalize.h"
+#include "vgui_baseui_interface.h"
+#include "datacache/idatacache.h"
+#include "sys_dll.h"
+#include "toolframework/itoolframework.h"
+#include "tier0/vprof.h"
+#include "cl_steamauth.h"
+#include "tier1/fmtstr.h"
+#include "MapReslistGenerator.h"
+#include "cl_main.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+void Snd_Restart_f();
+
+#define MAPLIST_FILE "maplist.txt"
+
+class CEngineSoundServices : public ISoundServices
+{
+public:
+ CEngineSoundServices() { m_frameTime = 0; }
+
+ virtual void *LevelAlloc( int nBytes, const char *pszTag )
+ {
+ return Hunk_AllocName(nBytes, pszTag);
+ }
+
+ virtual void OnExtraUpdate()
+ {
+ if ( IsPC() && g_ClientDLL && game && game->IsActiveApp() )
+ {
+ g_ClientDLL->IN_Accumulate();
+ }
+ }
+
+ virtual bool GetSoundSpatialization( int entIndex, SpatializationInfo_t& info )
+ {
+ if ( !entitylist )
+ {
+ return false;
+ }
+
+ // Entity has been deleted
+ IClientEntity *pClientEntity = entitylist->GetClientEntity( entIndex );
+ if ( !pClientEntity )
+ {
+ // FIXME: Should this assert?
+ return false;
+ }
+
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+ bool bResult = pClientEntity->GetSoundSpatialization( info );
+
+ return bResult;
+ }
+
+ virtual bool GetToolSpatialization( int iUserData, int guid, SpatializationInfo_t& info )
+ {
+ if ( IsX360() )
+ {
+ return false;
+ }
+
+ return toolframework->GetSoundSpatialization( iUserData, guid, info );
+ }
+
+ virtual float GetClientTime()
+ {
+ return cl.GetTime();
+ }
+
+ // Filtered local time
+ virtual float GetHostTime()
+ {
+ return host_time;
+ }
+
+ virtual int GetViewEntity()
+ {
+ return cl.m_nViewEntity;
+ }
+
+ virtual void SetSoundFrametime( float realDt, float hostDt )
+ {
+ extern bool IsReplayRendering();
+ if ( cl_movieinfo.IsRecording() || IsReplayRendering() )
+ {
+ m_frameTime = hostDt;
+ }
+ else
+ {
+ m_frameTime = realDt;
+ }
+ }
+
+ virtual float GetHostFrametime()
+ {
+ return m_frameTime;
+ }
+
+ virtual int GetServerCount()
+ {
+ return cl.m_nServerCount;
+ }
+
+ virtual bool IsPlayer( SoundSource source )
+ {
+ return ( source == cl.m_nPlayerSlot + 1 );
+ }
+
+ virtual void OnChangeVoiceStatus( int entity, bool status)
+ {
+ ClientDLL_VoiceStatus(entity, status);
+ }
+
+ virtual bool IsConnected()
+ {
+ return cl.IsConnected();
+ }
+
+ // Calls into client .dll with list of close caption tokens to construct a caption out of
+ virtual void EmitSentenceCloseCaption( char const *tokenstream )
+ {
+ if ( g_ClientDLL )
+ {
+ g_ClientDLL->EmitSentenceCloseCaption( tokenstream );
+ }
+ }
+
+ virtual void EmitCloseCaption( char const *captionname, float duration )
+ {
+ if ( g_ClientDLL )
+ {
+ g_ClientDLL->EmitCloseCaption( captionname, duration );
+ }
+ }
+
+ virtual char const *GetGameDir()
+ {
+ return com_gamedir;
+ }
+
+ // If the game is paused, certain audio will pause, too (anything with phoneme/sentence data for now)
+ virtual bool IsGamePaused()
+ {
+ extern IVEngineClient *engineClient;
+ if ( !engineClient )
+ {
+ Assert( !"No engineClient, bug???" );
+ return false;
+ }
+
+ return engineClient->IsPaused();
+ }
+
+ virtual bool IsGameActive()
+ {
+ extern IVEngineClient *engineClient;
+ if ( !engineClient )
+ {
+ Assert( !"No engineClient, bug???" );
+ return true;
+ }
+
+ return engineClient->IsActiveApp();
+ }
+
+ virtual void RestartSoundSystem()
+ {
+ Snd_Restart_f();
+ }
+
+ virtual void GetAllManifestFiles( CUtlRBTree< FileNameHandle_t, int >& list )
+ {
+ list.RemoveAll();
+
+ // Load them in
+ FileHandle_t resfilehandle = g_pFileSystem->Open( MAPLIST_FILE, "rb", "MOD" );
+ if ( FILESYSTEM_INVALID_HANDLE != resfilehandle )
+ {
+ // Read in and parse mapcycle.txt
+ int length = g_pFileSystem->Size(resfilehandle);
+ if ( length > 0 )
+ {
+ char *pStart = (char *)new char[ length + 1 ];
+ if ( pStart && ( length == g_pFileSystem->Read(pStart, length, resfilehandle) )
+ )
+ {
+ pStart[ length ] = 0;
+ const char *pFileList = pStart;
+
+ while ( 1 )
+ {
+ pFileList = COM_Parse( pFileList );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ char manifest_file[ 512 ];
+ Q_snprintf( manifest_file, sizeof( manifest_file ), "%s/%s.manifest", AUDIOSOURCE_CACHE_ROOTDIR, com_token );
+
+ if ( g_pFileSystem->FileExists( manifest_file, "MOD" ) )
+ {
+ FileNameHandle_t handle = g_pFileSystem->FindOrAddFileName( manifest_file );
+ if ( list.Find( handle ) == list.InvalidIndex() )
+ {
+ list.Insert( handle );
+ }
+ }
+
+ // Any more tokens on this line?
+ while ( COM_TokenWaiting( pFileList ) )
+ {
+ pFileList = COM_Parse( pFileList );
+ }
+ }
+ }
+ delete[] pStart;
+ }
+
+ g_pFileSystem->Close(resfilehandle);
+ }
+ else
+ {
+ Warning( "GetAllManifestFiles: Unable to load %s\n", MAPLIST_FILE );
+ }
+ }
+
+ virtual void GetAllSoundFilesInManifest( CUtlRBTree< FileNameHandle_t, int >& list, char const *manifestfile )
+ {
+ list.RemoveAll();
+ CacheSoundsFromResFile( true, list, manifestfile, false );
+ }
+
+ virtual void GetAllSoundFilesReferencedInReslists( CUtlRBTree< FileNameHandle_t, int >& list )
+ {
+ char reslistdir[ MAX_PATH ];
+ Q_strncpy( reslistdir, MapReslistGenerator().GetResListDirectory(), sizeof( reslistdir ) );
+ list.RemoveAll();
+
+ // Load them in
+ FileHandle_t resfilehandle = g_pFileSystem->Open( MAPLIST_FILE, "rb", "MOD" );
+ if ( FILESYSTEM_INVALID_HANDLE != resfilehandle )
+ {
+ // Read in and parse mapcycle.txt
+ int length = g_pFileSystem->Size(resfilehandle);
+ if ( length > 0 )
+ {
+ char *pStart = (char *)new char[ length + 1 ];
+ if ( pStart && ( length == g_pFileSystem->Read(pStart, length, resfilehandle) )
+ )
+ {
+ pStart[ length ] = 0;
+ const char *pFileList = pStart;
+
+ while ( 1 )
+ {
+ char resfile[ 512 ];
+
+ pFileList = COM_Parse( pFileList );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ Q_snprintf( resfile, sizeof( resfile ), "%s\\%s.lst", reslistdir, com_token );
+
+ CacheSoundsFromResFile( false, list, resfile );
+
+ // Any more tokens on this line?
+ while ( COM_TokenWaiting( pFileList ) )
+ {
+ pFileList = COM_Parse( pFileList );
+ }
+ }
+ }
+ delete[] pStart;
+ }
+
+ g_pFileSystem->Close(resfilehandle);
+
+ CacheSoundsFromResFile( false, list, CFmtStr( "%s\\engine.lst", reslistdir ) );
+ CacheSoundsFromResFile( false, list, CFmtStr( "%s\\all.lst", reslistdir ) );
+ }
+ else
+ {
+ Warning( "GetAllSoundFilesReferencedInReslists: Unable to load file %s\n", MAPLIST_FILE );
+ }
+ }
+
+ virtual void CacheBuildingStart()
+ {
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ EngineVGui()->ActivateGameUI();
+ EngineVGui()->StartCustomProgress();
+ const wchar_t *str = g_pVGuiLocalize->Find( "#Valve_CreatingCache" );
+ if ( str )
+ {
+ EngineVGui()->UpdateCustomProgressBar( 0.0f, str );
+ }
+ }
+
+ virtual void CacheBuildingUpdateProgress( float percent, char const *cachefile )
+ {
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ const wchar_t *format = g_pVGuiLocalize->Find( "Valve_CreatingSpecificSoundCache" );
+ if ( format )
+ {
+ wchar_t constructed[ 1024 ];
+ wchar_t file[ 256 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( cachefile, file, sizeof( file ) );
+
+ g_pVGuiLocalize->ConstructString_safe(
+ constructed,
+ ( wchar_t * )format,
+ 1,
+ file );
+
+ EngineVGui()->UpdateCustomProgressBar( percent, constructed );
+ }
+ }
+
+ virtual void CacheBuildingFinish()
+ {
+ if ( IsX360() )
+ {
+ return;
+ }
+
+ EngineVGui()->FinishCustomProgress();
+ EngineVGui()->HideGameUI();
+ }
+
+ virtual int GetPrecachedSoundCount()
+ {
+ if ( !sv.IsActive() )
+ return 0;
+
+ INetworkStringTable *table = sv.GetSoundPrecacheTable();
+ if ( !table )
+ return 0;
+
+ return table->GetNumStrings();
+ }
+
+ virtual char const *GetPrecachedSound( int index )
+ {
+ Assert( sv.IsActive() );
+
+ INetworkStringTable *table = sv.GetSoundPrecacheTable();
+ if ( !table )
+ return "";
+
+ return table->GetString( index );
+ }
+
+ virtual bool ShouldSuppressNonUISounds()
+ {
+ return EngineVGui()->IsGameUIVisible() || IsGamePaused();
+ }
+
+ virtual char const *GetUILanguage()
+ {
+ extern ConVar cl_language;
+ return cl_language.GetString();
+ }
+
+private:
+
+ float m_frameTime;
+
+ void CacheSoundsFromResFile( bool quiet, CUtlRBTree< FileNameHandle_t, int >& list, char const *resfile, bool checkandcleanname = true )
+ {
+ if ( !g_pFileSystem->FileExists( resfile, "MOD" ) )
+ {
+ Warning( "CacheSoundsFromResFile: Unable to find '%s'\n", resfile );
+ return;
+ }
+
+ int oldCount = list.Count();
+
+ FileHandle_t resfilehandle = g_pFileSystem->Open( resfile, "rb", "MOD" );
+ if ( FILESYSTEM_INVALID_HANDLE != resfilehandle )
+ {
+ // Read in and parse mapcycle.txt
+ int length = g_pFileSystem->Size(resfilehandle);
+ if ( length > 0 )
+ {
+ char *pStart = (char *)new char[ length + 1 ];
+ if ( pStart && ( length == g_pFileSystem->Read(pStart, length, resfilehandle) )
+ )
+ {
+ pStart[ length ] = 0;
+ const char *pFileList = pStart;
+
+ while ( 1 )
+ {
+ pFileList = COM_Parse( pFileList );
+ if ( strlen( com_token ) <= 0 )
+ break;
+
+ if ( checkandcleanname )
+ {
+ if ( Q_stristr( com_token, ".wav" ) ||
+ Q_stristr( com_token, ".mp3" ) )
+ {
+ // skip past the game/mod directory "hl2/sound/player/footstep.wav"
+ Q_FixSlashes(com_token); // "hl2\sound\player\footstep.wav"
+ const char *pName = com_token;
+ while (pName[0] && pName[0] != CORRECT_PATH_SEPARATOR)
+ {
+ pName++;
+ } // "\sound\player\footstep.wav"
+ FileNameHandle_t handle = g_pFileSystem->FindOrAddFileName( pName+1 ); // "sound\player\footstep.wav"
+ if ( list.Find( handle ) == list.InvalidIndex() )
+ {
+ list.Insert( handle );
+ }
+ }
+ }
+ else
+ {
+ FileNameHandle_t handle = g_pFileSystem->FindOrAddFileName( com_token );
+ if ( list.Find( handle ) == list.InvalidIndex() )
+ {
+ list.Insert( handle );
+ }
+ }
+ }
+ }
+ delete[] pStart;
+ }
+
+ g_pFileSystem->Close(resfilehandle);
+ }
+
+ int newCount = list.Count();
+
+ if ( !quiet )
+ {
+ Msg( "Processing (%i new) from %s\n", newCount - oldCount, resfile );
+ }
+ }
+
+ virtual void OnSoundStarted( int guid, StartSoundParams_t& params, char const *soundname )
+ {
+ VPROF("OnSoundStarted");
+
+ if ( IsX360() || !toolframework->IsToolRecording() || params.suppressrecording )
+ return;
+
+ KeyValues *msg = new KeyValues( "StartSound" );
+ msg->SetInt( "guid", guid );
+ msg->SetFloat( "time", cl.GetTime() );
+ msg->SetInt( "staticsound", params.staticsound ? 1 : 0 );
+ msg->SetInt( "soundsource", params.soundsource );
+ msg->SetInt( "entchannel", params.entchannel );
+ msg->SetString( "soundname", soundname );
+ msg->SetFloat( "originx", params.origin.x );
+ msg->SetFloat( "originy", params.origin.y );
+ msg->SetFloat( "originz", params.origin.z );
+ msg->SetFloat( "directionx", params.direction.x );
+ msg->SetFloat( "directiony", params.direction.y );
+ msg->SetFloat( "directionz", params.direction.z );
+ msg->SetInt( "updatepositions", params.bUpdatePositions );
+ msg->SetFloat( "fvol", params.fvol );
+ msg->SetInt( "soundlevel", (int)params.soundlevel );
+ msg->SetInt( "flags", params.flags );
+ msg->SetInt( "pitch", params.pitch );
+ msg->SetInt( "specialdsp", params.specialdsp );
+ msg->SetInt( "fromserver", params.fromserver ? 1 : 0 );
+ msg->SetFloat( "delay", params.delay );
+ msg->SetInt( "speakerentity", params.speakerentity );
+
+ toolframework->PostMessage( msg );
+
+ msg->deleteThis();
+ }
+
+ virtual void OnSoundStopped( int guid, int soundsource, int channel, char const *soundname )
+ {
+ // NOTE: At the moment, if we don't receive a StartSound message but we do
+ // receive a StopSound message, the StopSound message is ignored. In a perfect
+ // world, if the StartSound message was not sent, a StopSound message should not
+ // be sent for that guid either. This requires more plumbing, though, and
+ // for the moment, it's not necessary to do that plumbing.
+
+ VPROF("OnSoundStopped");
+
+ if ( IsX360() || !toolframework->IsToolRecording() )
+ return;
+
+ KeyValues *msg = new KeyValues( "StopSound" );
+ msg->SetInt( "guid", guid );
+ msg->SetFloat( "time", cl.GetTime() );
+ msg->SetInt( "soundsource", soundsource );
+ msg->SetInt( "entchannel", channel );
+ msg->SetString( "soundname", soundname );
+
+ toolframework->PostMessage( msg );
+
+ msg->deleteThis();
+ }
+};
+
+
+static CEngineSoundServices g_EngineSoundServices;
+ISoundServices *g_pSoundServices = &g_EngineSoundServices;