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.

1830 lines
40 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
  9. #include "commonmacros.h"
  10. #include "basetypes.h"
  11. #include "sentence.h"
  12. #include "utlbuffer.h"
  13. #include <stdlib.h>
  14. #include "mathlib/vector.h"
  15. #include "mathlib/mathlib.h"
  16. #include <ctype.h>
  17. #include "checksum_crc.h"
  18. #include "phonemeconverter.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Purpose: converts an english string to unicode
  23. //-----------------------------------------------------------------------------
  24. int ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSize);
  25. #if PHONEME_EDITOR
  26. void CEmphasisSample::SetSelected( bool isSelected )
  27. {
  28. selected = isSelected;
  29. }
  30. void CPhonemeTag::SetSelected( bool isSelected )
  31. {
  32. m_bSelected = isSelected;
  33. }
  34. bool CPhonemeTag::GetSelected() const
  35. {
  36. return m_bSelected;
  37. }
  38. void CPhonemeTag::SetStartAndEndBytes( unsigned int start, unsigned int end )
  39. {
  40. m_uiStartByte = start;
  41. m_uiEndByte = end;
  42. }
  43. unsigned int CPhonemeTag::GetStartByte() const
  44. {
  45. return m_uiStartByte;
  46. }
  47. unsigned int CPhonemeTag::GetEndByte() const
  48. {
  49. return m_uiEndByte;
  50. }
  51. void CWordTag::SetSelected( bool isSelected )
  52. {
  53. m_bSelected = isSelected;
  54. }
  55. bool CWordTag::GetSelected() const
  56. {
  57. return m_bSelected;
  58. }
  59. void CWordTag::SetStartAndEndBytes( unsigned int start, unsigned int end )
  60. {
  61. m_uiStartByte = start;
  62. m_uiEndByte = end;
  63. }
  64. unsigned int CWordTag::GetStartByte() const
  65. {
  66. return m_uiStartByte;
  67. }
  68. unsigned int CWordTag::GetEndByte() const
  69. {
  70. return m_uiEndByte;
  71. }
  72. #else
  73. // xbox doesn't store this data
  74. void CEmphasisSample::SetSelected( bool isSelected ) {}
  75. void CPhonemeTag::SetSelected( bool isSelected ) {}
  76. bool CPhonemeTag::GetSelected() const { return false; }
  77. void CPhonemeTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) {}
  78. unsigned int CPhonemeTag::GetStartByte() const { return 0; }
  79. unsigned int CPhonemeTag::GetEndByte() const { return 0; }
  80. void CWordTag::SetSelected( bool isSelected ) {}
  81. bool CWordTag::GetSelected() const { return false; }
  82. void CWordTag::SetStartAndEndBytes( unsigned int start, unsigned int end ) {}
  83. unsigned int CWordTag::GetStartByte() const { return 0; }
  84. unsigned int CWordTag::GetEndByte() const { return 0; }
  85. #endif
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. //-----------------------------------------------------------------------------
  89. CWordTag::CWordTag( void )
  90. {
  91. m_pszWord = NULL;
  92. SetStartAndEndBytes( 0, 0 );
  93. m_flStartTime = 0.0f;
  94. m_flEndTime = 0.0f;
  95. SetSelected( false );
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose:
  99. // Input : from -
  100. //-----------------------------------------------------------------------------
  101. CWordTag::CWordTag( const CWordTag& from )
  102. {
  103. m_pszWord = NULL;
  104. SetWord( from.m_pszWord );
  105. SetStartAndEndBytes( from.GetStartByte(), from.GetEndByte() );
  106. m_flStartTime = from.m_flStartTime;
  107. m_flEndTime = from.m_flEndTime;
  108. SetSelected( from.GetSelected() );
  109. for ( int p = 0; p < from.m_Phonemes.Count(); p++ )
  110. {
  111. CPhonemeTag *newPhoneme = new CPhonemeTag( *from.m_Phonemes[ p ] );
  112. m_Phonemes.AddToTail( newPhoneme );
  113. }
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. // Input : *word -
  118. //-----------------------------------------------------------------------------
  119. CWordTag::CWordTag( const char *word )
  120. {
  121. SetStartAndEndBytes( 0, 0 );
  122. m_flStartTime = 0.0f;
  123. m_flEndTime = 0.0f;
  124. m_pszWord = NULL;
  125. SetSelected( false );
  126. SetWord( word );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. CWordTag::~CWordTag( void )
  132. {
  133. delete[] m_pszWord;
  134. while ( m_Phonemes.Count() > 0 )
  135. {
  136. delete m_Phonemes[ 0 ];
  137. m_Phonemes.Remove( 0 );
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. // Input : *tag -
  143. // Output : int
  144. //-----------------------------------------------------------------------------
  145. int CWordTag::IndexOfPhoneme( CPhonemeTag *tag )
  146. {
  147. for ( int i = 0 ; i < m_Phonemes.Count(); i++ )
  148. {
  149. CPhonemeTag *p = m_Phonemes[ i ];
  150. if ( p == tag )
  151. return i;
  152. }
  153. return -1;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. // Input : *word -
  158. //-----------------------------------------------------------------------------
  159. void CWordTag::SetWord( const char *word )
  160. {
  161. delete[] m_pszWord;
  162. m_pszWord = NULL;
  163. if ( !word || !word[ 0 ] )
  164. return;
  165. int len = strlen( word ) + 1;
  166. m_pszWord = new char[ len ];
  167. Assert( m_pszWord );
  168. Q_strncpy( m_pszWord, word, len );
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose:
  172. // Output : const char
  173. //-----------------------------------------------------------------------------
  174. const char *CWordTag::GetWord() const
  175. {
  176. return m_pszWord ? m_pszWord : "";
  177. }
  178. unsigned int CWordTag::ComputeDataCheckSum()
  179. {
  180. int i;
  181. int c;
  182. CRC32_t crc;
  183. CRC32_Init( &crc );
  184. // Checksum the text
  185. if ( m_pszWord != NULL )
  186. {
  187. CRC32_ProcessBuffer( &crc, m_pszWord, Q_strlen( m_pszWord ) );
  188. }
  189. // Checksum phonemes
  190. c = m_Phonemes.Count();
  191. for ( i = 0; i < c; ++i )
  192. {
  193. CPhonemeTag *phoneme = m_Phonemes[ i ];
  194. unsigned int phonemeCheckSum = phoneme->ComputeDataCheckSum();
  195. CRC32_ProcessBuffer( &crc, &phonemeCheckSum, sizeof( unsigned int ) );
  196. }
  197. // Checksum timestamps
  198. CRC32_ProcessBuffer( &crc, &m_flStartTime, sizeof( float ) );
  199. CRC32_ProcessBuffer( &crc, &m_flEndTime, sizeof( float ) );
  200. CRC32_Final( &crc );
  201. return ( unsigned int )crc;
  202. }
  203. CBasePhonemeTag::CBasePhonemeTag()
  204. {
  205. m_flStartTime = 0;
  206. m_flEndTime = 0;
  207. m_nPhonemeCode = 0;
  208. }
  209. CBasePhonemeTag::CBasePhonemeTag( const CBasePhonemeTag& from )
  210. {
  211. memcpy( this, &from, sizeof(*this) );
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. CPhonemeTag::CPhonemeTag( void )
  217. {
  218. m_szPhoneme = NULL;
  219. SetStartAndEndBytes( 0, 0 );
  220. SetSelected( false );
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose:
  224. // Input : from -
  225. //-----------------------------------------------------------------------------
  226. CPhonemeTag::CPhonemeTag( const CPhonemeTag& from ) :
  227. BaseClass( from )
  228. {
  229. SetStartAndEndBytes( from.GetStartByte(), from.GetEndByte() );
  230. SetSelected( from.GetSelected() );
  231. m_szPhoneme = NULL;
  232. SetTag( from.GetTag() );
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose:
  236. // Input : *phoneme -
  237. //-----------------------------------------------------------------------------
  238. CPhonemeTag::CPhonemeTag( const char *phoneme )
  239. {
  240. SetStartAndEndBytes( 0, 0 );
  241. SetStartTime( 0.0f );
  242. SetEndTime( 0.0f );
  243. SetSelected( false );
  244. SetPhonemeCode( 0 );
  245. m_szPhoneme = NULL;
  246. SetTag( phoneme );
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose:
  250. //-----------------------------------------------------------------------------
  251. CPhonemeTag::~CPhonemeTag( void )
  252. {
  253. delete[] m_szPhoneme;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose:
  257. // Input : *phoneme -
  258. //-----------------------------------------------------------------------------
  259. void CPhonemeTag::SetTag( const char *phoneme )
  260. {
  261. delete m_szPhoneme;
  262. m_szPhoneme = NULL;
  263. if ( !phoneme || !phoneme [ 0 ] )
  264. return;
  265. int len = Q_strlen( phoneme ) + 1;
  266. m_szPhoneme = new char[ len ];
  267. Assert( m_szPhoneme );
  268. Q_strncpy( m_szPhoneme, phoneme, len );
  269. }
  270. char const *CPhonemeTag::GetTag() const
  271. {
  272. return m_szPhoneme ? m_szPhoneme : "";
  273. }
  274. unsigned int CPhonemeTag::ComputeDataCheckSum()
  275. {
  276. CRC32_t crc;
  277. CRC32_Init( &crc );
  278. // Checksum the text
  279. CRC32_ProcessBuffer( &crc, m_szPhoneme, Q_strlen( m_szPhoneme ) );
  280. int phonemeCode = GetPhonemeCode();
  281. CRC32_ProcessBuffer( &crc, &phonemeCode, sizeof( int ) );
  282. // Checksum timestamps
  283. float startTime = GetStartTime();
  284. float endTime = GetEndTime();
  285. CRC32_ProcessBuffer( &crc, &startTime, sizeof( float ) );
  286. CRC32_ProcessBuffer( &crc, &endTime, sizeof( float ) );
  287. CRC32_Final( &crc );
  288. return ( unsigned int )crc;
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose: Simple language to string and string to language lookup dictionary
  292. //-----------------------------------------------------------------------------
  293. #pragma pack(1)
  294. struct CCLanguage
  295. {
  296. int type;
  297. char const *name;
  298. unsigned char r, g, b; // For faceposer, indicator color for this language
  299. };
  300. static CCLanguage g_CCLanguageLookup[] =
  301. {
  302. { CC_ENGLISH, "english", 0, 0, 0 },
  303. { CC_FRENCH, "french", 150, 0, 0 },
  304. { CC_GERMAN, "german", 0, 150, 0 },
  305. { CC_ITALIAN, "italian", 0, 150, 150 },
  306. { CC_KOREAN, "korean", 150, 0, 150 },
  307. { CC_SCHINESE, "schinese", 150, 0, 150 },
  308. { CC_SPANISH, "spanish", 0, 0, 150 },
  309. { CC_TCHINESE, "tchinese", 150, 0, 150 },
  310. { CC_JAPANESE, "japanese", 250, 150, 0 },
  311. { CC_RUSSIAN, "russian", 0, 250, 150 },
  312. { CC_THAI, "thai", 0 , 150, 250 },
  313. { CC_PORTUGUESE,"portuguese", 0 , 0, 150 },
  314. };
  315. #pragma pack()
  316. void CSentence::ColorForLanguage( int language, unsigned char& r, unsigned char& g, unsigned char& b )
  317. {
  318. r = g = b = 0;
  319. if ( language < 0 || language >= CC_NUM_LANGUAGES )
  320. {
  321. return;
  322. }
  323. r = g_CCLanguageLookup[ language ].r;
  324. g = g_CCLanguageLookup[ language ].g;
  325. b = g_CCLanguageLookup[ language ].b;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. // Input : language -
  330. // Output : char const
  331. //-----------------------------------------------------------------------------
  332. char const *CSentence::NameForLanguage( int language )
  333. {
  334. if ( language < 0 || language >= CC_NUM_LANGUAGES )
  335. return "unknown_language";
  336. CCLanguage *entry = &g_CCLanguageLookup[ language ];
  337. Assert( entry->type == language );
  338. return entry->name;
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose:
  342. // Input : *name -
  343. // Output : int
  344. //-----------------------------------------------------------------------------
  345. int CSentence::LanguageForName( char const *name )
  346. {
  347. int l;
  348. for ( l = 0; l < CC_NUM_LANGUAGES; l++ )
  349. {
  350. CCLanguage *entry = &g_CCLanguageLookup[ l ];
  351. Assert( entry->type == l );
  352. if ( !stricmp( entry->name, name ) )
  353. return l;
  354. }
  355. return -1;
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose:
  359. //-----------------------------------------------------------------------------
  360. CSentence::CSentence( void )
  361. {
  362. #if PHONEME_EDITOR
  363. m_nResetWordBase = 0;
  364. m_szText = 0;
  365. m_uCheckSum = 0;
  366. #endif
  367. m_bShouldVoiceDuck = false;
  368. m_bStoreCheckSum = false;
  369. m_bIsValid = false;
  370. m_bIsCached = false;
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose:
  374. //-----------------------------------------------------------------------------
  375. CSentence::~CSentence( void )
  376. {
  377. Reset();
  378. #if PHONEME_EDITOR
  379. delete[] m_szText;
  380. #endif
  381. }
  382. void CSentence::ParsePlaintext( CUtlBuffer& buf )
  383. {
  384. char token[ 4096 ];
  385. char text[ 4096 ];
  386. text[ 0 ] = 0;
  387. while ( 1 )
  388. {
  389. buf.GetString( token, sizeof( token ) );
  390. if ( !stricmp( token, "}" ) )
  391. break;
  392. Q_strncat( text, token, sizeof( text ), COPY_ALL_CHARACTERS );
  393. Q_strncat( text, " ", sizeof( text ), COPY_ALL_CHARACTERS );
  394. }
  395. SetText( text );
  396. }
  397. void CSentence::ParseWords( CUtlBuffer& buf )
  398. {
  399. char token[ 4096 ];
  400. char word[ 256 ];
  401. float start, end;
  402. while ( 1 )
  403. {
  404. buf.GetString( token, sizeof( token ) );
  405. if ( !stricmp( token, "}" ) )
  406. break;
  407. if ( stricmp( token, "WORD" ) )
  408. break;
  409. buf.GetString( token, sizeof( token ) );
  410. Q_strncpy( word, token, sizeof( word ) );
  411. buf.GetString( token, sizeof( token ) );
  412. start = atof( token );
  413. buf.GetString( token, sizeof( token ) );
  414. end = atof( token );
  415. CWordTag *wt = new CWordTag( word );
  416. Assert( wt );
  417. wt->m_flStartTime = start;
  418. wt->m_flEndTime = end;
  419. AddWordTag( wt );
  420. buf.GetString( token, sizeof( token ) );
  421. if ( stricmp( token, "{" ) )
  422. break;
  423. while ( 1 )
  424. {
  425. buf.GetString( token, sizeof( token ) );
  426. if ( !stricmp( token, "}" ) )
  427. break;
  428. // Parse phoneme
  429. int code;
  430. char phonemename[ 256 ];
  431. float start, end;
  432. float volume;
  433. code = atoi( token );
  434. buf.GetString( token, sizeof( token ) );
  435. Q_strncpy( phonemename, token, sizeof( phonemename ) );
  436. buf.GetString( token, sizeof( token ) );
  437. start = atof( token );
  438. buf.GetString( token, sizeof( token ) );
  439. end = atof( token );
  440. buf.GetString( token, sizeof( token ) );
  441. volume = atof( token );
  442. CPhonemeTag *pt = new CPhonemeTag();
  443. Assert( pt );
  444. pt->SetPhonemeCode( code );
  445. pt->SetTag( phonemename );
  446. pt->SetStartTime( start );
  447. pt->SetEndTime( end );
  448. AddPhonemeTag( wt, pt );
  449. }
  450. }
  451. }
  452. void CSentence::ParseEmphasis( CUtlBuffer& buf )
  453. {
  454. char token[ 4096 ];
  455. while ( 1 )
  456. {
  457. buf.GetString( token, sizeof( token ) );
  458. if ( !stricmp( token, "}" ) )
  459. break;
  460. char t[ 256 ];
  461. Q_strncpy( t, token, sizeof( t ) );
  462. buf.GetString( token, sizeof( token ) );
  463. char value[ 256 ];
  464. Q_strncpy( value, token, sizeof( value ) );
  465. CEmphasisSample sample;
  466. sample.SetSelected( false );
  467. sample.time = atof( t );
  468. sample.value = atof( value );
  469. m_EmphasisSamples.AddToTail( sample );
  470. }
  471. }
  472. // This is obsolete, so it doesn't do anything with the data which is parsed.
  473. void CSentence::ParseCloseCaption( CUtlBuffer& buf )
  474. {
  475. char token[ 4096 ];
  476. while ( 1 )
  477. {
  478. // Format is
  479. // language_name
  480. // {
  481. // PHRASE char streamlength "streambytes" starttime endtime
  482. // PHRASE unicode streamlength "streambytes" starttime endtime
  483. // }
  484. buf.GetString( token, sizeof( token ) );
  485. if ( !stricmp( token, "}" ) )
  486. break;
  487. buf.GetString( token, sizeof( token ) );
  488. if ( stricmp( token, "{" ) )
  489. break;
  490. buf.GetString( token, sizeof( token ) );
  491. while ( 1 )
  492. {
  493. if ( !stricmp( token, "}" ) )
  494. break;
  495. if ( stricmp( token, "PHRASE" ) )
  496. break;
  497. char cc_type[32];
  498. char cc_stream[ 4096 ];
  499. int cc_length;
  500. memset( cc_stream, 0, sizeof( cc_stream ) );
  501. buf.GetString( token, sizeof( token ) );
  502. Q_strncpy( cc_type, token, sizeof( cc_type ) );
  503. bool unicode = false;
  504. if ( !stricmp( cc_type, "unicode" ) )
  505. {
  506. unicode = true;
  507. }
  508. else if ( stricmp( cc_type, "char" ) )
  509. {
  510. Assert( 0 );
  511. }
  512. buf.GetString( token, sizeof( token ) );
  513. cc_length = atoi( token );
  514. Assert( cc_length >= 0 && cc_length < sizeof( cc_stream ) );
  515. // Skip space
  516. buf.GetChar();
  517. buf.Get( cc_stream, cc_length );
  518. cc_stream[ cc_length ] = 0;
  519. // Skip space
  520. buf.GetChar();
  521. buf.GetString( token, sizeof( token ) );
  522. buf.GetString( token, sizeof( token ) );
  523. buf.GetString( token, sizeof( token ) );
  524. }
  525. }
  526. }
  527. void CSentence::ParseOptions( CUtlBuffer& buf )
  528. {
  529. char token[ 4096 ];
  530. while ( 1 )
  531. {
  532. buf.GetString( token, sizeof( token ) );
  533. if ( !stricmp( token, "}" ) )
  534. break;
  535. if ( Q_strlen( token ) == 0 )
  536. break;
  537. char key[ 256 ];
  538. Q_strncpy( key, token, sizeof( key ) );
  539. char value[ 256 ];
  540. buf.GetString( token, sizeof( token ) );
  541. Q_strncpy( value, token, sizeof( value ) );
  542. if ( !strcmpi( key, "voice_duck" ) )
  543. {
  544. SetVoiceDuck( atoi(value) ? true : false );
  545. }
  546. else if ( !strcmpi( key, "checksum" ) )
  547. {
  548. SetDataCheckSum( (unsigned int)atoi( value ) );
  549. }
  550. }
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose: VERSION 1.0 parser, need to implement new ones if
  554. // file format changes!!!
  555. // Input : buf -
  556. //-----------------------------------------------------------------------------
  557. void CSentence::ParseDataVersionOnePointZero( CUtlBuffer& buf )
  558. {
  559. char token[ 4096 ];
  560. while ( 1 )
  561. {
  562. buf.GetString( token, sizeof( token ) );
  563. if ( strlen( token ) <= 0 )
  564. break;
  565. char section[ 256 ];
  566. Q_strncpy( section, token, sizeof( section ) );
  567. buf.GetString( token, sizeof( token ) );
  568. if ( stricmp( token, "{" ) )
  569. break;
  570. if ( !stricmp( section, "PLAINTEXT" ) )
  571. {
  572. ParsePlaintext( buf );
  573. }
  574. else if ( !stricmp( section, "WORDS" ) )
  575. {
  576. ParseWords( buf );
  577. }
  578. else if ( !stricmp( section, "EMPHASIS" ) )
  579. {
  580. ParseEmphasis( buf );
  581. }
  582. else if ( !stricmp( section, "CLOSECAPTION" ) )
  583. {
  584. // NOTE: CLOSECAPTION IS NO LONGER VALID
  585. // This just skips the section of data.
  586. ParseCloseCaption( buf );
  587. }
  588. else if ( !stricmp( section, "OPTIONS" ) )
  589. {
  590. ParseOptions( buf );
  591. }
  592. }
  593. }
  594. float g_maxTime;
  595. // This is a compressed save of just the data needed to drive phonemes in the engine (no word / sentence text, etc )
  596. //-----------------------------------------------------------------------------
  597. // Purpose:
  598. // Input : buf -
  599. //-----------------------------------------------------------------------------
  600. void CSentence::CacheSaveToBuffer( CUtlBuffer& buf, int version )
  601. {
  602. Assert( !buf.IsText() );
  603. Assert( m_bIsCached );
  604. int i;
  605. unsigned short pcount = GetRuntimePhonemeCount();
  606. // header
  607. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  608. {
  609. buf.PutChar( version );
  610. buf.PutChar( 0 );
  611. buf.PutChar( 0 );
  612. buf.PutChar( 0 );
  613. buf.PutInt( pcount );
  614. }
  615. else
  616. {
  617. buf.PutChar( version );
  618. buf.PutShort( pcount );
  619. }
  620. // phoneme
  621. if ( version == CACHED_SENTENCE_VERSION_PACKED )
  622. {
  623. for ( i = 0; i < pcount; ++i )
  624. {
  625. const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i );
  626. Assert( phoneme );
  627. buf.PutUnsignedChar( CodeToByteCode( phoneme->GetPhonemeCode() ) );
  628. float start = phoneme->GetStartTime() * 1000.0f/5.0f;
  629. Assert( start >= -32768.0f && start <= 32767.0f );
  630. start = clamp( start, -32768.0f, 32767.0f );
  631. buf.PutShort( (short)start );
  632. float end = phoneme->GetEndTime() * 1000.0f/5.0f;
  633. Assert( end >= -32768.0f && end <= 32767.0f );
  634. end = clamp( end, -32768.0f, 32767.0f );
  635. buf.PutShort( (short)end );
  636. }
  637. }
  638. else if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  639. {
  640. for ( i = 0; i < pcount; ++i )
  641. {
  642. const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i );
  643. Assert( phoneme );
  644. buf.PutInt( phoneme->GetPhonemeCode() );
  645. buf.PutFloat( phoneme->GetStartTime() );
  646. buf.PutFloat( phoneme->GetEndTime() );
  647. }
  648. }
  649. else
  650. {
  651. for ( i = 0; i < pcount; ++i )
  652. {
  653. const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i );
  654. Assert( phoneme );
  655. buf.PutShort( phoneme->GetPhonemeCode() );
  656. buf.PutFloat( phoneme->GetStartTime() );
  657. buf.PutFloat( phoneme->GetEndTime() );
  658. }
  659. }
  660. // emphasis samples and voice duck
  661. int c = m_EmphasisSamples.Count();
  662. Assert( c <= 32767 );
  663. if ( version == CACHED_SENTENCE_VERSION_PACKED )
  664. {
  665. buf.PutShort( c );
  666. for ( i = 0; i < c; i++ )
  667. {
  668. CEmphasisSample *sample = &m_EmphasisSamples[i];
  669. Assert( sample );
  670. float scaledTime = sample->time * 1000.0f/5.0f;
  671. Assert( scaledTime >= -32768.0f && scaledTime <= 32767.0f );
  672. scaledTime = clamp( scaledTime, -32768.0f, 32767.0f );
  673. buf.PutShort( scaledTime );
  674. short scaledValue = (short)clamp( sample->value * 32767.0f, 0.0f, 32767.0f );
  675. buf.PutShort( scaledValue );
  676. }
  677. buf.PutChar( GetVoiceDuck() ? 1 : 0 );
  678. }
  679. else if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  680. {
  681. buf.PutInt( c );
  682. for ( i = 0; i < c; i++ )
  683. {
  684. CEmphasisSample *sample = &m_EmphasisSamples[i];
  685. Assert( sample );
  686. buf.PutFloat( sample->time );
  687. buf.PutFloat( sample->value );
  688. }
  689. buf.PutInt( GetVoiceDuck() ? 1 : 0 );
  690. }
  691. else
  692. {
  693. buf.PutShort( c );
  694. for ( i = 0; i < c; i++ )
  695. {
  696. CEmphasisSample *sample = &m_EmphasisSamples[i];
  697. Assert( sample );
  698. buf.PutFloat( sample->time );
  699. short scaledValue = (short)clamp( sample->value * 32767.0f, 0.0f, 32767.0f );
  700. buf.PutShort( scaledValue );
  701. }
  702. buf.PutChar( GetVoiceDuck() ? 1 : 0 );
  703. }
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Purpose:
  707. // Input : buf -
  708. //-----------------------------------------------------------------------------
  709. void CSentence::CacheRestoreFromBuffer( CUtlBuffer& buf )
  710. {
  711. Assert( !buf.IsText() );
  712. Reset();
  713. m_bIsCached = true;
  714. // determine format
  715. int version = buf.GetChar();
  716. if ( version != CACHED_SENTENCE_VERSION &&
  717. version != CACHED_SENTENCE_VERSION_ALIGNED &&
  718. version != CACHED_SENTENCE_VERSION_PACKED )
  719. {
  720. // Uh oh, version changed...
  721. m_bIsValid = false;
  722. return;
  723. }
  724. unsigned short pcount;
  725. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  726. {
  727. buf.GetChar();
  728. buf.GetChar();
  729. buf.GetChar();
  730. pcount = buf.GetInt();
  731. }
  732. else
  733. {
  734. pcount = (unsigned short)buf.GetShort();
  735. }
  736. // phonemes
  737. CPhonemeTag pt;
  738. int i;
  739. if ( version == CACHED_SENTENCE_VERSION_PACKED )
  740. {
  741. for ( i = 0; i < pcount; ++i )
  742. {
  743. unsigned char code = buf.GetUnsignedChar();
  744. float st = (float)buf.GetShort() * 5.0f/1000.0f;
  745. float et = (float)buf.GetShort() * 5.0f/1000.0f;
  746. pt.SetPhonemeCode( ByteCodeToCode( code ) );
  747. pt.SetStartTime( st );
  748. pt.SetEndTime( et );
  749. AddRuntimePhoneme( &pt );
  750. }
  751. }
  752. else if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  753. {
  754. for ( i = 0; i < pcount; ++i )
  755. {
  756. int code = buf.GetInt();
  757. float st = buf.GetFloat();
  758. float et = buf.GetFloat();
  759. pt.SetPhonemeCode( code );
  760. pt.SetStartTime( st );
  761. pt.SetEndTime( et );
  762. AddRuntimePhoneme( &pt );
  763. }
  764. }
  765. else
  766. {
  767. for ( i = 0; i < pcount; ++i )
  768. {
  769. unsigned short code = buf.GetShort();
  770. float st = buf.GetFloat();
  771. float et = buf.GetFloat();
  772. pt.SetPhonemeCode( code );
  773. pt.SetStartTime( st );
  774. pt.SetEndTime( et );
  775. AddRuntimePhoneme( &pt );
  776. }
  777. }
  778. // emphasis samples and voice duck
  779. int c;
  780. if ( version == CACHED_SENTENCE_VERSION_PACKED )
  781. {
  782. c = buf.GetShort();
  783. for ( i = 0; i < c; i++ )
  784. {
  785. CEmphasisSample sample;
  786. sample.SetSelected( false );
  787. sample.time = (float)buf.GetShort() * 5.0f/1000.0f;
  788. sample.value = (float)buf.GetShort() * 1.0f/32767.0f;
  789. m_EmphasisSamples.AddToTail( sample );
  790. }
  791. SetVoiceDuck( buf.GetChar() == 0 ? false : true );
  792. }
  793. else if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  794. {
  795. c = buf.GetInt();
  796. for ( i = 0; i < c; i++ )
  797. {
  798. CEmphasisSample sample;
  799. sample.SetSelected( false );
  800. sample.time = buf.GetFloat();
  801. sample.value = buf.GetFloat();
  802. m_EmphasisSamples.AddToTail( sample );
  803. }
  804. SetVoiceDuck( buf.GetInt() == 0 ? false : true );
  805. }
  806. else
  807. {
  808. c = buf.GetShort();
  809. for ( i = 0; i < c; i++ )
  810. {
  811. CEmphasisSample sample;
  812. sample.SetSelected( false );
  813. sample.time = buf.GetFloat();
  814. sample.value = (float)buf.GetShort() / 32767.0f;
  815. m_EmphasisSamples.AddToTail( sample );
  816. }
  817. SetVoiceDuck( buf.GetChar() == 0 ? false : true );
  818. }
  819. m_bIsValid = true;
  820. }
  821. int CSentence::GetRuntimePhonemeCount() const
  822. {
  823. return m_RunTimePhonemes.Count();
  824. }
  825. const CBasePhonemeTag *CSentence::GetRuntimePhoneme( int i ) const
  826. {
  827. Assert( m_bIsCached );
  828. return m_RunTimePhonemes[ i ];
  829. }
  830. void CSentence::ClearRuntimePhonemes()
  831. {
  832. while ( m_RunTimePhonemes.Count() > 0 )
  833. {
  834. CBasePhonemeTag *tag = m_RunTimePhonemes[ 0 ];
  835. delete tag;
  836. m_RunTimePhonemes.Remove( 0 );
  837. }
  838. }
  839. void CSentence::AddRuntimePhoneme( const CPhonemeTag *src )
  840. {
  841. Assert( m_bIsCached );
  842. CBasePhonemeTag *tag = new CBasePhonemeTag();
  843. *tag = *src;
  844. m_RunTimePhonemes.AddToTail( tag );
  845. }
  846. void CSentence::MakeRuntimeOnly()
  847. {
  848. m_bIsCached = true;
  849. #if PHONEME_EDITOR
  850. delete m_szText;
  851. m_szText = NULL;
  852. int c = m_Words.Count();
  853. for ( int i = 0; i < c; ++i )
  854. {
  855. CWordTag *word = m_Words[ i ];
  856. Assert( word );
  857. int pcount = word->m_Phonemes.Count();
  858. for ( int j = 0; j < pcount; ++j )
  859. {
  860. CPhonemeTag *phoneme = word->m_Phonemes[ j ];
  861. Assert( phoneme );
  862. AddRuntimePhoneme( phoneme );
  863. }
  864. }
  865. // Remove all existing words
  866. while ( m_Words.Count() > 0 )
  867. {
  868. CWordTag *word = m_Words[ 0 ];
  869. delete word;
  870. m_Words.Remove( 0 );
  871. }
  872. #endif
  873. m_bIsValid = true;
  874. }
  875. void CSentence::SaveToBuffer( CUtlBuffer& buf )
  876. {
  877. #if PHONEME_EDITOR
  878. Assert( !m_bIsCached );
  879. int i, j;
  880. buf.Printf( "VERSION 1.0\n" );
  881. buf.Printf( "PLAINTEXT\n" );
  882. buf.Printf( "{\n" );
  883. buf.Printf( "%s\n", GetText() );
  884. buf.Printf( "}\n" );
  885. buf.Printf( "WORDS\n" );
  886. buf.Printf( "{\n" );
  887. for ( i = 0; i < m_Words.Count(); i++ )
  888. {
  889. CWordTag *word = m_Words[ i ];
  890. Assert( word );
  891. buf.Printf( "WORD %s %.3f %.3f\n",
  892. word->GetWord(),
  893. word->m_flStartTime,
  894. word->m_flEndTime );
  895. buf.Printf( "{\n" );
  896. for ( j = 0; j < word->m_Phonemes.Count(); j++ )
  897. {
  898. CPhonemeTag *phoneme = word->m_Phonemes[ j ];
  899. Assert( phoneme );
  900. buf.Printf( "%i %s %.3f %.3f 1\n",
  901. phoneme->GetPhonemeCode(),
  902. phoneme->GetTag(),
  903. phoneme->GetStartTime(),
  904. phoneme->GetEndTime() );
  905. }
  906. buf.Printf( "}\n" );
  907. }
  908. buf.Printf( "}\n" );
  909. buf.Printf( "EMPHASIS\n" );
  910. buf.Printf( "{\n" );
  911. int c = m_EmphasisSamples.Count();
  912. for ( i = 0; i < c; i++ )
  913. {
  914. CEmphasisSample *sample = &m_EmphasisSamples[ i ];
  915. Assert( sample );
  916. buf.Printf( "%f %f\n", sample->time, sample->value );
  917. }
  918. buf.Printf( "}\n" );
  919. buf.Printf( "OPTIONS\n" );
  920. buf.Printf( "{\n" );
  921. buf.Printf( "voice_duck %d\n", GetVoiceDuck() ? 1 : 0 );
  922. if ( m_bStoreCheckSum )
  923. {
  924. buf.Printf( "checksum %d\n", m_uCheckSum );
  925. }
  926. buf.Printf( "}\n" );
  927. #else
  928. Assert( 0 );
  929. #endif
  930. }
  931. //-----------------------------------------------------------------------------
  932. // Purpose:
  933. // Input : *data -
  934. // size -
  935. //-----------------------------------------------------------------------------
  936. void CSentence::InitFromDataChunk( void *data, int size )
  937. {
  938. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  939. buf.EnsureCapacity( size );
  940. buf.Put( data, size );
  941. buf.SeekPut( CUtlBuffer::SEEK_HEAD, size );
  942. InitFromBuffer( buf );
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Purpose:
  946. // Input : buf -
  947. //-----------------------------------------------------------------------------
  948. void CSentence::InitFromBuffer( CUtlBuffer& buf )
  949. {
  950. Assert( buf.IsText() );
  951. Reset();
  952. char token[ 4096 ];
  953. buf.GetString( token, sizeof( token ) );
  954. if ( stricmp( token, "VERSION" ) )
  955. return;
  956. buf.GetString( token, sizeof( token ) );
  957. if ( atof( token ) == 1.0f )
  958. {
  959. ParseDataVersionOnePointZero( buf );
  960. m_bIsValid = true;
  961. }
  962. else
  963. {
  964. Assert( 0 );
  965. return;
  966. }
  967. }
  968. //-----------------------------------------------------------------------------
  969. // Purpose:
  970. // Output : int
  971. //-----------------------------------------------------------------------------
  972. int CSentence::GetWordBase( void )
  973. {
  974. #if PHONEME_EDITOR
  975. return m_nResetWordBase;
  976. #else
  977. Assert( 0 );
  978. return 0;
  979. #endif
  980. }
  981. //-----------------------------------------------------------------------------
  982. // Purpose:
  983. //-----------------------------------------------------------------------------
  984. void CSentence::ResetToBase( void )
  985. {
  986. #if PHONEME_EDITOR
  987. // Delete everything after m_nResetWordBase
  988. while ( m_Words.Count() > m_nResetWordBase )
  989. {
  990. delete m_Words[ m_Words.Count() - 1 ];
  991. m_Words.Remove( m_Words.Count() - 1 );
  992. }
  993. #endif
  994. ClearRuntimePhonemes();
  995. }
  996. //-----------------------------------------------------------------------------
  997. // Purpose:
  998. //-----------------------------------------------------------------------------
  999. void CSentence::MarkNewPhraseBase( void )
  1000. {
  1001. #if PHONEME_EDITOR
  1002. m_nResetWordBase = MAX( m_Words.Count(), 0 );
  1003. #endif
  1004. }
  1005. //-----------------------------------------------------------------------------
  1006. // Purpose:
  1007. //-----------------------------------------------------------------------------
  1008. void CSentence::Reset( void )
  1009. {
  1010. #if PHONEME_EDITOR
  1011. m_nResetWordBase = 0;
  1012. while ( m_Words.Count() > 0 )
  1013. {
  1014. delete m_Words[ 0 ];
  1015. m_Words.Remove( 0 );
  1016. }
  1017. #endif
  1018. m_EmphasisSamples.RemoveAll();
  1019. ClearRuntimePhonemes();
  1020. }
  1021. //-----------------------------------------------------------------------------
  1022. // Purpose:
  1023. // Input : *tag -
  1024. //-----------------------------------------------------------------------------
  1025. void CSentence::AddPhonemeTag( CWordTag *word, CPhonemeTag *tag )
  1026. {
  1027. word->m_Phonemes.AddToTail( tag );
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose:
  1031. // Input : *tag -
  1032. //-----------------------------------------------------------------------------
  1033. void CSentence::AddWordTag( CWordTag *tag )
  1034. {
  1035. #if PHONEME_EDITOR
  1036. m_Words.AddToTail( tag );
  1037. #endif
  1038. }
  1039. //-----------------------------------------------------------------------------
  1040. // Purpose:
  1041. // Output : int
  1042. //-----------------------------------------------------------------------------
  1043. int CSentence::CountPhonemes( void )
  1044. {
  1045. int c = 0;
  1046. #if PHONEME_EDITOR
  1047. for( int i = 0; i < m_Words.Count(); i++ )
  1048. {
  1049. CWordTag *word = m_Words[ i ];
  1050. c += word->m_Phonemes.Count();
  1051. }
  1052. #endif
  1053. return c;
  1054. }
  1055. //-----------------------------------------------------------------------------
  1056. // Purpose: // For legacy loading, try to find a word that contains the time
  1057. // Input : time -
  1058. // Output : CWordTag
  1059. //-----------------------------------------------------------------------------
  1060. CWordTag *CSentence::EstimateBestWord( float time )
  1061. {
  1062. #if PHONEME_EDITOR
  1063. CWordTag *bestWord = NULL;
  1064. for( int i = 0; i < m_Words.Count(); i++ )
  1065. {
  1066. CWordTag *word = m_Words[ i ];
  1067. if ( !word )
  1068. continue;
  1069. if ( word->m_flStartTime <= time && word->m_flEndTime >= time )
  1070. return word;
  1071. if ( time < word->m_flStartTime )
  1072. {
  1073. bestWord = word;
  1074. }
  1075. if ( time > word->m_flEndTime && bestWord )
  1076. return bestWord;
  1077. }
  1078. // return best word if we found one
  1079. if ( bestWord )
  1080. {
  1081. return bestWord;
  1082. }
  1083. // Return last word
  1084. if ( m_Words.Count() >= 1 )
  1085. {
  1086. return m_Words[ m_Words.Count() - 1 ];
  1087. }
  1088. #endif
  1089. // Oh well
  1090. return NULL;
  1091. }
  1092. //-----------------------------------------------------------------------------
  1093. // Purpose:
  1094. // Input : *phoneme -
  1095. // Output : CWordTag
  1096. //-----------------------------------------------------------------------------
  1097. CWordTag *CSentence::GetWordForPhoneme( CPhonemeTag *phoneme )
  1098. {
  1099. #if PHONEME_EDITOR
  1100. for( int i = 0; i < m_Words.Count(); i++ )
  1101. {
  1102. CWordTag *word = m_Words[ i ];
  1103. if ( !word )
  1104. continue;
  1105. for ( int j = 0 ; j < word->m_Phonemes.Count() ; j++ )
  1106. {
  1107. CPhonemeTag *p = word->m_Phonemes[ j ];
  1108. if ( p == phoneme )
  1109. {
  1110. return word;
  1111. }
  1112. }
  1113. }
  1114. #endif
  1115. return NULL;
  1116. }
  1117. //-----------------------------------------------------------------------------
  1118. // Purpose: Assignment operator
  1119. // Input : src -
  1120. // Output : CSentence&
  1121. //-----------------------------------------------------------------------------
  1122. CSentence& CSentence::operator=( const CSentence& src )
  1123. {
  1124. int i;
  1125. // Clear current stuff
  1126. Reset();
  1127. int c;
  1128. #if PHONEME_EDITOR
  1129. // Copy everything
  1130. for ( i = 0 ; i < src.m_Words.Count(); i++ )
  1131. {
  1132. CWordTag *word = src.m_Words[ i ];
  1133. CWordTag *newWord = new CWordTag( *word );
  1134. AddWordTag( newWord );
  1135. }
  1136. SetText( src.GetText() );
  1137. m_nResetWordBase = src.m_nResetWordBase;
  1138. c = src.m_EmphasisSamples.Count();
  1139. for ( i = 0; i < c; i++ )
  1140. {
  1141. CEmphasisSample s = src.m_EmphasisSamples[ i ];
  1142. m_EmphasisSamples.AddToTail( s );
  1143. }
  1144. #endif
  1145. m_bIsCached = src.m_bIsCached;
  1146. c = src.GetRuntimePhonemeCount();
  1147. for ( i = 0; i < c; i++ )
  1148. {
  1149. Assert( m_bIsCached );
  1150. const CBasePhonemeTag *tag = src.GetRuntimePhoneme( i );
  1151. CPhonemeTag full;
  1152. ((CBasePhonemeTag &)(full)) = *tag;
  1153. AddRuntimePhoneme( &full );
  1154. }
  1155. m_bShouldVoiceDuck = src.m_bShouldVoiceDuck;
  1156. #if PHONEME_EDITOR
  1157. m_bStoreCheckSum = src.m_bStoreCheckSum;
  1158. m_uCheckSum = src.m_uCheckSum;
  1159. #endif
  1160. m_bIsValid = src.m_bIsValid;
  1161. return (*this);
  1162. }
  1163. void CSentence::Append( float starttime, const CSentence& src )
  1164. {
  1165. #if PHONEME_EDITOR
  1166. int i;
  1167. // Combine
  1168. for ( i = 0 ; i < src.m_Words.Count(); i++ )
  1169. {
  1170. CWordTag *word = src.m_Words[ i ];
  1171. CWordTag *newWord = new CWordTag( *word );
  1172. newWord->m_flStartTime += starttime;
  1173. newWord->m_flEndTime += starttime;
  1174. // Offset times
  1175. int c = newWord->m_Phonemes.Count();
  1176. for ( int i = 0; i < c; ++i )
  1177. {
  1178. CPhonemeTag *tag = newWord->m_Phonemes[ i ];
  1179. tag->AddStartTime( starttime );
  1180. tag->AddEndTime( starttime );
  1181. }
  1182. AddWordTag( newWord );
  1183. }
  1184. if ( src.GetText()[ 0 ] )
  1185. {
  1186. char fulltext[ 4096 ];
  1187. if ( GetText()[ 0 ] )
  1188. {
  1189. Q_snprintf( fulltext, sizeof( fulltext ), "%s %s", GetText(), src.GetText() );
  1190. }
  1191. else
  1192. {
  1193. Q_strncpy( fulltext, src.GetText(), sizeof( fulltext ) );
  1194. }
  1195. SetText( fulltext );
  1196. }
  1197. int c = src.m_EmphasisSamples.Count();
  1198. for ( i = 0; i < c; i++ )
  1199. {
  1200. CEmphasisSample s = src.m_EmphasisSamples[ i ];
  1201. s.time += starttime;
  1202. m_EmphasisSamples.AddToTail( s );
  1203. }
  1204. // Or in voice duck settings
  1205. m_bShouldVoiceDuck |= src.m_bShouldVoiceDuck;
  1206. #else
  1207. Assert( 0 );
  1208. #endif
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Purpose:
  1212. // Input : *text -
  1213. //-----------------------------------------------------------------------------
  1214. void CSentence::SetText( const char *text )
  1215. {
  1216. #if PHONEME_EDITOR
  1217. delete[] m_szText;
  1218. m_szText = NULL;
  1219. if ( !text || !text[ 0 ] )
  1220. {
  1221. return;
  1222. }
  1223. int len = Q_strlen( text ) + 1;
  1224. m_szText = new char[ len ];
  1225. Assert( m_szText );
  1226. Q_strncpy( m_szText, text, len );
  1227. #endif
  1228. }
  1229. //-----------------------------------------------------------------------------
  1230. // Purpose:
  1231. // Output : const char
  1232. //-----------------------------------------------------------------------------
  1233. const char *CSentence::GetText( void ) const
  1234. {
  1235. #if PHONEME_EDITOR
  1236. return m_szText ? m_szText : "";
  1237. #else
  1238. return "";
  1239. #endif
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Purpose:
  1243. //-----------------------------------------------------------------------------
  1244. void CSentence::SetTextFromWords( void )
  1245. {
  1246. #if PHONEME_EDITOR
  1247. char fulltext[ 1024 ];
  1248. fulltext[ 0 ] = 0;
  1249. for ( int i = 0 ; i < m_Words.Count(); i++ )
  1250. {
  1251. CWordTag *word = m_Words[ i ];
  1252. Q_strncat( fulltext, word->GetWord(), sizeof( fulltext ), COPY_ALL_CHARACTERS );
  1253. if ( i != m_Words.Count() )
  1254. {
  1255. Q_strncat( fulltext, " ", sizeof( fulltext ), COPY_ALL_CHARACTERS );
  1256. }
  1257. }
  1258. SetText( fulltext );
  1259. #endif
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Purpose:
  1263. //-----------------------------------------------------------------------------
  1264. void CSentence::Resort( void )
  1265. {
  1266. int c = m_EmphasisSamples.Count();
  1267. for ( int i = 0; i < c; i++ )
  1268. {
  1269. for ( int j = i + 1; j < c; j++ )
  1270. {
  1271. CEmphasisSample src = m_EmphasisSamples[ i ];
  1272. CEmphasisSample dest = m_EmphasisSamples[ j ];
  1273. if ( src.time > dest.time )
  1274. {
  1275. m_EmphasisSamples[ i ] = dest;
  1276. m_EmphasisSamples[ j ] = src;
  1277. }
  1278. }
  1279. }
  1280. }
  1281. //-----------------------------------------------------------------------------
  1282. // Purpose:
  1283. // Input : number -
  1284. // Output : CEmphasisSample
  1285. //-----------------------------------------------------------------------------
  1286. CEmphasisSample *CSentence::GetBoundedSample( int number, float endtime )
  1287. {
  1288. // Search for two samples which span time f
  1289. static CEmphasisSample nullstart;
  1290. nullstart.time = 0.0f;
  1291. nullstart.value = 0.5f;
  1292. static CEmphasisSample nullend;
  1293. nullend.time = endtime;
  1294. nullend.value = 0.5f;
  1295. if ( number < 0 )
  1296. {
  1297. return &nullstart;
  1298. }
  1299. else if ( number >= GetNumSamples() )
  1300. {
  1301. return &nullend;
  1302. }
  1303. return GetSample( number );
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. // Purpose:
  1307. // Input : time -
  1308. // type -
  1309. // Output : float
  1310. //-----------------------------------------------------------------------------
  1311. float CSentence::GetIntensity( float time, float endtime )
  1312. {
  1313. float zeroValue = 0.5f;
  1314. int c = GetNumSamples();
  1315. if ( c <= 0 )
  1316. {
  1317. return zeroValue;
  1318. }
  1319. int i;
  1320. for ( i = -1 ; i < c; i++ )
  1321. {
  1322. CEmphasisSample *s = GetBoundedSample( i, endtime );
  1323. CEmphasisSample *n = GetBoundedSample( i + 1, endtime );
  1324. if ( !s || !n )
  1325. continue;
  1326. if ( time >= s->time && time <= n->time )
  1327. {
  1328. break;
  1329. }
  1330. }
  1331. int prev = i - 1;
  1332. int start = i;
  1333. int end = i + 1;
  1334. int next = i + 2;
  1335. prev = MAX( -1, prev );
  1336. start = MAX( -1, start );
  1337. end = MIN( end, GetNumSamples() );
  1338. next = MIN( next, GetNumSamples() );
  1339. CEmphasisSample *esPre = GetBoundedSample( prev, endtime );
  1340. CEmphasisSample *esStart = GetBoundedSample( start, endtime );
  1341. CEmphasisSample *esEnd = GetBoundedSample( end, endtime );
  1342. CEmphasisSample *esNext = GetBoundedSample( next, endtime );
  1343. float dt = esEnd->time - esStart->time;
  1344. dt = clamp( dt, 0.01f, 1.0f );
  1345. Vector vPre( esPre->time, esPre->value, 0 );
  1346. Vector vStart( esStart->time, esStart->value, 0 );
  1347. Vector vEnd( esEnd->time, esEnd->value, 0 );
  1348. Vector vNext( esNext->time, esNext->value, 0 );
  1349. float f2 = ( time - esStart->time ) / ( dt );
  1350. f2 = clamp( f2, 0.0f, 1.0f );
  1351. Vector vOut;
  1352. Catmull_Rom_Spline(
  1353. vPre,
  1354. vStart,
  1355. vEnd,
  1356. vNext,
  1357. f2,
  1358. vOut );
  1359. float retval = clamp( vOut.y, 0.0f, 1.0f );
  1360. return retval;
  1361. }
  1362. int CSentence::GetNumSamples( void )
  1363. {
  1364. return m_EmphasisSamples.Count();
  1365. }
  1366. CEmphasisSample *CSentence::GetSample( int index )
  1367. {
  1368. if ( index < 0 || index >= GetNumSamples() )
  1369. return NULL;
  1370. return &m_EmphasisSamples[ index ];
  1371. }
  1372. void CSentence::GetEstimatedTimes( float& start, float &end )
  1373. {
  1374. #if PHONEME_EDITOR
  1375. float beststart = 100000.0f;
  1376. float bestend = -100000.0f;
  1377. int c = m_Words.Count();
  1378. if ( !c )
  1379. {
  1380. start = end = 0.0f;
  1381. return;
  1382. }
  1383. for ( int i = 0; i< c; i++ )
  1384. {
  1385. CWordTag *w = m_Words[ i ];
  1386. Assert( w );
  1387. if ( w->m_flStartTime < beststart )
  1388. {
  1389. beststart = w->m_flStartTime;
  1390. }
  1391. if ( w->m_flEndTime > bestend )
  1392. {
  1393. bestend = w->m_flEndTime;
  1394. }
  1395. }
  1396. if ( beststart == 100000.0f )
  1397. {
  1398. Assert( 0 );
  1399. beststart = 0.0f;
  1400. }
  1401. if ( bestend == -100000.0f )
  1402. {
  1403. Assert( 0 );
  1404. bestend = 1.0f;
  1405. }
  1406. start = beststart;
  1407. end = bestend;
  1408. #endif
  1409. }
  1410. void CSentence::SetDataCheckSum( unsigned int chk )
  1411. {
  1412. #if PHONEME_EDITOR
  1413. m_bStoreCheckSum = true;
  1414. m_uCheckSum = chk;
  1415. #endif
  1416. }
  1417. unsigned int CSentence::ComputeDataCheckSum()
  1418. {
  1419. #if PHONEME_EDITOR
  1420. int i;
  1421. int c;
  1422. CRC32_t crc;
  1423. CRC32_Init( &crc );
  1424. // Checksum the text
  1425. CRC32_ProcessBuffer( &crc, GetText(), Q_strlen( GetText() ) );
  1426. // Checsum words and phonemes
  1427. c = m_Words.Count();
  1428. for ( i = 0; i < c; ++i )
  1429. {
  1430. CWordTag *word = m_Words[ i ];
  1431. unsigned int wordCheckSum = word->ComputeDataCheckSum();
  1432. CRC32_ProcessBuffer( &crc, &wordCheckSum, sizeof( unsigned int ) );
  1433. }
  1434. // Checksum emphasis data
  1435. c = m_EmphasisSamples.Count();
  1436. for ( i = 0; i < c; ++i )
  1437. {
  1438. CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].time, sizeof( float ) );
  1439. CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].value, sizeof( float ) );
  1440. }
  1441. CRC32_Final( &crc );
  1442. return ( unsigned int )crc;
  1443. #else
  1444. Assert( 0 );
  1445. return 0;
  1446. #endif
  1447. }
  1448. unsigned int CSentence::GetDataCheckSum() const
  1449. {
  1450. #if PHONEME_EDITOR
  1451. Assert( m_bStoreCheckSum );
  1452. Assert( m_uCheckSum != 0 );
  1453. return m_uCheckSum;
  1454. #else
  1455. Assert( 0 );
  1456. return 0;
  1457. #endif
  1458. }
  1459. #define STARTEND_TIMEGAP 0.1
  1460. int CSentence::CountWords( char const *str )
  1461. {
  1462. if ( !str || !str[ 0 ] )
  1463. return 0;
  1464. int c = 1;
  1465. unsigned char *p = (unsigned char *)str;
  1466. while ( *p )
  1467. {
  1468. if ( *p <= 32 )
  1469. {
  1470. c++;
  1471. while ( *p && *p <= 32 )
  1472. {
  1473. p++;
  1474. }
  1475. }
  1476. if ( !(*p) )
  1477. break;
  1478. p++;
  1479. }
  1480. return c;
  1481. }
  1482. //-----------------------------------------------------------------------------
  1483. // Purpose: Static method
  1484. // Input : in -
  1485. // Output : Returns true on success, false on failure.
  1486. //-----------------------------------------------------------------------------
  1487. bool CSentence::ShouldSplitWord( char in )
  1488. {
  1489. if ( in <= 32 )
  1490. return true;
  1491. if ( V_ispunct( in ) )
  1492. {
  1493. // don't split on apostrophe
  1494. if ( in == '\'' )
  1495. return false;
  1496. return true;
  1497. }
  1498. return false;
  1499. }
  1500. void CSentence::CreateEventWordDistribution( char const *pszText, float flSentenceDuration )
  1501. {
  1502. Assert( pszText );
  1503. if ( !pszText )
  1504. return;
  1505. int wordCount = CountWords( pszText );
  1506. if ( wordCount <= 0 )
  1507. return;
  1508. float wordLength = ( flSentenceDuration - 2 * STARTEND_TIMEGAP) / (float)wordCount;
  1509. float wordStart = STARTEND_TIMEGAP;
  1510. Reset();
  1511. char word[ 256 ];
  1512. unsigned char const *in = (unsigned char *)pszText;
  1513. char *out = word;
  1514. while ( *in )
  1515. {
  1516. if ( !ShouldSplitWord( *in ) )
  1517. {
  1518. *out++ = *in++;
  1519. }
  1520. else
  1521. {
  1522. *out = 0;
  1523. // Skip over splitters
  1524. while ( *in && ( ShouldSplitWord( *in ) ) )
  1525. {
  1526. in++;
  1527. }
  1528. if ( strlen( word ) > 0 )
  1529. {
  1530. CWordTag *w = new CWordTag();
  1531. Assert( w );
  1532. w->SetWord( word );
  1533. w->m_flStartTime = wordStart;
  1534. w->m_flEndTime = wordStart + wordLength;
  1535. AddWordTag( w );
  1536. wordStart += wordLength;
  1537. }
  1538. out = word;
  1539. }
  1540. }
  1541. *out = 0;
  1542. if ( strlen( word ) > 0 )
  1543. {
  1544. CWordTag *w = new CWordTag();
  1545. Assert( w );
  1546. w->SetWord( word );
  1547. w->m_flStartTime = wordStart;
  1548. w->m_flEndTime = wordStart + wordLength;
  1549. AddWordTag( w );
  1550. wordStart += wordLength;
  1551. }
  1552. }
  1553. #endif // !_STATIC_LINKED || _SHARED_LIB