Counter Strike : Global Offensive Source Code
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.

601 lines
19 KiB

  1. //========= Copyright � 1996-2005, 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. #include "audio/private/snd_sfx.h"
  21. #include "cl_splitscreen.h"
  22. #include "cl_demo.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. // HACK: expose in sound.h maybe?
  26. void DSP_FastReset(int dsp);
  27. extern float g_flReplaySoundFade;
  28. //-----------------------------------------------------------------------------
  29. //
  30. // Client-side implementation of the engine sound interface
  31. //
  32. //-----------------------------------------------------------------------------
  33. class CEngineSoundClient : public IEngineSound
  34. {
  35. public:
  36. // constructor, destructor
  37. CEngineSoundClient();
  38. virtual ~CEngineSoundClient();
  39. virtual bool PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound );
  40. virtual bool IsSoundPrecached( const char *pSample );
  41. virtual void PrefetchSound( const char *pSample );
  42. virtual bool IsLoopingSound( const char *pSample );
  43. virtual float GetSoundDuration( const char *pSample );
  44. virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  45. float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
  46. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  47. virtual int EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  48. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  49. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  50. virtual void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex,
  51. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  52. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  53. virtual void StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash = SOUNDEMITTER_INVALID_HASH );
  54. virtual void StopAllSounds(bool bClearBuffers);
  55. virtual void SetRoomType( IRecipientFilter& filter, int roomType );
  56. virtual void SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset );
  57. virtual int EmitAmbientSound( const char *pSample, float flVolume,
  58. int iPitch, int flags, float soundtime = 0.0f );
  59. virtual float GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist );
  60. // Client .dll only functions
  61. virtual int GetGuidForLastSoundEmitted();
  62. virtual bool IsSoundStillPlaying( int guid );
  63. virtual bool GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight );
  64. virtual void StopSoundByGuid( int guid, bool bForceSync );
  65. // Set's master volume (0.0->1.0)
  66. virtual void SetVolumeByGuid( int guid, float fvol );
  67. virtual float GetElapsedTimeByGuid( int guid );
  68. // Retrieves list of all active sounds
  69. virtual void GetActiveSounds( CUtlVector< SndInfo_t >& sndlist );
  70. virtual void PrecacheSentenceGroup( const char *pGroupName );
  71. virtual void NotifyBeginMoviePlayback();
  72. virtual void NotifyEndMoviePlayback();
  73. virtual bool IsMoviePlaying();
  74. virtual bool GetPreventSound( void );
  75. virtual void SetReplaySoundFade( float flReplayVolume ) { g_flReplaySoundFade = flReplayVolume; }
  76. virtual float GetReplaySoundFade()const { return g_flReplaySoundFade; }
  77. #if defined( _GAMECONSOLE )
  78. virtual void UnloadSound( const char *pSample );
  79. #endif
  80. private:
  81. int EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  82. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  83. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime = 0.0f, int speakerentity = -1 );
  84. bool m_bMoviePlaying;
  85. };
  86. //-----------------------------------------------------------------------------
  87. // Client-server neutral sound interface accessor
  88. //-----------------------------------------------------------------------------
  89. static CEngineSoundClient s_EngineSoundClient;
  90. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CEngineSoundClient, IEngineSound,
  91. IENGINESOUND_CLIENT_INTERFACE_VERSION, s_EngineSoundClient );
  92. IEngineSound *EngineSoundClient()
  93. {
  94. return &s_EngineSoundClient;
  95. }
  96. //-----------------------------------------------------------------------------
  97. // constructor, destructor
  98. //-----------------------------------------------------------------------------
  99. CEngineSoundClient::CEngineSoundClient() :
  100. m_bMoviePlaying( false )
  101. {
  102. }
  103. CEngineSoundClient::~CEngineSoundClient()
  104. {
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Precache a particular sample
  108. //-----------------------------------------------------------------------------
  109. bool CEngineSoundClient::PrecacheSound( const char *pSample, bool bPreload, bool bIsUISound )
  110. {
  111. CSfxTable *pTable = S_PrecacheSound( pSample );
  112. if ( pTable )
  113. {
  114. if ( bIsUISound )
  115. {
  116. S_MarkUISound( pTable );
  117. }
  118. return true;
  119. }
  120. return false;
  121. }
  122. //-----------------------------------------------------------------------------
  123. // Purpose:
  124. // Input : *pSample -
  125. //-----------------------------------------------------------------------------
  126. void CEngineSoundClient::PrefetchSound( const char *pSample )
  127. {
  128. S_PrefetchSound( pSample, true );
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose:
  132. // Input : *pSample -
  133. // Output : Returns true on success, false on failure.
  134. //-----------------------------------------------------------------------------
  135. bool CEngineSoundClient::IsSoundPrecached( const char *pSample )
  136. {
  137. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  138. {
  139. return true;
  140. }
  141. int idx = GetBaseLocalClient().LookupSoundIndex( pSample );
  142. if ( idx == -1 )
  143. return false;
  144. return true;
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Returns if the sound is looping
  148. //-----------------------------------------------------------------------------
  149. bool CEngineSoundClient::IsLoopingSound( const char *pSample )
  150. {
  151. CSfxTable *pTable = S_PrecacheSound( pSample );
  152. if ( !pTable || !pTable->pSource )
  153. return false;
  154. return pTable->pSource->IsLooped();
  155. }
  156. extern IBaseClientDLL *g_ClientDLL;
  157. //-----------------------------------------------------------------------------
  158. // Actually does the work of emitting a sound
  159. //-----------------------------------------------------------------------------
  160. int CEngineSoundClient::EmitSoundInternal( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  161. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  162. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  163. {
  164. FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
  165. if (flVolume < 0 || flVolume > 1)
  166. {
  167. Warning ("EmitSound: %s volume out of bounds = %f\n", pSample, flVolume);
  168. return 0;
  169. }
  170. if (iSoundLevel < MIN_SNDLVL_VALUE || iSoundLevel > MAX_SNDLVL_VALUE)
  171. {
  172. Warning ("EmitSound: %s soundlevel out of bounds = %d\n", pSample, iSoundLevel);
  173. return 0;
  174. }
  175. if (iPitch < 0 || iPitch > 255)
  176. {
  177. Warning ("EmitSound: %s pitch out of bounds = %i\n", pSample, iPitch);
  178. return 0;
  179. }
  180. bool bInEyeSound = false;
  181. if (iEntIndex < 0)
  182. {
  183. bInEyeSound = true;
  184. if (g_ClientDLL)
  185. iEntIndex = g_ClientDLL->GetInEyeEntity();
  186. if (iEntIndex < 0)
  187. iEntIndex = GetLocalClient().GetViewEntity();
  188. }
  189. // See if local player is a recipient
  190. int i = 0;
  191. int c = filter.GetRecipientCount();
  192. for ( ; i < c ; i++ )
  193. {
  194. int index = filter.GetRecipientIndex( i );
  195. if ( index == GetLocalClient().m_nPlayerSlot + 1 )
  196. break;
  197. }
  198. // Local player not receiving sound
  199. if ( i >= c )
  200. return 0;
  201. // Point at origin if they didn't specify a sound source.
  202. Vector vecDummyOrigin;
  203. if (!pOrigin)
  204. {
  205. // Try to use the origin of the entity
  206. IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
  207. // don't update position if we stop this sound
  208. if (pEnt && !(iFlags & SND_STOP) )
  209. {
  210. vecDummyOrigin = pEnt->GetRenderOrigin();
  211. }
  212. else
  213. {
  214. vecDummyOrigin.Init();
  215. }
  216. pOrigin = &vecDummyOrigin;
  217. }
  218. Vector vecDirection;
  219. if (!pDirection)
  220. {
  221. IClientEntity *pEnt = entitylist->GetClientEntity( iEntIndex );
  222. if (pEnt && !(iFlags & SND_STOP))
  223. {
  224. QAngle angles;
  225. angles = pEnt->GetAbsAngles();
  226. AngleVectors( angles, &vecDirection );
  227. }
  228. else
  229. {
  230. vecDirection.Init();
  231. }
  232. pDirection = &vecDirection;
  233. }
  234. if ( pUtlVecOrigins )
  235. {
  236. (*pUtlVecOrigins).AddToTail( *pOrigin );
  237. }
  238. // L4D
  239. float delay = soundtime;
  240. if ( soundtime > 0.0f )
  241. {
  242. // this sound was played directly on the client, use its clock sync
  243. delay = S_ComputeDelayForSoundtime( soundtime, CLOCK_SYNC_CLIENT );
  244. if ( delay < 0 && delay > -0.100f )
  245. {
  246. delay = 0;
  247. }
  248. }
  249. StartSoundParams_t params;
  250. params.staticsound = iChannel == CHAN_STATIC;
  251. params.soundsource = iEntIndex;
  252. params.entchannel = iChannel;
  253. params.origin = *pOrigin;
  254. params.direction = *pDirection;
  255. params.bUpdatePositions = bUpdatePositions;
  256. params.fvol = flVolume;
  257. params.soundlevel = iSoundLevel;
  258. params.flags = iFlags;
  259. params.pitch = iPitch;
  260. params.fromserver = false;
  261. params.delay = delay;
  262. params.speakerentity = speakerentity;
  263. params.m_bIsScriptHandle = ( iFlags & SND_IS_SCRIPTHANDLE ) ? true : false ;
  264. params.m_bInEyeSound = bInEyeSound;
  265. if ( iFlags & SND_GENERATE_GUID )
  266. {
  267. params.m_nQueuedGUID = StartSoundParams_t::GENERATE_GUID;
  268. }
  269. // soundentry handling
  270. if ( iFlags & SND_IS_SCRIPTHANDLE )
  271. {
  272. // Don't actually play sounds if playing a demo and skipping ahead
  273. // but always stop sounds
  274. if ( demoplayer->IsSkipping() && !(iFlags&SND_STOP) )
  275. {
  276. return 0;
  277. }
  278. params.m_nSoundScriptHash = nSoundEntryHash;
  279. return S_StartSoundEntry( params, nSeed, false );
  280. }
  281. CSfxTable *pSound = S_PrecacheSound(pSample);
  282. if (!pSound)
  283. return 0;
  284. params.pSfx = pSound;
  285. // Don't actually play sounds if playing a demo and skipping ahead
  286. // but always stop sounds
  287. if ( demoplayer->IsSkipping() && !(iFlags&SND_STOP) )
  288. {
  289. return 0;
  290. }
  291. return S_StartSound( params );
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Plays a sentence
  295. //-----------------------------------------------------------------------------
  296. void CEngineSoundClient::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel,
  297. int iSentenceIndex, float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  298. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePosition, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  299. {
  300. if ( iSentenceIndex >= 0 )
  301. {
  302. char pName[8];
  303. Q_snprintf( pName, sizeof(pName), "!%d", iSentenceIndex );
  304. EmitSoundInternal( filter, iEntIndex, iChannel, NULL, SOUNDEMITTER_INVALID_HASH, pName, flVolume, iSoundLevel, nSeed,
  305. iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePosition, soundtime, speakerentity );
  306. }
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Emits a sound
  310. //-----------------------------------------------------------------------------
  311. int CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  312. float flVolume, float flAttenuation, int nSeed, int iFlags, int iPitch,
  313. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  314. {
  315. VPROF( "CEngineSoundClient::EmitSound" );
  316. return EmitSound( filter, iEntIndex, iChannel, pSoundEntry, nSoundEntryHash, pSample, flVolume, ATTN_TO_SNDLVL( flAttenuation ), nSeed, iFlags,
  317. iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  318. }
  319. int CEngineSoundClient::EmitSound( IRecipientFilter& filter, int iEntIndex, int iChannel, const char *pSoundEntry, HSOUNDSCRIPTHASH nSoundEntryHash, const char *pSample,
  320. float flVolume, soundlevel_t iSoundLevel, int nSeed, int iFlags, int iPitch,
  321. const Vector *pOrigin, const Vector *pDirection, CUtlVector< Vector >* pUtlVecOrigins, bool bUpdatePositions, float soundtime /*= 0.0f*/, int speakerentity /*= -1*/ )
  322. {
  323. VPROF( "CEngineSoundClient::EmitSound" );
  324. if ( pSample && TestSoundChar(pSample, CHAR_SENTENCE) )
  325. {
  326. int iSentenceIndex = -1;
  327. VOX_LookupString( PSkipSoundChars(pSample), &iSentenceIndex );
  328. if (iSentenceIndex >= 0)
  329. {
  330. EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume,
  331. iSoundLevel, nSeed, iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  332. }
  333. else
  334. {
  335. DevWarning( 2, "Unable to find %s in sentences.txt\n", PSkipSoundChars(pSample));
  336. }
  337. return -1;
  338. }
  339. else
  340. {
  341. return EmitSoundInternal( filter, iEntIndex, iChannel, pSoundEntry, nSoundEntryHash, pSample, flVolume, iSoundLevel, nSeed,
  342. iFlags, iPitch, pOrigin, pDirection, pUtlVecOrigins, bUpdatePositions, soundtime, speakerentity );
  343. }
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Stops a sound
  347. //-----------------------------------------------------------------------------
  348. void CEngineSoundClient::StopSound( int iEntIndex, int iChannel, const char *pSample, HSOUNDSCRIPTHASH nSoundEntryHash )
  349. {
  350. FORCE_DEFAULT_SPLITSCREEN_PLAYER_GUARD;
  351. CEngineSingleUserFilter filter( GetLocalClient().m_nPlayerSlot + 1 );
  352. EmitSound( filter, iEntIndex, iChannel, pSample, nSoundEntryHash, pSample, 0, SNDLVL_NONE, 0, SND_STOP, PITCH_NORM,
  353. NULL, NULL, NULL, true );
  354. }
  355. void CEngineSoundClient::SetRoomType( IRecipientFilter& filter, int roomType )
  356. {
  357. #ifndef LINUX
  358. extern ConVar snd_dsp_spew_changes;
  359. extern ConVar dsp_room;
  360. if ( snd_dsp_spew_changes.GetBool() )
  361. {
  362. DevMsg( "Changing to room type %d.\n", roomType );
  363. }
  364. dsp_room.SetValue( roomType );
  365. #endif
  366. }
  367. void CEngineSoundClient::SetPlayerDSP( IRecipientFilter& filter, int dspType, bool fastReset )
  368. {
  369. extern void dsp_player_set( int val );
  370. dsp_player_set( dspType );
  371. if ( fastReset )
  372. {
  373. DSP_FastReset( dspType );
  374. }
  375. }
  376. int CEngineSoundClient::EmitAmbientSound( const char *pSample, float flVolume,
  377. int iPitch, int flags, float soundtime /*= 0.0f*/ )
  378. {
  379. float delay = 0.0f;
  380. if ( soundtime != 0.0f )
  381. {
  382. delay = soundtime - GetBaseLocalClient().m_flLastServerTickTime;
  383. }
  384. CSfxTable *pSound = S_PrecacheSound(pSample);
  385. StartSoundParams_t params;
  386. params.staticsound = true;
  387. params.soundsource = SOUND_FROM_LOCAL_PLAYER;
  388. params.entchannel = CHAN_STATIC;
  389. params.pSfx = pSound;
  390. params.origin = vec3_origin;
  391. params.fvol = flVolume;
  392. params.soundlevel = SNDLVL_NONE;
  393. params.flags = flags;
  394. params.pitch = iPitch;
  395. params.fromserver = false;
  396. params.delay = delay;
  397. return S_StartSound( params );
  398. }
  399. void CEngineSoundClient::StopAllSounds(bool bClearBuffers)
  400. {
  401. S_StopAllSounds( bClearBuffers );
  402. }
  403. bool CEngineSoundClient::GetPreventSound( void )
  404. {
  405. return S_GetPreventSound( );
  406. }
  407. float CEngineSoundClient::GetDistGainFromSoundLevel( soundlevel_t soundlevel, float dist )
  408. {
  409. return S_GetGainFromSoundLevel( soundlevel, dist );
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Purpose:
  413. // Input : *pSample -
  414. // Output : float
  415. //-----------------------------------------------------------------------------
  416. float CEngineSoundClient::GetSoundDuration( const char *pSample )
  417. {
  418. return AudioSource_GetSoundDuration( pSample );
  419. }
  420. // Client .dll only functions
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. // Input : -
  424. // Output : int
  425. //-----------------------------------------------------------------------------
  426. int CEngineSoundClient::GetGuidForLastSoundEmitted()
  427. {
  428. return S_GetGuidForLastSoundEmitted();
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose:
  432. // Input : guid -
  433. // Output : Returns true on success, false on failure.
  434. //-----------------------------------------------------------------------------
  435. bool CEngineSoundClient::IsSoundStillPlaying( int guid )
  436. {
  437. return S_IsSoundStillPlaying( guid );
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Purpose:
  441. // Input : guid -
  442. //-----------------------------------------------------------------------------
  443. void CEngineSoundClient::StopSoundByGuid( int guid, bool bForceSync )
  444. {
  445. S_StopSoundByGuid( guid, bForceSync );
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose: Retrieves list of all active sounds
  449. // Input : sndlist -
  450. //-----------------------------------------------------------------------------
  451. void CEngineSoundClient::GetActiveSounds( CUtlVector< SndInfo_t >& sndlist )
  452. {
  453. S_GetActiveSounds( sndlist );
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose: Set's master volume (0.0->1.0)
  457. // Input : guid -
  458. // fvol -
  459. //-----------------------------------------------------------------------------
  460. void CEngineSoundClient::SetVolumeByGuid( int guid, float fvol )
  461. {
  462. S_SetVolumeByGuid( guid, fvol );
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose: Returns sound's current elapsed time
  466. // Input : guid -
  467. //-----------------------------------------------------------------------------
  468. float CEngineSoundClient::GetElapsedTimeByGuid( int guid )
  469. {
  470. return S_GetElapsedTimeByGuid( guid );
  471. }
  472. //-----------------------------------------------------------------------------
  473. //-----------------------------------------------------------------------------
  474. void CEngineSoundClient::PrecacheSentenceGroup( const char *pGroupName )
  475. {
  476. VOX_PrecacheSentenceGroup( this, pGroupName );
  477. }
  478. void CEngineSoundClient::NotifyBeginMoviePlayback()
  479. {
  480. StopAllSounds(true);
  481. #if defined( _X360 )
  482. XMPOverrideBackgroundMusic();
  483. #endif
  484. m_bMoviePlaying = true;
  485. }
  486. void CEngineSoundClient::NotifyEndMoviePlayback()
  487. {
  488. #if defined( _X360 )
  489. XMPRestoreBackgroundMusic();
  490. #endif
  491. m_bMoviePlaying = false;
  492. }
  493. bool CEngineSoundClient::IsMoviePlaying()
  494. {
  495. return m_bMoviePlaying;
  496. }
  497. bool CEngineSoundClient::GetSoundChannelVolume( const char* sound, float &flVolumeLeft, float &flVolumeRight )
  498. {
  499. return S_GetSoundChannelVolume( sound, flVolumeLeft, flVolumeRight );
  500. }
  501. #if defined( _GAMECONSOLE )
  502. void CEngineSoundClient::UnloadSound( const char *pSample )
  503. {
  504. S_UnloadSound( pSample );
  505. }
  506. #endif