Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "engine/IEngineSound.h"
  8. #include "tier0/dbg.h"
  9. #include "sound.h"
  10. #include "client.h"
  11. #include "vox.h"
  12. #include "icliententity.h"
  13. #include "icliententitylist.h"
  14. #include "enginesingleuserfilter.h"
  15. #include "snd_audio_source.h"
  16. #if defined(_X360)
  17. #include "xmp.h"
  18. #endif
  19. #include "tier0/vprof.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. // HACK: expose in sound.h maybe?
  23. void DSP_FastReset(int dsp);
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Client-side implementation of the engine sound interface
  27. //
  28. //-----------------------------------------------------------------------------
  29. class CEngineSoundClient : public IEngineSound
  30. {
  31. public:
  32. // constructor, destructor
  33. CEngineSoundClient();
  34. virtual ~CEngineSoundClient();
  35. virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound );
  36. virtual bool IsSoundPrecached( const char *pSample );
  37. virtual void PrefetchSound( const char *pSample );
  38. virtual float GetSoundDuration( const char *pSample );
  39. virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  40. float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP,
  41. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  42. virtual void EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  43. float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  44. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  45. virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
  46. float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  47. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  48. virtual void StopSound( int iEntIndex, int iChannel, const char *pSample );
  49. virtual void StopAllSounds(bool bClearBuffers);
  50. virtual void SetRoomType( IRecipientFilter& filter, int roomType );
  51. virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset );
  52. virtual void EmitAmbientSound( const char *pSample, float flVolume,
  53. int iPitch, int flags, float soundtime = 0.0f );
  54. virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist );
  55. // Client .dll only functions
  56. virtual int GetGuidForLastSoundEmitted();
  57. virtual bool IsSoundStillPlaying( int guid );
  58. virtual void StopSoundByGuid( int guid );
  59. // Set's master volume (0.0->1.0)
  60. virtual void SetVolumeByGuid( int guid, float fvol );
  61. // Retrieves list of all active sounds
  62. virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist );
  63. virtual void PrecacheSentenceGroup( const char *pGroupName );
  64. virtual void NotifyBeginMoviePlayback();
  65. virtual void NotifyEndMoviePlayback();
  66. private:
  67. void EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  68. float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  69. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  70. };
  71. //-----------------------------------------------------------------------------
  72. // Client-server neutral sound interface accessor
  73. //-----------------------------------------------------------------------------
  74. static CEngineSoundClient s_EngineSoundClient;
  75. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundClient, IEngineSound,
  76. IENGINESOUND_CLIENT_INTERFACE_VERSION, s_EngineSoundClient );
  77. IEngineSound *EngineSoundClient()
  78. {
  79. return &s_EngineSoundClient;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // constructor, destructor
  83. //-----------------------------------------------------------------------------
  84. CEngineSoundClient::CEngineSoundClient()
  85. {
  86. }
  87. CEngineSoundClient::~CEngineSoundClient()
  88. {
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Precache a particular sample
  92. //-----------------------------------------------------------------------------
  93. bool CEngineSoundClient::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound )
  94. {
  95. CSfxTable *pTable = S_PrecacheSound( pSample );
  96. if ( pTable )
  97. {
  98. if ( bIsUISound )
  99. {
  100. S_MarkUISound( pTable );
  101. }
  102. return true;
  103. }
  104. return false;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. // Input : *pSample -
  109. //-----------------------------------------------------------------------------
  110. void CEngineSoundClient::PrefetchSound( const char *pSample )
  111. {
  112. S_PrefetchSound( pSample, true );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. // Input : *pSample -
  117. // Output : Returns true on success, false on failure.
  118. //-----------------------------------------------------------------------------
  119. bool CEngineSoundClient::IsSoundPrecached( const char *pSample )
  120. {
  121. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  122. {
  123. return true;
  124. }
  125. int idx = cl.LookupSoundIndex( pSample );
  126. if ( idx == -1 )
  127. return false;
  128. return true;
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Actually does the work of emitting a sound
  132. //-----------------------------------------------------------------------------
  133. void CEngineSoundClient::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  134. float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  135. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  136. {
  137. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  138. if (flVolume < 0 || flVolume > 1)
  139. {
  140. Warning ("EmitSound: volume out of bounds = %f\n", flVolume);
  141. return;
  142. }
  143. if ( ( iSoundLevel < soundlevel_t(MIN_SNDLVL_VALUE) ) || ( iSoundLevel > soundlevel_t(MAX_SNDLVL_VALUE) ) )
  144. {
  145. Warning ("EmitSound: soundlevel out of bounds = %d\n", iSoundLevel);
  146. return;
  147. }
  148. if (iPitch < 0 || iPitch > 255)
  149. {
  150. Warning ("EmitSound: pitch out of bounds = %i\n", iPitch);
  151. return;
  152. }
  153. int iSoundSource = iEntIndex;
  154. // Handle client UI sounds
  155. if ( iSoundSource != SOUND_FROM_UI_PANEL )
  156. {
  157. if (iSoundSource < 0)
  158. iSoundSource = cl.m_nViewEntity;
  159. // See if local player is a recipient
  160. int i = 0;
  161. int c = filter.GetRecipientCount();
  162. for ( ; i < c ; i++ )
  163. {
  164. int index = filter.GetRecipientIndex( i );
  165. if ( index == cl.m_nPlayerSlot + 1 )
  166. break;
  167. }
  168. // Local player not receiving sound
  169. if ( i >= c )
  170. return;
  171. }
  172. CSfxTable *pSound = S_PrecacheSound(pSample);
  173. if (!pSound)
  174. return;
  175. Vector vecDummyOrigin;
  176. Vector vecDirection;
  177. if ( iSoundSource == SOUND_FROM_UI_PANEL )
  178. {
  179. vecDummyOrigin.Init();
  180. vecDirection.Init();
  181. pOrigin = &vecDummyOrigin;
  182. pDirection = &vecDirection;
  183. }
  184. else
  185. {
  186. // Point at origin if they didn't specify a sound source.
  187. if (!pOrigin)
  188. {
  189. // Try to use the origin of the entity
  190. IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
  191. // don't update position if we stop this sound
  192. if (pEnt && !(iFlags & SND_STOP) )
  193. {
  194. vecDummyOrigin = pEnt->GetRenderOrigin();
  195. }
  196. else
  197. {
  198. vecDummyOrigin.Init();
  199. }
  200. pOrigin = &vecDummyOrigin;
  201. }
  202. if (!pDirection)
  203. {
  204. IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
  205. if (pEnt && !(iFlags & SND_STOP))
  206. {
  207. QAngle angles;
  208. angles = pEnt->GetAbsAngles();
  209. AngleVectors( angles, &vecDirection );
  210. }
  211. else
  212. {
  213. vecDirection.Init();
  214. }
  215. pDirection = &vecDirection;
  216. }
  217. }
  218. if ( pUtlVecOrigins )
  219. {
  220. (*pUtlVecOrigins).AddToTail( *pOrigin );
  221. }
  222. float delay = 0.0f;
  223. if ( soundtime != 0.0f )
  224. {
  225. // this sound was played directly on the client, use its clock sync
  226. delay = S_ComputeDelayForSoundtime( soundtime, CLOCK_SYNC_CLIENT );
  227. #if 0
  228. static float lastSoundTime = 0;
  229. Msg("[%.3f] Play %s at %.3f %.1fsms delay\n", soundtime - lastSoundTime, pSample, soundtime, delay * 1000.0f );
  230. lastSoundTime = soundtime;
  231. #endif
  232. // anything over 250ms is assumed to be intentional skipping
  233. if ( delay <= 0 && delay > -0.250f )
  234. {
  235. // leave a little delay to flag the channel in the low-level sound system
  236. delay = 1e-6f;
  237. }
  238. }
  239. StartSoundParams_t params;
  240. params.staticsound = iChannel == CHAN_STATIC;
  241. params.soundsource = iSoundSource;
  242. params.entchannel = iChannel;
  243. params.pSfx = pSound;
  244. params.origin = *pOrigin;
  245. params.direction = *pDirection;
  246. params.bUpdatePositions = bUpdatePositions;
  247. params.fvol = flVolume;
  248. params.soundlevel = iSoundLevel;
  249. params.flags = iFlags;
  250. params.pitch = iPitch;
  251. params.specialdsp = iSpecialDSP;
  252. params.fromserver = false;
  253. params.delay = delay;
  254. params.speakerentity = speakerentity;
  255. S_StartSound( params );
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Plays a sentence
  259. //-----------------------------------------------------------------------------
  260. void CEngineSoundClient::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel,
  261. int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  262. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePosition, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  263. {
  264. if ( iSentenceIndex >= 0 )
  265. {
  266. char pName[8];
  267. Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex );
  268. EmitSoundInternal( filter, iEntIndex, iChannel, pName, flVolume, iSoundLevel,
  269. iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePosition, soundtime, speakerentity );
  270. }
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Emits a sound
  274. //-----------------------------------------------------------------------------
  275. void CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  276. float flVolume, float flAttenuation, int iFlags, int iPitch, int iSpecialDSP,
  277. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  278. {
  279. VPROF( "CEngineSoundClient::EmitSound" );
  280. EmitSound( filter, iEntIndex, iChannel, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), iFlags,
  281. iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  282. }
  283. void CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSample,
  284. float flVolume, soundlevel_t iSoundLevel, int iFlags, int iPitch, int iSpecialDSP,
  285. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  286. {
  287. VPROF( "CEngineSoundClient::EmitSound" );
  288. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  289. {
  290. int iSentenceIndex = -1;
  291. VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex );
  292. if (iSentenceIndex >= 0)
  293. {
  294. EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume,
  295. iSoundLevel, iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  296. }
  297. else
  298. {
  299. DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample));
  300. }
  301. }
  302. else
  303. {
  304. EmitSoundInternal( filter, iEntIndex, iChannel, pSample, flVolume, iSoundLevel,
  305. iFlags, iPitch, iSpecialDSP, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  306. }
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Stops a sound
  310. //-----------------------------------------------------------------------------
  311. void CEngineSoundClient::StopSound( int iEntIndex, int iChannel, const char *pSample )
  312. {
  313. CEngineSingleUserFilter filter( cl.m_nPlayerSlot + 1 );
  314. EmitSound( filter, iEntIndex, iChannel, pSample, 0, SNDLVL_NONE, SND_STOP, PITCH_NORM, 0,
  315. NULL, NULL, NULL, true );
  316. }
  317. void CEngineSoundClient::SetRoomType( IRecipientFilter& filter, int roomType )
  318. {
  319. extern ConVar dsp_room;
  320. dsp_room.SetValue( roomType );
  321. }
  322. void CEngineSoundClient::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset )
  323. {
  324. extern ConVar dsp_player;
  325. dsp_player.SetValue( dspType );
  326. if ( fastReset )
  327. {
  328. DSP_FastReset( dspType );
  329. }
  330. }
  331. void CEngineSoundClient::EmitAmbientSound( const char *pSample, float flVolume,
  332. int iPitch, int flags, float soundtime /*= 0.0f*/ )
  333. {
  334. float delay = 0.0f;
  335. if ( soundtime != 0.0f )
  336. {
  337. delay = soundtime - cl.m_flLastServerTickTime;
  338. }
  339. CSfxTable *pSound = S_PrecacheSound(pSample);
  340. StartSoundParams_t params;
  341. params.staticsound = true;
  342. params.soundsource = SOUND_FROM_LOCAL_PLAYER;
  343. params.entchannel = CHAN_STATIC;
  344. params.pSfx = pSound;
  345. params.origin = vec3_origin;
  346. params.fvol = flVolume;
  347. params.soundlevel = SNDLVL_NONE;
  348. params.flags = flags;
  349. params.pitch = iPitch;
  350. params.specialdsp = 0;
  351. params.fromserver = false;
  352. params.delay = delay;
  353. S_StartSound( params );
  354. }
  355. void CEngineSoundClient::StopAllSounds(bool bClearBuffers)
  356. {
  357. S_StopAllSounds( bClearBuffers );
  358. }
  359. float CEngineSoundClient::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist )
  360. {
  361. return S_GetGainFromSoundLevel( soundlevel, dist );
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose:
  365. // Input : *pSample -
  366. // Output : float
  367. //-----------------------------------------------------------------------------
  368. float CEngineSoundClient::GetSoundDuration( const char *pSample )
  369. {
  370. return AudioSource_GetSoundDuration( pSample );
  371. }
  372. // Client .dll only functions
  373. //-----------------------------------------------------------------------------
  374. // Purpose:
  375. // Input : -
  376. // Output : int
  377. //-----------------------------------------------------------------------------
  378. int CEngineSoundClient::GetGuidForLastSoundEmitted()
  379. {
  380. return S_GetGuidForLastSoundEmitted();
  381. }
  382. //-----------------------------------------------------------------------------
  383. // Purpose:
  384. // Input : guid -
  385. // Output : Returns true on success, false on failure.
  386. //-----------------------------------------------------------------------------
  387. bool CEngineSoundClient::IsSoundStillPlaying( int guid )
  388. {
  389. return S_IsSoundStillPlaying( guid );
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose:
  393. // Input : guid -
  394. //-----------------------------------------------------------------------------
  395. void CEngineSoundClient::StopSoundByGuid( int guid )
  396. {
  397. S_StopSoundByGuid( guid );
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose: Retrieves list of all active sounds
  401. // Input : sndlist -
  402. //-----------------------------------------------------------------------------
  403. void CEngineSoundClient::GetActiveSounds( CUtlVector< SndInfo_t >& sndlist )
  404. {
  405. S_GetActiveSounds( sndlist );
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Purpose: Set's master volume (0.0->1.0)
  409. // Input : guid -
  410. // fvol -
  411. //-----------------------------------------------------------------------------
  412. void CEngineSoundClient::SetVolumeByGuid( int guid, float fvol )
  413. {
  414. S_SetVolumeByGuid( guid, fvol );
  415. }
  416. //-----------------------------------------------------------------------------
  417. //-----------------------------------------------------------------------------
  418. void CEngineSoundClient::PrecacheSentenceGroup( const char *pGroupName )
  419. {
  420. VOX_PrecacheSentenceGroup( this, pGroupName );
  421. }
  422. void CEngineSoundClient::NotifyBeginMoviePlayback()
  423. {
  424. StopAllSounds(true);
  425. #if _X360
  426. XMPOverrideBackgroundMusic();
  427. #endif
  428. }
  429. void CEngineSoundClient::NotifyEndMoviePlayback()
  430. {
  431. #if _X360
  432. XMPRestoreBackgroundMusic();
  433. #endif
  434. }