Source code of Windows XP (NT5)
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.

715 lines
21 KiB

  1. /******************************************************************************
  2. * TrueTalk.cpp *
  3. *--------------*
  4. * This module is the main implementation for class CTrueTalk
  5. *------------------------------------------------------------------------------
  6. * Copyright (C) 2000 Microsoft Corporation Date: 02/29/00
  7. * All Rights Reserved
  8. *
  9. ********************************************************************* PACOG ***/
  10. #include "stdafx.h"
  11. #include "TrueTalk.h"
  12. #include "frontend.h"
  13. #include "backend.h"
  14. #include "queue.h"
  15. const int CTrueTalk::m_iQueueSize = 512;
  16. static const char g_pFlagCharacter = 0x00;
  17. static const unsigned char g_AnsiToAscii[] =
  18. {
  19. /*** Control characters - map to whitespace ***/
  20. 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  21. 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  22. 0x20, 0x20, 0x20, 0x20,
  23. /*** ASCII displayables ***/
  24. 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
  25. 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
  26. 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  27. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
  28. 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
  29. 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,
  30. /*** Control character ***/
  31. 0x20,
  32. /*** Euro symbol ***/
  33. 0x80,
  34. /*** Control character ***/
  35. 0x20,
  36. /*** Extended ASCII values ***/
  37. 0x27, // low single quote - map to single quote
  38. 0x20, // f-like character - map to space
  39. 0x22, // low double quote - map to double quote
  40. 0x2C, // elipsis - map to comma
  41. 0x20, // cross - map to space
  42. 0x20, // double cross - map to space
  43. 0x5E, // caret like accent - map to caret
  44. 0x89, // strange percent like sign
  45. 0x53, // S-hat - map to S
  46. 0x27, // left angle bracket like thing - map to single quote
  47. 0x20, // weird OE character - map to space
  48. 0x20, // control characters - map to space
  49. 0x20,
  50. 0x20,
  51. 0x20,
  52. 0x27, // left single quote - map to single quote
  53. 0x27, // right single quote - map to single quote
  54. 0x22, // left double quote - map to double quote
  55. 0x22, // right double quote - map to double quote
  56. 0x20, // bullet - map to space
  57. 0x2D, // long hyphen - map to hyphen
  58. 0x2D, // even longer hyphen - map to hyphen
  59. 0x7E, // tilde-like thing - map to tilde
  60. 0x98, // TM
  61. 0x73, // s-hat - map to s
  62. 0x27, // right angle bracket like thing - map to single quote
  63. 0x20, // weird oe like character - map to space
  64. 0x20, // control character - map to space
  65. 0x20, // control character - map to space
  66. 0x59, // Y with umlaut like accent - map to Y
  67. 0x20, // space? - map to space
  68. 0x20, // upside-down exclamation point - map to space
  69. 0xA2, // cents symbol
  70. 0xA3, // pounds symbol
  71. 0x20, // generic currency symbol - map to space
  72. 0xA5, // yen symbol
  73. 0x7C, // broken bar - map to bar
  74. 0x20, // strange symbol - map to space
  75. 0x20, // umlaut - map to space
  76. 0xA9, // copyright symbol
  77. 0x20, // strange a character - map to space
  78. 0x22, // strange <<-like character - map to double quote
  79. 0x20, // strange line-like character - map to space
  80. 0x2D, // hyphen-like character - map to hyphen
  81. 0xAE, // registered symbol
  82. 0x20, // high line - map to space
  83. 0xB0, // degree sign
  84. 0xB1, // plus-minus sign
  85. 0xB2, // superscript 2
  86. 0xB3, // superscript 3
  87. 0xB4, // single prime
  88. 0x20, // greek character - map to space
  89. 0x20, // paragraph symbol - map to space
  90. 0x20, // mid-height dot - map to space
  91. 0x20, // cedilla - map to space
  92. 0xB9, // superscript one
  93. 0x20, // circle with line - map to space
  94. 0x22, // strange >>-like character - map to double quote
  95. 0xBC, // vulgar 1/4
  96. 0xBD, // vulgar 1/2
  97. 0xBE, // vulgar 3/4
  98. 0x20, // upside-down question mark - map to space
  99. 0x41, // Accented uppercase As - map to A
  100. 0x41,
  101. 0x41,
  102. 0x41,
  103. 0x41,
  104. 0x41,
  105. 0x41,
  106. 0x43, // C with cedilla - map to C
  107. 0x45, // Accented uppercase Es - map to E
  108. 0x45,
  109. 0x45,
  110. 0x45,
  111. 0x49, // Accented uppercase Is - map to I
  112. 0x49,
  113. 0x49,
  114. 0x49,
  115. 0x20, // strange character - map to space
  116. 0x4E, // Accented uppercase N - map to N
  117. 0x4F, // Accented uppercase Os - map to O
  118. 0x4F,
  119. 0x4F,
  120. 0x4F,
  121. 0x4F,
  122. 0x20, // strange character - map to space
  123. 0x4F, // another O? - map to O
  124. 0x55, // Accented uppercase Us - map to U
  125. 0x55,
  126. 0x55,
  127. 0x55,
  128. 0x59, // Accented uppercase Y - map to Y
  129. 0x20, // strange character - map to space
  130. 0xDF, // Beta
  131. 0x61, // Accented lowercase as - map to a
  132. 0x61,
  133. 0x61,
  134. 0x61,
  135. 0x61,
  136. 0x61,
  137. 0x61,
  138. 0x63, // c with cedilla - map to c
  139. 0x65, // Accented lowercase es - map to e
  140. 0x65,
  141. 0x65,
  142. 0x65,
  143. 0x69, // Accented lowercase is - map to i
  144. 0x69,
  145. 0x69,
  146. 0x69,
  147. 0x75, // eth - map to t
  148. 0x6E, // Accented lowercase n - map to n
  149. 0x6F, // Accented lowercase os - map to o
  150. 0x6F,
  151. 0x6F,
  152. 0x6F,
  153. 0x6F,
  154. 0xF7, // division symbol
  155. 0x6F, // another o? - map to o
  156. 0x76, // Accented lowercase us - map to u
  157. 0x76,
  158. 0x76,
  159. 0x76,
  160. 0x79, // accented lowercase y - map to y
  161. 0x20, // strange character - map to space
  162. 0x79, // accented lowercase y - map to y
  163. };
  164. /*****************************************************************************
  165. * CTrueTalk::InitThreading *
  166. *--------------------------*
  167. * Description:
  168. *
  169. ******************************************************************* PACOG ***/
  170. void CTrueTalk::InitThreading()
  171. {
  172. CFrontEnd::InitThreading();
  173. }
  174. /*****************************************************************************
  175. * CTrueTalk::ReleaseThreading *
  176. *-----------------------------*
  177. * Description:
  178. *
  179. ******************************************************************* PACOG ***/
  180. void CTrueTalk::ReleaseThreading()
  181. {
  182. CFrontEnd::ReleaseThreading();
  183. }
  184. /*****************************************************************************
  185. * CTrueTalk::FinalConstruct *
  186. *---------------------------*
  187. * Description:
  188. * Constructor
  189. ******************************************************************* PACOG ***/
  190. HRESULT CTrueTalk::FinalConstruct()
  191. {
  192. HRESULT hr = S_OK;
  193. m_cpToken = 0;
  194. m_pTtp = 0;
  195. m_pBend = 0;
  196. m_pPhoneQueue = 0;
  197. m_dGain = 1.0;
  198. m_dwDebugLevel = 0;
  199. m_fTextOutput = false;
  200. m_WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
  201. m_WaveFormatEx.nChannels = 1;
  202. m_WaveFormatEx.nSamplesPerSec = 0;
  203. m_WaveFormatEx.nAvgBytesPerSec = 0;
  204. m_WaveFormatEx.nBlockAlign = 2;
  205. m_WaveFormatEx.wBitsPerSample = 16;
  206. m_WaveFormatEx.cbSize = 0;
  207. return hr;
  208. }
  209. /*****************************************************************************
  210. * CTrueTalk::FinalRelease *
  211. *-------------------------*
  212. * Description:
  213. * Destructor
  214. ******************************************************************* PACOG ***/
  215. void CTrueTalk::FinalRelease()
  216. {
  217. if ( m_pTtp)
  218. {
  219. delete m_pTtp;
  220. }
  221. if ( m_pBend )
  222. {
  223. delete m_pBend;
  224. }
  225. if (m_pPhoneQueue)
  226. {
  227. delete m_pPhoneQueue;
  228. }
  229. }
  230. /*****************************************************************************
  231. * CTrueTalk::SetObjectToken *
  232. *---------------------------*
  233. * Description:
  234. * This function performs the majority of the initialization of the voice.
  235. * Once the object token has been provided, the filenames are read from the
  236. * token key and the files are mapped.+++
  237. ******************************************************************* PACOG ***/
  238. STDMETHODIMP CTrueTalk::SetObjectToken (ISpObjectToken * pToken)
  239. {
  240. HRESULT hr = SpGenericSetObjectToken(pToken, m_cpToken);
  241. char pszFilePath[_MAX_PATH+1];
  242. bool fIsBrEng = false;
  243. //-- Read debug info first
  244. if ( SUCCEEDED (hr) )
  245. {
  246. hr = m_cpToken->GetDWORD (L"DebugInterest", &m_dwDebugLevel);
  247. if ( FAILED(hr) )
  248. {
  249. m_dwDebugLevel = 0;
  250. hr = S_OK;
  251. }
  252. }
  253. // Determine engine language
  254. if (SUCCEEDED(hr))
  255. {
  256. CComPtr<ISpObjectToken> cpToken;
  257. CSpDynamicString dstrLanguage;
  258. hr = SpGetSubTokenFromToken(m_cpToken, L"Attributes", &cpToken);
  259. if (SUCCEEDED(hr))
  260. {
  261. hr = cpToken->GetStringValue (L"Language", &dstrLanguage);
  262. }
  263. if (SUCCEEDED(hr))
  264. {
  265. WCHAR* ptr;
  266. ptr = wcschr (dstrLanguage.m_psz, ';');
  267. if ( ptr )
  268. {
  269. *ptr = 0;
  270. }
  271. if (wcscmp(dstrLanguage.m_psz, L"809") == 0)
  272. {
  273. fIsBrEng = true;
  274. }
  275. }
  276. }
  277. //-- Initialize front-end
  278. if ( SUCCEEDED (hr) )
  279. {
  280. CSpDynamicString dstrFilePath;
  281. hr = m_cpToken->GetStringValue( L"Dictionary", &dstrFilePath );
  282. if (SUCCEEDED(hr))
  283. {
  284. WideCharToMultiByte (CP_ACP, 0, dstrFilePath.m_psz, -1, pszFilePath, _MAX_PATH, 0, 0);
  285. }
  286. }
  287. if ( SUCCEEDED (hr) )
  288. {
  289. if ((m_pTtp = CFrontEnd::ClassFactory()) == 0)
  290. {
  291. return E_OUTOFMEMORY;
  292. }
  293. if (!m_pTtp->Init (pszFilePath, 0))
  294. {
  295. if (m_dwDebugLevel)
  296. {
  297. fprintf (stderr, "Error initializing ttp with dictionary path %s\n", pszFilePath);
  298. }
  299. return E_OUTOFMEMORY;
  300. }
  301. if ((m_pPhoneQueue = new CPhStrQueue (m_iQueueSize)) == 0)
  302. {
  303. return E_OUTOFMEMORY;
  304. }
  305. }
  306. //-- And now, the back end
  307. if ( SUCCEEDED (hr) )
  308. {
  309. CSpDynamicString dstrFilePath;
  310. hr = m_cpToken->GetStringValue( L"Sfont", &dstrFilePath );
  311. if (SUCCEEDED(hr))
  312. {
  313. WideCharToMultiByte (CP_ACP, 0, dstrFilePath.m_psz, -1, pszFilePath, _MAX_PATH, 0, 0);
  314. }
  315. }
  316. if ( SUCCEEDED (hr) )
  317. {
  318. int iBaseLine;
  319. int iRefLine;
  320. int iTopLine;
  321. if ((m_pBend = CBackEnd::ClassFactory()) == 0) {
  322. return E_OUTOFMEMORY;
  323. }
  324. if ( !m_pBend->LoadTable (pszFilePath, m_dwDebugLevel) ) {
  325. if (m_dwDebugLevel)
  326. {
  327. fprintf (stderr, "Error loading table %s\n", pszFilePath);
  328. }
  329. return E_OUTOFMEMORY;
  330. }
  331. CSpDynamicString dstrGain;
  332. hr = m_cpToken->GetStringValue( L"Gain", &dstrGain);
  333. if (SUCCEEDED(hr))
  334. {
  335. m_dGain = wcstod (dstrGain.m_psz, NULL);
  336. m_pBend->SetGain (m_dGain);
  337. }
  338. m_pBend->GetSpeakerInfo(&iBaseLine, &iRefLine, &iTopLine);
  339. m_pTtp->SetSpeakerParams(iBaseLine, iRefLine, iTopLine, fIsBrEng);
  340. m_WaveFormatEx.nSamplesPerSec = m_pBend->GetSampFreq();
  341. m_WaveFormatEx.nAvgBytesPerSec = m_WaveFormatEx.nSamplesPerSec * m_WaveFormatEx.nBlockAlign;
  342. }
  343. return hr;
  344. }
  345. /****************************************************************************
  346. * CTrueTalk::GetOutputFormat *
  347. *----------------------------*
  348. * Description:
  349. *
  350. * Returns:
  351. *
  352. ******************************************************************* PACOG ***/
  353. HRESULT CTrueTalk::GetOutputFormat( const GUID * pTargetFormatId,
  354. const WAVEFORMATEX * pTargetWaveFormatEx,
  355. GUID * pDesiredFormatId,
  356. WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx )
  357. {
  358. HRESULT hr = S_OK;
  359. if( ( SP_IS_BAD_WRITE_PTR(pDesiredFormatId) ) ||
  360. ( SP_IS_BAD_WRITE_PTR(ppCoMemDesiredWaveFormatEx) ) )
  361. {
  362. hr = E_POINTER;
  363. }
  364. if ( pTargetFormatId && *pTargetFormatId == SPDFID_Text)
  365. {
  366. *pDesiredFormatId = SPDFID_Text;
  367. m_fTextOutput = true;
  368. }
  369. else
  370. {
  371. *pDesiredFormatId = SPDFID_WaveFormatEx;
  372. *ppCoMemDesiredWaveFormatEx = (WAVEFORMATEX *)::CoTaskMemAlloc(sizeof(WAVEFORMATEX));
  373. if (*ppCoMemDesiredWaveFormatEx)
  374. {
  375. **ppCoMemDesiredWaveFormatEx = m_WaveFormatEx;
  376. }
  377. else
  378. {
  379. hr = E_OUTOFMEMORY;
  380. }
  381. }
  382. return hr;
  383. }
  384. /*****************************************************************************
  385. * CTrueTalk::Speak *
  386. *------------------*
  387. * Description:
  388. * This method is supposed to speak the text observing the associated
  389. * XML state.
  390. ******************************************************************* PACOG ***/
  391. HRESULT CTrueTalk::Speak (DWORD dwSpeakFlags,
  392. REFGUID rguidFormatId,
  393. const WAVEFORMATEX * pWaveFormatEx,
  394. const SPVTEXTFRAG * pTextFragList,
  395. ISpTTSEngineSite * pOutputSite)
  396. {
  397. HRESULT hr = S_OK;
  398. Phone* pPhones = 0;
  399. int iNumPhones;
  400. float* pfF0 = 0;
  401. int iNumF0;
  402. char* pcSamples = 0;
  403. int iNumSamples = 0;
  404. if (SyncActions(pOutputSite) != 0)
  405. {
  406. goto exit;
  407. }
  408. hr = RunFrontEnd (pTextFragList, pOutputSite);
  409. if ( FAILED(hr) )
  410. {
  411. goto exit;
  412. }
  413. while ( m_pPhoneQueue->Size() >0 ) //-- While something to synthesize
  414. {
  415. pPhones = 0;
  416. iNumPhones = 0;
  417. pfF0 = 0;
  418. iNumF0 = 0;
  419. //-- Got something from front end, synthesize
  420. if (m_pPhoneQueue->FirstElement (&pPhones, &iNumPhones, &pfF0, &iNumF0))
  421. {
  422. m_pPhoneQueue->Forward();
  423. m_pBend->NewPhoneString (pPhones, iNumPhones, pfF0, iNumF0);
  424. while ( m_pBend->OutputPending() )
  425. {
  426. if (SyncActions(pOutputSite) != 0)
  427. {
  428. break;
  429. }
  430. if (!m_pBend->GenerateOutput ( (short**)&pcSamples, &iNumSamples)) {
  431. hr = E_OUTOFMEMORY;
  432. goto exit;
  433. }
  434. if (pcSamples)
  435. {
  436. hr = pOutputSite->Write (pcSamples, iNumSamples*sizeof(short), 0);
  437. pcSamples = 0;
  438. iNumSamples = 0;
  439. if ( FAILED (hr) )
  440. {
  441. goto exit;
  442. }
  443. }
  444. }
  445. }
  446. if (pPhones)
  447. {
  448. free (pPhones);
  449. pPhones = 0;
  450. }
  451. if (pfF0)
  452. {
  453. free (pfF0);
  454. pfF0 = 0;
  455. }
  456. }
  457. exit:
  458. if (pPhones)
  459. {
  460. free (pPhones);
  461. }
  462. if (pfF0)
  463. {
  464. free (pfF0);
  465. }
  466. return hr;
  467. }
  468. /*****************************************************************************
  469. * CTrueTalk::RunFrontEnd *
  470. *------------------------*
  471. * Description:
  472. *
  473. ******************************************************************* PACOG ***/
  474. HRESULT CTrueTalk::RunFrontEnd (const SPVTEXTFRAG *pTextFragList, ISpTTSEngineSite* pOutputSite)
  475. {
  476. HRESULT hr = S_OK;
  477. int iStrLen;
  478. char* pszTxtPtr;
  479. Phone* pPhones;
  480. int iNumPhones;
  481. float* pfF0;
  482. int iNumF0;
  483. const SPVTEXTFRAG* pTempFrag = pTextFragList;
  484. m_pPhoneQueue->Reset();
  485. //Estimate size of array
  486. iStrLen = 0;
  487. for ( pTempFrag = pTextFragList; pTempFrag ; pTempFrag = pTempFrag->pNext )
  488. {
  489. if (pTempFrag->State.eAction == SPVA_Speak ||
  490. pTempFrag->State.eAction == SPVA_Pronounce ||
  491. pTempFrag->State.eAction == SPVA_SpellOut)
  492. {
  493. iStrLen += pTempFrag->ulTextLen + 1;
  494. }
  495. }
  496. if ( iStrLen )
  497. {
  498. if (m_fTextOutput)
  499. {
  500. //--- Write unicode signature
  501. static const WCHAR Signature = 0xFEFF;
  502. hr = pOutputSite->Write( &Signature, sizeof(Signature), NULL );
  503. for (pTempFrag = pTextFragList; SUCCEEDED(hr) && pTempFrag; pTempFrag = pTempFrag->pNext)
  504. {
  505. if (pTempFrag->State.eAction == SPVA_Speak ||
  506. pTempFrag->State.eAction == SPVA_Pronounce ||
  507. pTempFrag->State.eAction == SPVA_SpellOut)
  508. {
  509. hr = pOutputSite->Write( (WCHAR*)pTempFrag->pTextStart, pTempFrag->ulTextLen * sizeof(WCHAR), NULL );
  510. if (SUCCEEDED(hr))
  511. {
  512. hr = pOutputSite->Write( L" ", sizeof(WCHAR), NULL );
  513. }
  514. }
  515. }
  516. //--- Insert mark between blocks
  517. if( SUCCEEDED( hr ) )
  518. {
  519. static const WCHAR CRLF[2] = { 0x000D, 0x000A };
  520. hr = pOutputSite->Write( CRLF, 2*sizeof(WCHAR), NULL );
  521. }
  522. if( SUCCEEDED( hr ) )
  523. {
  524. static const WCHAR ENDL = 0x0000;
  525. hr = pOutputSite->Write( &ENDL, sizeof(WCHAR), NULL );
  526. }
  527. }
  528. else
  529. {
  530. //Allocate array
  531. char* pszString = new char[iStrLen + 2];
  532. if ( !pszString)
  533. {
  534. hr = E_OUTOFMEMORY;
  535. }
  536. iStrLen = 0;
  537. //Copy data into array
  538. for (pTempFrag = pTextFragList; SUCCEEDED(hr) && pTempFrag; pTempFrag = pTempFrag->pNext)
  539. {
  540. if (pTempFrag->State.eAction == SPVA_Speak ||
  541. pTempFrag->State.eAction == SPVA_Pronounce ||
  542. pTempFrag->State.eAction == SPVA_SpellOut)
  543. {
  544. hr = DoUnicodeToAsciiMap( (WCHAR*)pTempFrag->pTextStart, pTempFrag->ulTextLen, pszString + iStrLen);
  545. iStrLen += pTempFrag->ulTextLen;
  546. pszString[iStrLen++] = ' ';
  547. }
  548. }
  549. pszString[iStrLen] = '\0';
  550. //Process string
  551. m_pTtp->Lock();
  552. pszTxtPtr = pszString;
  553. while (SUCCEEDED(hr) && pszTxtPtr)
  554. {
  555. pPhones = 0;
  556. iNumPhones = 0;
  557. pfF0 = 0;
  558. iNumF0 = 0;
  559. //-- These calls are serialized (critical section), to avoid
  560. // conflicts with other channels.
  561. pszTxtPtr = m_pTtp->Process (pszTxtPtr, &pPhones, &iNumPhones, &pfF0, &iNumF0);
  562. if (iNumPhones)
  563. {
  564. if ( ! m_pPhoneQueue->Push (pPhones, iNumPhones, pfF0, iNumF0) )
  565. {
  566. hr = E_OUTOFMEMORY;
  567. }
  568. }
  569. }
  570. m_pTtp->Unlock();
  571. delete[] pszString;
  572. }
  573. }
  574. return hr;
  575. }
  576. /*****************************************************************************
  577. * CTrueTalk::DoUnicodeToAsciiMap *
  578. *--------------------------------*
  579. * Description:
  580. *
  581. ******************************************************************* PACOG ***/
  582. HRESULT CTrueTalk::DoUnicodeToAsciiMap ( const WCHAR *pUnicodeString, ULONG ulUnicodeStringLength,
  583. char* pszAsciiString )
  584. {
  585. HRESULT hr = S_OK;
  586. if ( pUnicodeString && ulUnicodeStringLength > 0 && pszAsciiString)
  587. {
  588. //--- Map WCHARs to ANSI chars
  589. if ( !WideCharToMultiByte( 1252, NULL, pUnicodeString, ulUnicodeStringLength, pszAsciiString,
  590. ulUnicodeStringLength, &g_pFlagCharacter, NULL ) )
  591. {
  592. hr = E_UNEXPECTED;
  593. }
  594. if (SUCCEEDED(hr))
  595. {
  596. //--- Use internal table to map ANSI to ASCII
  597. for (ULONG i = 0; i <ulUnicodeStringLength; i++)
  598. {
  599. pszAsciiString[i] = g_AnsiToAscii[(unsigned char)pszAsciiString[i]];
  600. }
  601. pszAsciiString[i] = '\0';
  602. // pszAsciiString[i] = ' ';
  603. // pszAsciiString[i+1] = '\0';
  604. }
  605. }
  606. return hr;
  607. } /* CTrueTalk::DoUnicodeToAsciiMap */
  608. /*****************************************************************************
  609. * CTrueTalk::SyncActions *
  610. *------------------------*
  611. * Description:
  612. *
  613. ******************************************************************* PACOG ***/
  614. int CTrueTalk::SyncActions(ISpTTSEngineSite * pOutputSite)
  615. {
  616. int iActions = pOutputSite->GetActions();
  617. if ( iActions != SPVES_CONTINUE )
  618. {
  619. if (iActions & SPVES_SKIP)
  620. {
  621. //This might not be the best default
  622. // maybe completely ignoring the flag...
  623. pOutputSite->CompleteSkip (0);
  624. }
  625. if (iActions & SPVES_RATE)
  626. {
  627. long lRate;
  628. pOutputSite->GetRate (&lRate);
  629. m_pTtp->SetRate (lRate);
  630. }
  631. if (iActions & SPVES_VOLUME)
  632. {
  633. unsigned short usVolume;
  634. pOutputSite->GetVolume (&usVolume);
  635. m_pBend->SetGain ( (m_dGain * usVolume) / 100.0);
  636. }
  637. }
  638. return (iActions & SPVES_ABORT);
  639. }