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.

583 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #if !defined(_STATIC_LINKED) || defined(SOUNDEMITTERSYSTEM_DLL)
  10. #include "SoundEmitterSystem/isoundemittersystembase.h"
  11. #include "interval.h"
  12. #include "soundchars.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. struct SoundChannels
  16. {
  17. int channel;
  18. const char *name;
  19. };
  20. // NOTE: This will need to be updated if channel names are added/removed
  21. static SoundChannels g_pChannelNames[] =
  22. {
  23. { CHAN_AUTO, "CHAN_AUTO" },
  24. { CHAN_WEAPON, "CHAN_WEAPON" },
  25. { CHAN_VOICE, "CHAN_VOICE" },
  26. { CHAN_ITEM, "CHAN_ITEM" },
  27. { CHAN_BODY, "CHAN_BODY" },
  28. { CHAN_STREAM, "CHAN_STREAM" },
  29. { CHAN_STATIC, "CHAN_STATIC" },
  30. { CHAN_VOICE2, "CHAN_VOICE2" },
  31. };
  32. struct VolumeLevel
  33. {
  34. float volume;
  35. const char *name;
  36. };
  37. static VolumeLevel g_pVolumeLevels[] =
  38. {
  39. { VOL_NORM, "VOL_NORM" },
  40. };
  41. struct PitchLookup
  42. {
  43. float pitch;
  44. const char *name;
  45. };
  46. static PitchLookup g_pPitchLookup[] =
  47. {
  48. { PITCH_NORM, "PITCH_NORM" },
  49. { PITCH_LOW, "PITCH_LOW" },
  50. { PITCH_HIGH, "PITCH_HIGH" },
  51. };
  52. //-----------------------------------------------------------------------------
  53. // Purpose:
  54. //-----------------------------------------------------------------------------
  55. struct SoundLevelLookup
  56. {
  57. soundlevel_t level;
  58. char const *name;
  59. };
  60. // NOTE: Needs to reflect the soundlevel_t enum defined in soundflags.h
  61. static SoundLevelLookup g_pSoundLevels[] =
  62. {
  63. { SNDLVL_NONE, "SNDLVL_NONE" },
  64. { SNDLVL_20dB, "SNDLVL_20dB" },
  65. { SNDLVL_25dB, "SNDLVL_25dB" },
  66. { SNDLVL_30dB, "SNDLVL_30dB" },
  67. { SNDLVL_35dB, "SNDLVL_35dB" },
  68. { SNDLVL_40dB, "SNDLVL_40dB" },
  69. { SNDLVL_45dB, "SNDLVL_45dB" },
  70. { SNDLVL_50dB, "SNDLVL_50dB" },
  71. { SNDLVL_55dB, "SNDLVL_55dB" },
  72. { SNDLVL_IDLE, "SNDLVL_IDLE" },
  73. { SNDLVL_TALKING, "SNDLVL_TALKING" },
  74. { SNDLVL_60dB, "SNDLVL_60dB" },
  75. { SNDLVL_65dB, "SNDLVL_65dB" },
  76. { SNDLVL_STATIC, "SNDLVL_STATIC" },
  77. { SNDLVL_70dB, "SNDLVL_70dB" },
  78. { SNDLVL_NORM, "SNDLVL_NORM" },
  79. { SNDLVL_75dB, "SNDLVL_75dB" },
  80. { SNDLVL_80dB, "SNDLVL_80dB" },
  81. { SNDLVL_85dB, "SNDLVL_85dB" },
  82. { SNDLVL_90dB, "SNDLVL_90dB" },
  83. { SNDLVL_95dB, "SNDLVL_95dB" },
  84. { SNDLVL_100dB, "SNDLVL_100dB" },
  85. { SNDLVL_105dB, "SNDLVL_105dB" },
  86. { SNDLVL_110dB, "SNDLVL_110dB" },
  87. { SNDLVL_120dB, "SNDLVL_120dB" },
  88. { SNDLVL_130dB, "SNDLVL_130dB" },
  89. { SNDLVL_GUNFIRE, "SNDLVL_GUNFIRE" },
  90. { SNDLVL_140dB, "SNDLVL_140dB" },
  91. { SNDLVL_150dB, "SNDLVL_150dB" },
  92. { SNDLVL_180dB, "SNDLVL_180dB" },
  93. };
  94. static const char *_SoundLevelToString( soundlevel_t level )
  95. {
  96. int c = ARRAYSIZE( g_pSoundLevels );
  97. int i;
  98. for ( i = 0 ; i < c; i++ )
  99. {
  100. SoundLevelLookup *entry = &g_pSoundLevels[ i ];
  101. if ( entry->level == level )
  102. return entry->name;
  103. }
  104. static char sz[ 32 ];
  105. Q_snprintf( sz, sizeof( sz ), "%i", (int)level );
  106. return sz;
  107. }
  108. static const char *_ChannelToString( int channel )
  109. {
  110. int c = ARRAYSIZE( g_pChannelNames );
  111. int i;
  112. for ( i = 0 ; i < c; i++ )
  113. {
  114. SoundChannels *entry = &g_pChannelNames[ i ];
  115. if ( entry->channel == channel )
  116. return entry->name;
  117. }
  118. static char sz[ 32 ];
  119. Q_snprintf( sz, sizeof( sz ), "%i", (int)channel );
  120. return sz;
  121. }
  122. static const char *_VolumeToString( float volume )
  123. {
  124. int c = ARRAYSIZE( g_pVolumeLevels );
  125. int i;
  126. for ( i = 0 ; i < c; i++ )
  127. {
  128. VolumeLevel *entry = &g_pVolumeLevels[ i ];
  129. if ( entry->volume == volume )
  130. return entry->name;
  131. }
  132. static char sz[ 32 ];
  133. Q_snprintf( sz, sizeof( sz ), "%.3f", volume );
  134. return sz;
  135. }
  136. static const char *_PitchToString( float pitch )
  137. {
  138. int c = ARRAYSIZE( g_pPitchLookup );
  139. int i;
  140. for ( i = 0 ; i < c; i++ )
  141. {
  142. PitchLookup *entry = &g_pPitchLookup[ i ];
  143. if ( entry->pitch == pitch )
  144. return entry->name;
  145. }
  146. static char sz[ 32 ];
  147. Q_snprintf( sz, sizeof( sz ), "%.3f", pitch );
  148. return sz;
  149. }
  150. #define SNDLVL_PREFIX "SNDLVL_"
  151. soundlevel_t TextToSoundLevel( const char *key )
  152. {
  153. if ( !key )
  154. {
  155. Assert( 0 );
  156. return SNDLVL_NORM;
  157. }
  158. int c = ARRAYSIZE( g_pSoundLevels );
  159. int i;
  160. for ( i = 0 ; i < c; i++ )
  161. {
  162. SoundLevelLookup *entry = &g_pSoundLevels[ i ];
  163. if ( !Q_strcasecmp( key, entry->name ) )
  164. return entry->level;
  165. }
  166. if ( !Q_strnicmp( key, SNDLVL_PREFIX, Q_strlen( SNDLVL_PREFIX ) ) )
  167. {
  168. char const *val = key + Q_strlen( SNDLVL_PREFIX );
  169. int sndlvl = atoi( val );
  170. if ( sndlvl > 0 && sndlvl <= 180 )
  171. {
  172. return ( soundlevel_t )sndlvl;
  173. }
  174. }
  175. DevMsg( "CSoundEmitterSystem: Unknown sound level %s\n", key );
  176. return SNDLVL_NORM;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose: Convert "chan_xxx" into integer value for channel
  180. // Input : *name -
  181. // Output : static int
  182. //-----------------------------------------------------------------------------
  183. int TextToChannel( const char *name )
  184. {
  185. if ( !name )
  186. {
  187. Assert( 0 );
  188. // CHAN_AUTO
  189. return CHAN_AUTO;
  190. }
  191. if ( Q_strncasecmp( name, "chan_", strlen( "chan_" ) ) )
  192. {
  193. return atoi( name );
  194. }
  195. int c = ARRAYSIZE( g_pChannelNames );
  196. int i;
  197. for ( i = 0; i < c; i++ )
  198. {
  199. if ( !Q_strcasecmp( name, g_pChannelNames[ i ].name ) )
  200. {
  201. return g_pChannelNames[ i ].channel;
  202. }
  203. }
  204. // At this point, it starts with chan_ but is not recognized
  205. // atoi would return 0, so just do chan auto
  206. DevMsg( "CSoundEmitterSystem: Warning, unknown channel type in sounds.txt (%s)\n", name );
  207. return CHAN_AUTO;
  208. }
  209. const char *SoundLevelToString( soundlevel_t level )
  210. {
  211. int c = ARRAYSIZE( g_pSoundLevels );
  212. int i;
  213. for ( i = 0 ; i < c; i++ )
  214. {
  215. SoundLevelLookup *entry = &g_pSoundLevels[ i ];
  216. if ( entry->level == level )
  217. return entry->name;
  218. }
  219. static char sz[ 32 ];
  220. Q_snprintf( sz, sizeof( sz ), "%i", (int)level );
  221. return sz;
  222. }
  223. const char *ChannelToString( int channel )
  224. {
  225. int c = ARRAYSIZE( g_pChannelNames );
  226. int i;
  227. for ( i = 0 ; i < c; i++ )
  228. {
  229. SoundChannels *entry = &g_pChannelNames[ i ];
  230. if ( entry->channel == channel )
  231. return entry->name;
  232. }
  233. static char sz[ 32 ];
  234. Q_snprintf( sz, sizeof( sz ), "%i", (int)channel );
  235. return sz;
  236. }
  237. const char *VolumeToString( float volume )
  238. {
  239. int c = ARRAYSIZE( g_pVolumeLevels );
  240. int i;
  241. for ( i = 0 ; i < c; i++ )
  242. {
  243. VolumeLevel *entry = &g_pVolumeLevels[ i ];
  244. if ( entry->volume == volume )
  245. return entry->name;
  246. }
  247. static char sz[ 32 ];
  248. Q_snprintf( sz, sizeof( sz ), "%.3f", volume );
  249. return sz;
  250. }
  251. const char *PitchToString( float pitch )
  252. {
  253. int c = ARRAYSIZE( g_pPitchLookup );
  254. int i;
  255. for ( i = 0 ; i < c; i++ )
  256. {
  257. PitchLookup *entry = &g_pPitchLookup[ i ];
  258. if ( entry->pitch == pitch )
  259. return entry->name;
  260. }
  261. static char sz[ 32 ];
  262. Q_snprintf( sz, sizeof( sz ), "%.3f", pitch );
  263. return sz;
  264. }
  265. CSoundParametersInternal::CSoundParametersInternal()
  266. {
  267. m_pConvertedNames = m_pSoundNames = NULL;
  268. m_nConvertedNames = m_nSoundNames = 0;
  269. channel = CHAN_AUTO; // 0
  270. volume.start = VOL_NORM; // 1.0f
  271. volume.range = 0.0f;
  272. pitch.start = PITCH_NORM; // 100
  273. pitch.range = 0;
  274. soundlevel.start = SNDLVL_NORM; // 75dB
  275. soundlevel.range = 0;
  276. delay_msec = 0;
  277. play_to_owner_only = false;
  278. had_missing_wave_files = false;
  279. uses_gender_token = false;
  280. }
  281. CSoundParametersInternal::CSoundParametersInternal( const CSoundParametersInternal& src )
  282. {
  283. m_pSoundNames = NULL;
  284. m_pConvertedNames = NULL;
  285. m_nSoundNames = 0;
  286. m_nConvertedNames = 0;
  287. CopyFrom( src );
  288. }
  289. CSoundParametersInternal::~CSoundParametersInternal()
  290. {
  291. if ( m_nSoundNames > 1 )
  292. free(m_pSoundNames );
  293. if ( m_nConvertedNames > 1 )
  294. free( m_pConvertedNames);
  295. m_pConvertedNames = NULL;
  296. m_pSoundNames = NULL;
  297. m_nSoundNames = 0;
  298. m_nConvertedNames = 0;
  299. }
  300. void CSoundParametersInternal::CopyFrom( const CSoundParametersInternal& src )
  301. {
  302. if ( m_nSoundNames > 1 )
  303. free(m_pSoundNames);
  304. if ( m_nConvertedNames > 1 )
  305. free(m_pConvertedNames);
  306. channel = src.channel;
  307. volume = src.volume;
  308. pitch = src.pitch;
  309. soundlevel = src.soundlevel;
  310. delay_msec = src.delay_msec;
  311. play_to_owner_only = src.play_to_owner_only;
  312. m_nSoundNames = src.m_nSoundNames;
  313. if ( m_nSoundNames )
  314. {
  315. if ( m_nSoundNames > 1 )
  316. {
  317. m_pSoundNames = (SoundFile*)malloc( sizeof(SoundFile)*m_nSoundNames);
  318. memcpy( m_pSoundNames, src.m_pSoundNames, m_nSoundNames * sizeof(SoundFile) );
  319. }
  320. else
  321. {
  322. m_pSoundNames = src.m_pSoundNames;
  323. }
  324. }
  325. else
  326. {
  327. m_pSoundNames = NULL;
  328. }
  329. m_nConvertedNames = src.m_nConvertedNames;
  330. if ( m_nConvertedNames )
  331. {
  332. if ( m_nConvertedNames > 1 )
  333. {
  334. m_pConvertedNames = (SoundFile*)malloc( sizeof(SoundFile)*m_nConvertedNames);
  335. memcpy( m_pConvertedNames, src.m_pConvertedNames, m_nConvertedNames * sizeof(SoundFile) );
  336. }
  337. else
  338. {
  339. m_pConvertedNames = src.m_pConvertedNames;
  340. }
  341. }
  342. else
  343. {
  344. m_pConvertedNames = NULL;
  345. }
  346. had_missing_wave_files = src.had_missing_wave_files;
  347. uses_gender_token = src.uses_gender_token;
  348. }
  349. #define CompareInterval( i1, i2 ) ( memcmp( &(i1), &(i2), sizeof(i1) ) == 0 )
  350. bool CSoundParametersInternal::operator == ( const CSoundParametersInternal& other ) const
  351. {
  352. if ( this == &other )
  353. return true;
  354. if ( channel != other.channel )
  355. return false;
  356. if ( !CompareInterval( volume, other.volume ) )
  357. return false;
  358. if ( !CompareInterval( pitch, other.pitch ) )
  359. return false;
  360. if ( !CompareInterval( soundlevel, other.soundlevel ) )
  361. return false;
  362. if ( delay_msec != other.delay_msec )
  363. return false;
  364. if ( play_to_owner_only != other.play_to_owner_only )
  365. return false;
  366. if ( m_nSoundNames != other.m_nSoundNames )
  367. return false;
  368. // Compare items
  369. int c = m_nSoundNames;
  370. for ( int i = 0; i < c; i++ )
  371. {
  372. if ( GetSoundNames()[ i ].symbol != other.GetSoundNames()[ i ].symbol )
  373. return false;
  374. }
  375. return true;
  376. }
  377. float16 ZERO_FLOAT16;
  378. const char *CSoundParametersInternal::VolumeToString( void ) const
  379. {
  380. if ( volume.range == ZERO_FLOAT16 )
  381. {
  382. return _VolumeToString( volume.start );
  383. }
  384. static char sz[ 64 ];
  385. Q_snprintf( sz, sizeof( sz ), "%.3f, %.3f", (float)volume.start, (float)volume.start + (float)volume.range );
  386. return sz;
  387. }
  388. const char *CSoundParametersInternal::ChannelToString( void ) const
  389. {
  390. return _ChannelToString( channel );
  391. }
  392. const char *CSoundParametersInternal::SoundLevelToString( void ) const
  393. {
  394. if ( soundlevel.range == 0 )
  395. {
  396. return _SoundLevelToString( (soundlevel_t)(int)soundlevel.start );
  397. }
  398. static char sz[ 64 ];
  399. Q_snprintf( sz, sizeof( sz ), "%i, %i", (soundlevel_t)(int)soundlevel.start, (soundlevel_t)(int)(soundlevel.start + soundlevel.range ) );
  400. return sz;
  401. }
  402. const char *CSoundParametersInternal::PitchToString( void ) const
  403. {
  404. if ( pitch.range == 0 )
  405. {
  406. return _PitchToString( (int)pitch.start );
  407. }
  408. static char sz[ 64 ];
  409. Q_snprintf( sz, sizeof( sz ), "%i, %i", (int)pitch.start, (int)(pitch.start + pitch.range ) );
  410. return sz;
  411. }
  412. void CSoundParametersInternal::VolumeFromString( const char *sz )
  413. {
  414. if ( !Q_strcasecmp( sz, "VOL_NORM" ) )
  415. {
  416. volume.start = VOL_NORM;
  417. volume.range = 0.0f;
  418. }
  419. else
  420. {
  421. volume.FromInterval( ReadInterval( sz ) );
  422. }
  423. }
  424. void CSoundParametersInternal::ChannelFromString( const char *sz )
  425. {
  426. channel = TextToChannel( sz );
  427. }
  428. void CSoundParametersInternal::PitchFromString( const char *sz )
  429. {
  430. if ( !Q_strcasecmp( sz, "PITCH_NORM" ) )
  431. {
  432. pitch.start = PITCH_NORM;
  433. pitch.range = 0;
  434. }
  435. else if ( !Q_strcasecmp( sz, "PITCH_LOW" ) )
  436. {
  437. pitch.start = PITCH_LOW;
  438. pitch.range = 0;
  439. }
  440. else if ( !Q_strcasecmp( sz, "PITCH_HIGH" ) )
  441. {
  442. pitch.start = PITCH_HIGH;
  443. pitch.range = 0;
  444. }
  445. else
  446. {
  447. pitch.FromInterval( ReadInterval( sz ) );
  448. }
  449. }
  450. void CSoundParametersInternal::SoundLevelFromString( const char *sz )
  451. {
  452. if ( !Q_strncasecmp( sz, "SNDLVL_", strlen( "SNDLVL_" ) ) )
  453. {
  454. soundlevel.start = TextToSoundLevel( sz );
  455. soundlevel.range = 0;
  456. }
  457. else
  458. {
  459. soundlevel.FromInterval( ReadInterval( sz ) );
  460. }
  461. }
  462. void CSoundParametersInternal::AddToTail( SoundFile **pDest, uint16 *pDestCount, const SoundFile &source )
  463. {
  464. (*pDestCount)++;
  465. if ( *pDestCount == 1 )
  466. {
  467. // NOTE: when there's only one soundfile in the list, we store it
  468. // packed into the pointer itself, the four bytes for the pointer is just used to store the sound file!
  469. COMPILE_TIME_ASSERT( sizeof(SoundFile) <= sizeof(SoundFile *) );
  470. *((SoundFile *)(pDest)) = source;
  471. }
  472. else
  473. {
  474. SoundFile temp;
  475. if ( *pDestCount == 2 )
  476. {
  477. // Copying from a list of one soundfile. Save off the struct
  478. // packed into the pointer field.
  479. temp = *((SoundFile *)(pDest));
  480. *pDest = NULL;
  481. }
  482. *pDest = (SoundFile *)realloc( *pDest, (*pDestCount) * sizeof(SoundFile) );
  483. (*pDest)[ *pDestCount - 1 ] = source;
  484. if ( *pDestCount == 2 )
  485. {
  486. (*pDest)[0] = temp;
  487. }
  488. }
  489. }
  490. #endif // !_STATIC_LINKED || SOUNDEMITTERSYSTEM_DLL