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.

1766 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #if !defined(_STATIC_LINKED) || defined(_SHARED_LIB)
  9. #include <assert.h>
  10. #include "commonmacros.h"
  11. #include "basetypes.h"
  12. #include "sentence.h"
  13. #include "utlbuffer.h"
  14. #include <stdlib.h>
  15. #include "mathlib/vector.h"
  16. #include "mathlib/mathlib.h"
  17. #include <ctype.h>
  18. #include "checksum_crc.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.Size(); 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.Size() > 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.Size(); 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, "koreana", 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 );
  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 );
  405. if ( !stricmp( token, "}" ) )
  406. break;
  407. if ( stricmp( token, "WORD" ) )
  408. break;
  409. buf.GetString( token );
  410. Q_strncpy( word, token, sizeof( word ) );
  411. buf.GetString( token );
  412. start = atof( token );
  413. buf.GetString( 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 );
  421. if ( stricmp( token, "{" ) )
  422. break;
  423. while ( 1 )
  424. {
  425. buf.GetString( token );
  426. if ( !stricmp( token, "}" ) )
  427. break;
  428. // Parse phoneme
  429. int code;
  430. char phonemename[ 256 ];
  431. float volume;
  432. code = atoi( token );
  433. buf.GetString( token );
  434. Q_strncpy( phonemename, token, sizeof( phonemename ) );
  435. buf.GetString( token );
  436. start = atof( token );
  437. buf.GetString( token );
  438. end = atof( token );
  439. buf.GetString( token );
  440. volume = atof( token );
  441. CPhonemeTag *pt = new CPhonemeTag();
  442. assert( pt );
  443. pt->SetPhonemeCode( code );
  444. pt->SetTag( phonemename );
  445. pt->SetStartTime( start );
  446. pt->SetEndTime( end );
  447. AddPhonemeTag( wt, pt );
  448. }
  449. }
  450. }
  451. void CSentence::ParseEmphasis( CUtlBuffer& buf )
  452. {
  453. char token[ 4096 ];
  454. while ( 1 )
  455. {
  456. buf.GetString( token );
  457. if ( !stricmp( token, "}" ) )
  458. break;
  459. char t[ 256 ];
  460. Q_strncpy( t, token, sizeof( t ) );
  461. buf.GetString( token );
  462. char value[ 256 ];
  463. Q_strncpy( value, token, sizeof( value ) );
  464. CEmphasisSample sample;
  465. sample.SetSelected( false );
  466. sample.time = atof( t );
  467. sample.value = atof( value );
  468. m_EmphasisSamples.AddToTail( sample );
  469. }
  470. }
  471. // This is obsolete, so it doesn't do anything with the data which is parsed.
  472. void CSentence::ParseCloseCaption( CUtlBuffer& buf )
  473. {
  474. char token[ 4096 ];
  475. while ( 1 )
  476. {
  477. // Format is
  478. // language_name
  479. // {
  480. // PHRASE char streamlength "streambytes" starttime endtime
  481. // PHRASE unicode streamlength "streambytes" starttime endtime
  482. // }
  483. buf.GetString( token );
  484. if ( !stricmp( token, "}" ) )
  485. break;
  486. buf.GetString( token );
  487. if ( stricmp( token, "{" ) )
  488. break;
  489. buf.GetString( token );
  490. while ( 1 )
  491. {
  492. if ( !stricmp( token, "}" ) )
  493. break;
  494. if ( stricmp( token, "PHRASE" ) )
  495. break;
  496. char cc_type[32];
  497. char cc_stream[ 4096 ];
  498. int cc_length;
  499. memset( cc_stream, 0, sizeof( cc_stream ) );
  500. buf.GetString( token );
  501. Q_strncpy( cc_type, token, sizeof( cc_type ) );
  502. bool unicode = false;
  503. if ( !stricmp( cc_type, "unicode" ) )
  504. {
  505. unicode = true;
  506. }
  507. else if ( stricmp( cc_type, "char" ) )
  508. {
  509. Assert( 0 );
  510. }
  511. buf.GetString( token );
  512. cc_length = atoi( token );
  513. Assert( cc_length >= 0 && cc_length < sizeof( cc_stream ) );
  514. // Skip space
  515. buf.GetChar();
  516. buf.Get( cc_stream, cc_length );
  517. cc_stream[ cc_length ] = 0;
  518. // Skip space
  519. buf.GetChar();
  520. buf.GetString( token );
  521. buf.GetString( token );
  522. buf.GetString( token );
  523. }
  524. }
  525. }
  526. void CSentence::ParseOptions( CUtlBuffer& buf )
  527. {
  528. char token[ 4096 ];
  529. while ( 1 )
  530. {
  531. buf.GetString( token );
  532. if ( !stricmp( token, "}" ) )
  533. break;
  534. if ( Q_strlen( token ) == 0 )
  535. break;
  536. char key[ 256 ];
  537. Q_strncpy( key, token, sizeof( key ) );
  538. char value[ 256 ];
  539. buf.GetString( token );
  540. Q_strncpy( value, token, sizeof( value ) );
  541. if ( !strcmpi( key, "voice_duck" ) )
  542. {
  543. SetVoiceDuck( atoi(value) ? true : false );
  544. }
  545. else if ( !strcmpi( key, "checksum" ) )
  546. {
  547. SetDataCheckSum( (unsigned int)atoi( value ) );
  548. }
  549. }
  550. }
  551. //-----------------------------------------------------------------------------
  552. // Purpose: VERSION 1.0 parser, need to implement new ones if
  553. // file format changes!!!
  554. // Input : buf -
  555. //-----------------------------------------------------------------------------
  556. void CSentence::ParseDataVersionOnePointZero( CUtlBuffer& buf )
  557. {
  558. char token[ 4096 ];
  559. while ( 1 )
  560. {
  561. buf.GetString( token );
  562. if ( strlen( token ) <= 0 )
  563. break;
  564. // end of block, return
  565. if ( !V_strcmp( token, "}" ) )
  566. break;
  567. char section[ 256 ];
  568. Q_strncpy( section, token, sizeof( section ) );
  569. buf.GetString( token );
  570. if ( stricmp( token, "{" ) )
  571. break;
  572. if ( !stricmp( section, "PLAINTEXT" ) )
  573. {
  574. ParsePlaintext( buf );
  575. }
  576. else if ( !stricmp( section, "WORDS" ) )
  577. {
  578. ParseWords( buf );
  579. }
  580. else if ( !stricmp( section, "EMPHASIS" ) )
  581. {
  582. ParseEmphasis( buf );
  583. }
  584. else if ( !stricmp( section, "CLOSECAPTION" ) )
  585. {
  586. // NOTE: CLOSECAPTION IS NO LONGER VALID
  587. // This just skips the section of data.
  588. ParseCloseCaption( buf );
  589. }
  590. else if ( !stricmp( section, "OPTIONS" ) )
  591. {
  592. ParseOptions( buf );
  593. }
  594. }
  595. }
  596. // This is a compressed save of just the data needed to drive phonemes in the engine (no word / sentence text, etc )
  597. //-----------------------------------------------------------------------------
  598. // Purpose:
  599. // Input : buf -
  600. //-----------------------------------------------------------------------------
  601. void CSentence::CacheSaveToBuffer( CUtlBuffer& buf, int version )
  602. {
  603. Assert( !buf.IsText() );
  604. Assert( m_bIsCached );
  605. int i;
  606. unsigned short pcount = GetRuntimePhonemeCount();
  607. // header
  608. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  609. {
  610. buf.PutChar( version );
  611. buf.PutChar( 0 );
  612. buf.PutChar( 0 );
  613. buf.PutChar( 0 );
  614. buf.PutInt( pcount );
  615. }
  616. else
  617. {
  618. buf.PutChar( version );
  619. buf.PutShort( pcount );
  620. }
  621. // phoneme
  622. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  623. {
  624. for ( i = 0; i < pcount; ++i )
  625. {
  626. const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i );
  627. Assert( phoneme );
  628. buf.PutInt( phoneme->GetPhonemeCode() );
  629. buf.PutFloat( phoneme->GetStartTime() );
  630. buf.PutFloat( phoneme->GetEndTime() );
  631. }
  632. }
  633. else
  634. {
  635. for ( i = 0; i < pcount; ++i )
  636. {
  637. const CBasePhonemeTag *phoneme = GetRuntimePhoneme( i );
  638. Assert( phoneme );
  639. buf.PutShort( phoneme->GetPhonemeCode() );
  640. buf.PutFloat( phoneme->GetStartTime() );
  641. buf.PutFloat( phoneme->GetEndTime() );
  642. }
  643. }
  644. // emphasis samples and voice duck
  645. int c = m_EmphasisSamples.Count();
  646. Assert( c <= 32767 );
  647. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  648. {
  649. buf.PutInt( c );
  650. for ( i = 0; i < c; i++ )
  651. {
  652. CEmphasisSample *sample = &m_EmphasisSamples[i];
  653. Assert( sample );
  654. buf.PutFloat( sample->time );
  655. buf.PutFloat( sample->value );
  656. }
  657. buf.PutInt( GetVoiceDuck() ? 1 : 0 );
  658. }
  659. else
  660. {
  661. buf.PutShort( c );
  662. for ( i = 0; i < c; i++ )
  663. {
  664. CEmphasisSample *sample = &m_EmphasisSamples[i];
  665. Assert( sample );
  666. buf.PutFloat( sample->time );
  667. short scaledValue = clamp( (short)( sample->value * 32767 ), (short)0, (short)32767 );
  668. buf.PutShort( scaledValue );
  669. }
  670. buf.PutChar( GetVoiceDuck() ? 1 : 0 );
  671. }
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Purpose:
  675. // Input : buf -
  676. //-----------------------------------------------------------------------------
  677. void CSentence::CacheRestoreFromBuffer( CUtlBuffer& buf )
  678. {
  679. Assert( !buf.IsText() );
  680. Reset();
  681. m_bIsCached = true;
  682. // determine format
  683. int version = buf.GetChar();
  684. if ( version != CACHED_SENTENCE_VERSION && version != CACHED_SENTENCE_VERSION_ALIGNED )
  685. {
  686. // Uh oh, version changed...
  687. m_bIsValid = false;
  688. return;
  689. }
  690. unsigned short pcount;
  691. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  692. {
  693. buf.GetChar();
  694. buf.GetChar();
  695. buf.GetChar();
  696. pcount = buf.GetInt();
  697. }
  698. else
  699. {
  700. pcount = (unsigned short)buf.GetShort();
  701. }
  702. // phonemes
  703. CPhonemeTag pt;
  704. int i;
  705. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  706. {
  707. for ( i = 0; i < pcount; ++i )
  708. {
  709. int code = buf.GetInt();
  710. float st = buf.GetFloat();
  711. float et = buf.GetFloat();
  712. pt.SetPhonemeCode( code );
  713. pt.SetStartTime( st );
  714. pt.SetEndTime( et );
  715. AddRuntimePhoneme( &pt );
  716. }
  717. }
  718. else
  719. {
  720. for ( i = 0; i < pcount; ++i )
  721. {
  722. unsigned short code = buf.GetShort();
  723. float st = buf.GetFloat();
  724. float et = buf.GetFloat();
  725. pt.SetPhonemeCode( code );
  726. pt.SetStartTime( st );
  727. pt.SetEndTime( et );
  728. AddRuntimePhoneme( &pt );
  729. }
  730. }
  731. // emphasis samples and voice duck
  732. int c;
  733. if ( version == CACHED_SENTENCE_VERSION_ALIGNED )
  734. {
  735. c = buf.GetInt();
  736. for ( i = 0; i < c; i++ )
  737. {
  738. CEmphasisSample sample;
  739. sample.SetSelected( false );
  740. sample.time = buf.GetFloat();
  741. sample.value = buf.GetFloat();
  742. m_EmphasisSamples.AddToTail( sample );
  743. }
  744. SetVoiceDuck( buf.GetInt() == 0 ? false : true );
  745. }
  746. else
  747. {
  748. c = buf.GetShort();
  749. for ( i = 0; i < c; i++ )
  750. {
  751. CEmphasisSample sample;
  752. sample.SetSelected( false );
  753. sample.time = buf.GetFloat();
  754. sample.value = (float)buf.GetShort() / 32767.0f;
  755. m_EmphasisSamples.AddToTail( sample );
  756. }
  757. SetVoiceDuck( buf.GetChar() == 0 ? false : true );
  758. }
  759. m_bIsValid = true;
  760. }
  761. int CSentence::GetRuntimePhonemeCount() const
  762. {
  763. return m_RunTimePhonemes.Count();
  764. }
  765. const CBasePhonemeTag *CSentence::GetRuntimePhoneme( int i ) const
  766. {
  767. Assert( m_bIsCached );
  768. return m_RunTimePhonemes[ i ];
  769. }
  770. void CSentence::ClearRuntimePhonemes()
  771. {
  772. while ( m_RunTimePhonemes.Count() > 0 )
  773. {
  774. CBasePhonemeTag *tag = m_RunTimePhonemes[ 0 ];
  775. delete tag;
  776. m_RunTimePhonemes.Remove( 0 );
  777. }
  778. }
  779. void CSentence::AddRuntimePhoneme( const CPhonemeTag *src )
  780. {
  781. Assert( m_bIsCached );
  782. CBasePhonemeTag *tag = new CBasePhonemeTag();
  783. *tag = *src;
  784. m_RunTimePhonemes.AddToTail( tag );
  785. }
  786. void CSentence::MakeRuntimeOnly()
  787. {
  788. m_bIsCached = true;
  789. #if PHONEME_EDITOR
  790. delete m_szText;
  791. m_szText = NULL;
  792. int c = m_Words.Count();
  793. for ( int i = 0; i < c; ++i )
  794. {
  795. CWordTag *word = m_Words[ i ];
  796. Assert( word );
  797. int pcount = word->m_Phonemes.Count();
  798. for ( int j = 0; j < pcount; ++j )
  799. {
  800. CPhonemeTag *phoneme = word->m_Phonemes[ j ];
  801. assert( phoneme );
  802. AddRuntimePhoneme( phoneme );
  803. }
  804. }
  805. // Remove all existing words
  806. while ( m_Words.Count() > 0 )
  807. {
  808. CWordTag *word = m_Words[ 0 ];
  809. delete word;
  810. m_Words.Remove( 0 );
  811. }
  812. #endif
  813. m_bIsValid = true;
  814. }
  815. void CSentence::SaveToBuffer( CUtlBuffer& buf )
  816. {
  817. #if PHONEME_EDITOR
  818. Assert( !m_bIsCached );
  819. int i, j;
  820. buf.Printf( "VERSION 1.0\n" );
  821. buf.Printf( "PLAINTEXT\n" );
  822. buf.Printf( "{\n" );
  823. buf.Printf( "%s\n", GetText() );
  824. buf.Printf( "}\n" );
  825. buf.Printf( "WORDS\n" );
  826. buf.Printf( "{\n" );
  827. for ( i = 0; i < m_Words.Size(); i++ )
  828. {
  829. CWordTag *word = m_Words[ i ];
  830. Assert( word );
  831. buf.Printf( "WORD %s %.3f %.3f\n",
  832. word->GetWord(),
  833. word->m_flStartTime,
  834. word->m_flEndTime );
  835. buf.Printf( "{\n" );
  836. for ( j = 0; j < word->m_Phonemes.Size(); j++ )
  837. {
  838. CPhonemeTag *phoneme = word->m_Phonemes[ j ];
  839. Assert( phoneme );
  840. buf.Printf( "%i %s %.3f %.3f 1\n",
  841. phoneme->GetPhonemeCode(),
  842. phoneme->GetTag(),
  843. phoneme->GetStartTime(),
  844. phoneme->GetEndTime() );
  845. }
  846. buf.Printf( "}\n" );
  847. }
  848. buf.Printf( "}\n" );
  849. buf.Printf( "EMPHASIS\n" );
  850. buf.Printf( "{\n" );
  851. int c = m_EmphasisSamples.Count();
  852. for ( i = 0; i < c; i++ )
  853. {
  854. CEmphasisSample *sample = &m_EmphasisSamples[ i ];
  855. Assert( sample );
  856. buf.Printf( "%f %f\n", sample->time, sample->value );
  857. }
  858. buf.Printf( "}\n" );
  859. buf.Printf( "OPTIONS\n" );
  860. buf.Printf( "{\n" );
  861. buf.Printf( "voice_duck %d\n", GetVoiceDuck() ? 1 : 0 );
  862. if ( m_bStoreCheckSum )
  863. {
  864. buf.Printf( "checksum %d\n", m_uCheckSum );
  865. }
  866. buf.Printf( "}\n" );
  867. #else
  868. Assert( 0 );
  869. #endif
  870. }
  871. //-----------------------------------------------------------------------------
  872. // Purpose:
  873. // Input : *data -
  874. // size -
  875. //-----------------------------------------------------------------------------
  876. void CSentence::InitFromDataChunk( void *data, int size )
  877. {
  878. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  879. buf.EnsureCapacity( size );
  880. buf.Put( data, size );
  881. buf.SeekPut( CUtlBuffer::SEEK_HEAD, size );
  882. InitFromBuffer( buf );
  883. }
  884. //-----------------------------------------------------------------------------
  885. // Purpose:
  886. // Input : buf -
  887. //-----------------------------------------------------------------------------
  888. void CSentence::InitFromBuffer( CUtlBuffer& buf )
  889. {
  890. Assert( buf.IsText() );
  891. Reset();
  892. char token[ 4096 ];
  893. buf.GetString( token );
  894. if ( stricmp( token, "VERSION" ) )
  895. return;
  896. buf.GetString( token );
  897. if ( atof( token ) == 1.0f )
  898. {
  899. ParseDataVersionOnePointZero( buf );
  900. m_bIsValid = true;
  901. }
  902. else
  903. {
  904. assert( 0 );
  905. return;
  906. }
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose:
  910. // Output : int
  911. //-----------------------------------------------------------------------------
  912. int CSentence::GetWordBase( void )
  913. {
  914. #if PHONEME_EDITOR
  915. return m_nResetWordBase;
  916. #else
  917. Assert( 0 );
  918. return 0;
  919. #endif
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Purpose:
  923. //-----------------------------------------------------------------------------
  924. void CSentence::ResetToBase( void )
  925. {
  926. #if PHONEME_EDITOR
  927. // Delete everything after m_nResetWordBase
  928. while ( m_Words.Size() > m_nResetWordBase )
  929. {
  930. delete m_Words[ m_Words.Size() - 1 ];
  931. m_Words.Remove( m_Words.Size() - 1 );
  932. }
  933. #endif
  934. ClearRuntimePhonemes();
  935. }
  936. //-----------------------------------------------------------------------------
  937. // Purpose:
  938. //-----------------------------------------------------------------------------
  939. void CSentence::MarkNewPhraseBase( void )
  940. {
  941. #if PHONEME_EDITOR
  942. m_nResetWordBase = max( m_Words.Size(), 0 );
  943. #endif
  944. }
  945. //-----------------------------------------------------------------------------
  946. // Purpose:
  947. //-----------------------------------------------------------------------------
  948. void CSentence::Reset( void )
  949. {
  950. #if PHONEME_EDITOR
  951. m_nResetWordBase = 0;
  952. while ( m_Words.Size() > 0 )
  953. {
  954. delete m_Words[ 0 ];
  955. m_Words.Remove( 0 );
  956. }
  957. #endif
  958. m_EmphasisSamples.RemoveAll();
  959. ClearRuntimePhonemes();
  960. }
  961. //-----------------------------------------------------------------------------
  962. // Purpose:
  963. // Input : *tag -
  964. //-----------------------------------------------------------------------------
  965. void CSentence::AddPhonemeTag( CWordTag *word, CPhonemeTag *tag )
  966. {
  967. word->m_Phonemes.AddToTail( tag );
  968. }
  969. //-----------------------------------------------------------------------------
  970. // Purpose:
  971. // Input : *tag -
  972. //-----------------------------------------------------------------------------
  973. void CSentence::AddWordTag( CWordTag *tag )
  974. {
  975. #if PHONEME_EDITOR
  976. m_Words.AddToTail( tag );
  977. #endif
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Purpose:
  981. // Output : int
  982. //-----------------------------------------------------------------------------
  983. int CSentence::CountPhonemes( void )
  984. {
  985. int c = 0;
  986. #if PHONEME_EDITOR
  987. for( int i = 0; i < m_Words.Size(); i++ )
  988. {
  989. CWordTag *word = m_Words[ i ];
  990. c += word->m_Phonemes.Size();
  991. }
  992. #endif
  993. return c;
  994. }
  995. //-----------------------------------------------------------------------------
  996. // Purpose: // For legacy loading, try to find a word that contains the time
  997. // Input : time -
  998. // Output : CWordTag
  999. //-----------------------------------------------------------------------------
  1000. CWordTag *CSentence::EstimateBestWord( float time )
  1001. {
  1002. #if PHONEME_EDITOR
  1003. CWordTag *bestWord = NULL;
  1004. for( int i = 0; i < m_Words.Size(); i++ )
  1005. {
  1006. CWordTag *word = m_Words[ i ];
  1007. if ( !word )
  1008. continue;
  1009. if ( word->m_flStartTime <= time && word->m_flEndTime >= time )
  1010. return word;
  1011. if ( time < word->m_flStartTime )
  1012. {
  1013. bestWord = word;
  1014. }
  1015. if ( time > word->m_flEndTime && bestWord )
  1016. return bestWord;
  1017. }
  1018. // return best word if we found one
  1019. if ( bestWord )
  1020. {
  1021. return bestWord;
  1022. }
  1023. // Return last word
  1024. if ( m_Words.Size() >= 1 )
  1025. {
  1026. return m_Words[ m_Words.Size() - 1 ];
  1027. }
  1028. #endif
  1029. // Oh well
  1030. return NULL;
  1031. }
  1032. //-----------------------------------------------------------------------------
  1033. // Purpose:
  1034. // Input : *phoneme -
  1035. // Output : CWordTag
  1036. //-----------------------------------------------------------------------------
  1037. CWordTag *CSentence::GetWordForPhoneme( CPhonemeTag *phoneme )
  1038. {
  1039. #if PHONEME_EDITOR
  1040. for( int i = 0; i < m_Words.Size(); i++ )
  1041. {
  1042. CWordTag *word = m_Words[ i ];
  1043. if ( !word )
  1044. continue;
  1045. for ( int j = 0 ; j < word->m_Phonemes.Size() ; j++ )
  1046. {
  1047. CPhonemeTag *p = word->m_Phonemes[ j ];
  1048. if ( p == phoneme )
  1049. {
  1050. return word;
  1051. }
  1052. }
  1053. }
  1054. #endif
  1055. return NULL;
  1056. }
  1057. //-----------------------------------------------------------------------------
  1058. // Purpose: Assignment operator
  1059. // Input : src -
  1060. // Output : CSentence&
  1061. //-----------------------------------------------------------------------------
  1062. CSentence& CSentence::operator=( const CSentence& src )
  1063. {
  1064. int i;
  1065. // Clear current stuff
  1066. Reset();
  1067. int c;
  1068. #if PHONEME_EDITOR
  1069. // Copy everything
  1070. for ( i = 0 ; i < src.m_Words.Size(); i++ )
  1071. {
  1072. CWordTag *word = src.m_Words[ i ];
  1073. CWordTag *newWord = new CWordTag( *word );
  1074. AddWordTag( newWord );
  1075. }
  1076. SetText( src.GetText() );
  1077. m_nResetWordBase = src.m_nResetWordBase;
  1078. c = src.m_EmphasisSamples.Size();
  1079. for ( i = 0; i < c; i++ )
  1080. {
  1081. CEmphasisSample s = src.m_EmphasisSamples[ i ];
  1082. m_EmphasisSamples.AddToTail( s );
  1083. }
  1084. #endif
  1085. m_bIsCached = src.m_bIsCached;
  1086. c = src.GetRuntimePhonemeCount();
  1087. for ( i = 0; i < c; i++ )
  1088. {
  1089. Assert( m_bIsCached );
  1090. const CBasePhonemeTag *tag = src.GetRuntimePhoneme( i );
  1091. CPhonemeTag full;
  1092. ((CBasePhonemeTag &)(full)) = *tag;
  1093. AddRuntimePhoneme( &full );
  1094. }
  1095. m_bShouldVoiceDuck = src.m_bShouldVoiceDuck;
  1096. #if PHONEME_EDITOR
  1097. m_bStoreCheckSum = src.m_bStoreCheckSum;
  1098. m_uCheckSum = src.m_uCheckSum;
  1099. #endif
  1100. m_bIsValid = src.m_bIsValid;
  1101. return (*this);
  1102. }
  1103. void CSentence::Append( float starttime, const CSentence& src )
  1104. {
  1105. #if PHONEME_EDITOR
  1106. int i;
  1107. // Combine
  1108. for ( i = 0 ; i < src.m_Words.Size(); i++ )
  1109. {
  1110. CWordTag *word = src.m_Words[ i ];
  1111. CWordTag *newWord = new CWordTag( *word );
  1112. newWord->m_flStartTime += starttime;
  1113. newWord->m_flEndTime += starttime;
  1114. // Offset times
  1115. int c = newWord->m_Phonemes.Count();
  1116. for ( int j = 0; j < c; ++j )
  1117. {
  1118. CPhonemeTag *tag = newWord->m_Phonemes[ j ];
  1119. tag->AddStartTime( starttime );
  1120. tag->AddEndTime( starttime );
  1121. }
  1122. AddWordTag( newWord );
  1123. }
  1124. if ( src.GetText()[ 0 ] )
  1125. {
  1126. char fulltext[ 4096 ];
  1127. if ( GetText()[ 0 ] )
  1128. {
  1129. Q_snprintf( fulltext, sizeof( fulltext ), "%s %s", GetText(), src.GetText() );
  1130. }
  1131. else
  1132. {
  1133. Q_strncpy( fulltext, src.GetText(), sizeof( fulltext ) );
  1134. }
  1135. SetText( fulltext );
  1136. }
  1137. int c = src.m_EmphasisSamples.Size();
  1138. for ( i = 0; i < c; i++ )
  1139. {
  1140. CEmphasisSample s = src.m_EmphasisSamples[ i ];
  1141. s.time += starttime;
  1142. m_EmphasisSamples.AddToTail( s );
  1143. }
  1144. // Or in voice duck settings
  1145. m_bShouldVoiceDuck |= src.m_bShouldVoiceDuck;
  1146. #else
  1147. Assert( 0 );
  1148. #endif
  1149. }
  1150. //-----------------------------------------------------------------------------
  1151. // Purpose:
  1152. // Input : *text -
  1153. //-----------------------------------------------------------------------------
  1154. void CSentence::SetText( const char *text )
  1155. {
  1156. #if PHONEME_EDITOR
  1157. delete[] m_szText;
  1158. m_szText = NULL;
  1159. if ( !text || !text[ 0 ] )
  1160. {
  1161. return;
  1162. }
  1163. int len = Q_strlen( text ) + 1;
  1164. m_szText = new char[ len ];
  1165. Assert( m_szText );
  1166. Q_strncpy( m_szText, text, len );
  1167. #endif
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose:
  1171. // Output : const char
  1172. //-----------------------------------------------------------------------------
  1173. const char *CSentence::GetText( void ) const
  1174. {
  1175. #if PHONEME_EDITOR
  1176. return m_szText ? m_szText : "";
  1177. #else
  1178. return "";
  1179. #endif
  1180. }
  1181. //-----------------------------------------------------------------------------
  1182. // Purpose:
  1183. //-----------------------------------------------------------------------------
  1184. void CSentence::SetTextFromWords( void )
  1185. {
  1186. #if PHONEME_EDITOR
  1187. char fulltext[ 1024 ];
  1188. fulltext[ 0 ] = 0;
  1189. for ( int i = 0 ; i < m_Words.Size(); i++ )
  1190. {
  1191. CWordTag *word = m_Words[ i ];
  1192. Q_strncat( fulltext, word->GetWord(), sizeof( fulltext ), COPY_ALL_CHARACTERS );
  1193. if ( i != m_Words.Size() )
  1194. {
  1195. Q_strncat( fulltext, " ", sizeof( fulltext ), COPY_ALL_CHARACTERS );
  1196. }
  1197. }
  1198. SetText( fulltext );
  1199. #endif
  1200. }
  1201. //-----------------------------------------------------------------------------
  1202. // Purpose:
  1203. //-----------------------------------------------------------------------------
  1204. void CSentence::Resort( void )
  1205. {
  1206. int c = m_EmphasisSamples.Size();
  1207. for ( int i = 0; i < c; i++ )
  1208. {
  1209. for ( int j = i + 1; j < c; j++ )
  1210. {
  1211. CEmphasisSample src = m_EmphasisSamples[ i ];
  1212. CEmphasisSample dest = m_EmphasisSamples[ j ];
  1213. if ( src.time > dest.time )
  1214. {
  1215. m_EmphasisSamples[ i ] = dest;
  1216. m_EmphasisSamples[ j ] = src;
  1217. }
  1218. }
  1219. }
  1220. }
  1221. //-----------------------------------------------------------------------------
  1222. // Purpose:
  1223. // Input : number -
  1224. // Output : CEmphasisSample
  1225. //-----------------------------------------------------------------------------
  1226. CEmphasisSample *CSentence::GetBoundedSample( int number, float endtime )
  1227. {
  1228. // Search for two samples which span time f
  1229. static CEmphasisSample nullstart;
  1230. nullstart.time = 0.0f;
  1231. nullstart.value = 0.5f;
  1232. static CEmphasisSample nullend;
  1233. nullend.time = endtime;
  1234. nullend.value = 0.5f;
  1235. if ( number < 0 )
  1236. {
  1237. return &nullstart;
  1238. }
  1239. else if ( number >= GetNumSamples() )
  1240. {
  1241. return &nullend;
  1242. }
  1243. return GetSample( number );
  1244. }
  1245. //-----------------------------------------------------------------------------
  1246. // Purpose:
  1247. // Input : time -
  1248. // type -
  1249. // Output : float
  1250. //-----------------------------------------------------------------------------
  1251. float CSentence::GetIntensity( float time, float endtime )
  1252. {
  1253. float zeroValue = 0.5f;
  1254. int c = GetNumSamples();
  1255. if ( c <= 0 )
  1256. {
  1257. return zeroValue;
  1258. }
  1259. int i;
  1260. for ( i = -1 ; i < c; i++ )
  1261. {
  1262. CEmphasisSample *s = GetBoundedSample( i, endtime );
  1263. CEmphasisSample *n = GetBoundedSample( i + 1, endtime );
  1264. if ( !s || !n )
  1265. continue;
  1266. if ( time >= s->time && time <= n->time )
  1267. {
  1268. break;
  1269. }
  1270. }
  1271. int prev = i - 1;
  1272. int start = i;
  1273. int end = i + 1;
  1274. int next = i + 2;
  1275. prev = max( -1, prev );
  1276. start = max( -1, start );
  1277. end = min( end, GetNumSamples() );
  1278. next = min( next, GetNumSamples() );
  1279. CEmphasisSample *esPre = GetBoundedSample( prev, endtime );
  1280. CEmphasisSample *esStart = GetBoundedSample( start, endtime );
  1281. CEmphasisSample *esEnd = GetBoundedSample( end, endtime );
  1282. CEmphasisSample *esNext = GetBoundedSample( next, endtime );
  1283. float dt = esEnd->time - esStart->time;
  1284. dt = clamp( dt, 0.01f, 1.0f );
  1285. Vector vPre( esPre->time, esPre->value, 0 );
  1286. Vector vStart( esStart->time, esStart->value, 0 );
  1287. Vector vEnd( esEnd->time, esEnd->value, 0 );
  1288. Vector vNext( esNext->time, esNext->value, 0 );
  1289. float f2 = ( time - esStart->time ) / ( dt );
  1290. f2 = clamp( f2, 0.0f, 1.0f );
  1291. Vector vOut;
  1292. Catmull_Rom_Spline(
  1293. vPre,
  1294. vStart,
  1295. vEnd,
  1296. vNext,
  1297. f2,
  1298. vOut );
  1299. float retval = clamp( vOut.y, 0.0f, 1.0f );
  1300. return retval;
  1301. }
  1302. int CSentence::GetNumSamples( void )
  1303. {
  1304. return m_EmphasisSamples.Count();
  1305. }
  1306. CEmphasisSample *CSentence::GetSample( int index )
  1307. {
  1308. if ( index < 0 || index >= GetNumSamples() )
  1309. return NULL;
  1310. return &m_EmphasisSamples[ index ];
  1311. }
  1312. void CSentence::GetEstimatedTimes( float& start, float &end )
  1313. {
  1314. #if PHONEME_EDITOR
  1315. float beststart = 100000.0f;
  1316. float bestend = -100000.0f;
  1317. int c = m_Words.Count();
  1318. if ( !c )
  1319. {
  1320. start = end = 0.0f;
  1321. return;
  1322. }
  1323. for ( int i = 0; i< c; i++ )
  1324. {
  1325. CWordTag *w = m_Words[ i ];
  1326. Assert( w );
  1327. if ( w->m_flStartTime < beststart )
  1328. {
  1329. beststart = w->m_flStartTime;
  1330. }
  1331. if ( w->m_flEndTime > bestend )
  1332. {
  1333. bestend = w->m_flEndTime;
  1334. }
  1335. }
  1336. if ( beststart == 100000.0f )
  1337. {
  1338. Assert( 0 );
  1339. beststart = 0.0f;
  1340. }
  1341. if ( bestend == -100000.0f )
  1342. {
  1343. Assert( 0 );
  1344. bestend = 1.0f;
  1345. }
  1346. start = beststart;
  1347. end = bestend;
  1348. #endif
  1349. }
  1350. void CSentence::SetDataCheckSum( unsigned int chk )
  1351. {
  1352. #if PHONEME_EDITOR
  1353. m_bStoreCheckSum = true;
  1354. m_uCheckSum = chk;
  1355. #endif
  1356. }
  1357. unsigned int CSentence::ComputeDataCheckSum()
  1358. {
  1359. #if PHONEME_EDITOR
  1360. int i;
  1361. int c;
  1362. CRC32_t crc;
  1363. CRC32_Init( &crc );
  1364. // Checksum the text
  1365. CRC32_ProcessBuffer( &crc, GetText(), Q_strlen( GetText() ) );
  1366. // Checsum words and phonemes
  1367. c = m_Words.Count();
  1368. for ( i = 0; i < c; ++i )
  1369. {
  1370. CWordTag *word = m_Words[ i ];
  1371. unsigned int wordCheckSum = word->ComputeDataCheckSum();
  1372. CRC32_ProcessBuffer( &crc, &wordCheckSum, sizeof( unsigned int ) );
  1373. }
  1374. // Checksum emphasis data
  1375. c = m_EmphasisSamples.Count();
  1376. for ( i = 0; i < c; ++i )
  1377. {
  1378. CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].time, sizeof( float ) );
  1379. CRC32_ProcessBuffer( &crc, &m_EmphasisSamples[ i ].value, sizeof( float ) );
  1380. }
  1381. CRC32_Final( &crc );
  1382. return ( unsigned int )crc;
  1383. #else
  1384. Assert( 0 );
  1385. return 0;
  1386. #endif
  1387. }
  1388. unsigned int CSentence::GetDataCheckSum() const
  1389. {
  1390. #if PHONEME_EDITOR
  1391. Assert( m_bStoreCheckSum );
  1392. Assert( m_uCheckSum != 0 );
  1393. return m_uCheckSum;
  1394. #else
  1395. Assert( 0 );
  1396. return 0;
  1397. #endif
  1398. }
  1399. #define STARTEND_TIMEGAP 0.1
  1400. int CSentence::CountWords( char const *str )
  1401. {
  1402. if ( !str || !str[ 0 ] )
  1403. return 0;
  1404. int c = 1;
  1405. unsigned char *p = (unsigned char *)str;
  1406. while ( *p )
  1407. {
  1408. if ( *p <= 32 )
  1409. {
  1410. c++;
  1411. while ( *p && *p <= 32 )
  1412. {
  1413. p++;
  1414. }
  1415. }
  1416. if ( !(*p) )
  1417. break;
  1418. p++;
  1419. }
  1420. return c;
  1421. }
  1422. //-----------------------------------------------------------------------------
  1423. // Purpose: Static method
  1424. // Input : in -
  1425. // Output : Returns true on success, false on failure.
  1426. //-----------------------------------------------------------------------------
  1427. bool CSentence::ShouldSplitWord( char in )
  1428. {
  1429. if ( in <= 32 )
  1430. return true;
  1431. if ( (unsigned char)in > SCHAR_MAX )
  1432. return true;
  1433. if ( ispunct( in ) )
  1434. {
  1435. // don't split on apostrophe
  1436. if ( in == '\'' )
  1437. return false;
  1438. return true;
  1439. }
  1440. return false;
  1441. }
  1442. void CSentence::CreateEventWordDistribution( char const *pszText, float flSentenceDuration )
  1443. {
  1444. Assert( pszText );
  1445. if ( !pszText )
  1446. return;
  1447. int wordCount = CountWords( pszText );
  1448. if ( wordCount <= 0 )
  1449. return;
  1450. float wordLength = ( flSentenceDuration - 2 * STARTEND_TIMEGAP) / (float)wordCount;
  1451. float wordStart = STARTEND_TIMEGAP;
  1452. Reset();
  1453. char word[ 256 ];
  1454. unsigned char const *in = (unsigned char *)pszText;
  1455. char *out = word;
  1456. while ( *in )
  1457. {
  1458. if ( !ShouldSplitWord( *in ) )
  1459. {
  1460. *out++ = *in++;
  1461. }
  1462. else
  1463. {
  1464. *out = 0;
  1465. // Skip over splitters
  1466. while ( *in && ( ShouldSplitWord( *in ) ) )
  1467. {
  1468. in++;
  1469. }
  1470. if ( strlen( word ) > 0 )
  1471. {
  1472. CWordTag *w = new CWordTag();
  1473. Assert( w );
  1474. w->SetWord( word );
  1475. w->m_flStartTime = wordStart;
  1476. w->m_flEndTime = wordStart + wordLength;
  1477. AddWordTag( w );
  1478. wordStart += wordLength;
  1479. }
  1480. out = word;
  1481. }
  1482. }
  1483. *out = 0;
  1484. if ( strlen( word ) > 0 )
  1485. {
  1486. CWordTag *w = new CWordTag();
  1487. Assert( w );
  1488. w->SetWord( word );
  1489. w->m_flStartTime = wordStart;
  1490. w->m_flEndTime = wordStart + wordLength;
  1491. AddWordTag( w );
  1492. wordStart += wordLength;
  1493. }
  1494. }
  1495. #endif // !_STATIC_LINKED || _SHARED_LIB