Leaked source code of windows server 2003
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.

341 lines
11 KiB

  1. /*******************************************************************************
  2. * TTSEngine.cpp *
  3. *---------------*
  4. * Description:
  5. * This module is the main implementation file for the CTTSEngine class.
  6. *-------------------------------------------------------------------------------
  7. * Created By: EDC Date: 03/12/99
  8. * Copyright (C) 1999 Microsoft Corporation
  9. * All Rights Reserved
  10. *
  11. *******************************************************************************/
  12. //--- Additional includes
  13. #include "stdafx.h"
  14. #include <stdio.h>
  15. #include "TTSEngine.h"
  16. #include "stdsentenum.h"
  17. #include "VoiceDataObj.h"
  18. #include "commonlx.h"
  19. /*****************************************************************************
  20. * CTTSEngine::FinalConstruct *
  21. *----------------------------*
  22. * Description:
  23. * Constructor
  24. ********************************************************************* EDC ***/
  25. HRESULT CTTSEngine::FinalConstruct()
  26. {
  27. SPDBG_FUNC( "CTTSEngine::FinalConstruct" );
  28. HRESULT hr = S_OK;
  29. return hr;
  30. } /* CTTSEngine::FinalConstruct */
  31. /*****************************************************************************
  32. * CTTSEngine::FinalRelease *
  33. *--------------------------*
  34. * Description:
  35. * destructor
  36. ********************************************************************* EDC ***/
  37. void CTTSEngine::FinalRelease()
  38. {
  39. SPDBG_FUNC( "CTTSEngine::FinalRelease" );
  40. } /* CTTSEngine::FinalRelease */
  41. /*****************************************************************************
  42. * CTTSEngine::VoiceInit *
  43. *-----------------------*
  44. * Description:
  45. * This method is called by the voice data object during construction
  46. * to give the TTS driver object access to the voice unit data.
  47. ******************************************************************* PACOG ***/
  48. STDMETHODIMP CTTSEngine::VoiceInit( IMSVoiceData* pVoiceData )
  49. {
  50. SPDBG_FUNC( "CTTSEngine::VoiceInit" );
  51. HRESULT hr = S_OK;
  52. //--- Create sentence enumerator and initialize
  53. CComObject<CStdSentEnum> *pSentEnum;
  54. hr = CComObject<CStdSentEnum>::CreateInstance( &pSentEnum );
  55. //--- Create aggregate lexicon
  56. if ( SUCCEEDED( hr ) )
  57. {
  58. hr = pSentEnum->InitAggregateLexicon();
  59. }
  60. //--- Get our voice token
  61. CComPtr<ISpObjectToken> cpVoiceToken;
  62. if (SUCCEEDED(hr))
  63. {
  64. cpVoiceToken = ((CVoiceDataObj*)pVoiceData)->GetVoiceToken();
  65. }
  66. //--- Create vendor lexicon and add to aggregate
  67. if (SUCCEEDED(hr))
  68. {
  69. CComPtr<ISpObjectToken> cpToken;
  70. hr = SpGetSubTokenFromToken(cpVoiceToken, L"Lex", &cpToken);
  71. CComPtr<ISpLexicon> cpCompressedLexicon;
  72. if (SUCCEEDED(hr))
  73. {
  74. hr = SpCreateObjectFromToken(cpToken, &cpCompressedLexicon);
  75. }
  76. if (SUCCEEDED(hr))
  77. {
  78. hr = pSentEnum->AddLexiconToAggregate(cpCompressedLexicon, eLEXTYPE_PRIVATE1);
  79. }
  80. }
  81. //--- Create LTS lexicon and add to aggregate
  82. if (SUCCEEDED(hr))
  83. {
  84. CComPtr<ISpObjectToken> cpToken;
  85. hr = SpGetSubTokenFromToken(cpVoiceToken, L"Lts", &cpToken);
  86. CComPtr<ISpLexicon> cpLTSLexicon;
  87. if (SUCCEEDED(hr))
  88. {
  89. hr = SpCreateObjectFromToken(cpToken, &cpLTSLexicon);
  90. }
  91. if (SUCCEEDED(hr))
  92. {
  93. hr = pSentEnum->AddLexiconToAggregate(cpLTSLexicon, eLEXTYPE_PRIVATE2);
  94. }
  95. }
  96. //--- Create morphology lexicon
  97. if ( SUCCEEDED( hr ) )
  98. {
  99. hr = pSentEnum->InitMorphLexicon();
  100. }
  101. //--- Set member sentence enumerator
  102. if ( SUCCEEDED( hr ) )
  103. {
  104. m_cpSentEnum = pSentEnum;
  105. }
  106. //--- Save voice data interface, do not AddRef or it will cause circular reference
  107. if( SUCCEEDED( hr ) )
  108. {
  109. m_pVoiceDataObj = pVoiceData;
  110. hr = InitDriver();
  111. }
  112. return hr;
  113. } /* CTTSEngine::VoiceInit */
  114. /*****************************************************************************
  115. * CTTSEngine::Speak *
  116. *-------------------*
  117. * Description:
  118. * This method is supposed to speak the text observing the associated
  119. * XML state.
  120. ********************************************************************* EDC ***/
  121. STDMETHODIMP CTTSEngine::
  122. Speak( DWORD dwSpeakFlags, REFGUID rguidFormatId,
  123. const WAVEFORMATEX * /* pWaveFormatEx ignored */,
  124. const SPVTEXTFRAG* pTextFragList,
  125. ISpTTSEngineSite* pOutputSite )
  126. {
  127. SPDBG_FUNC( "CTTSEngine::Speak" );
  128. HRESULT hr = S_OK;
  129. //--- Early exit?
  130. if( ( rguidFormatId != SPDFID_WaveFormatEx && rguidFormatId != SPDFID_Text ) || SP_IS_BAD_INTERFACE_PTR( pOutputSite ) )
  131. {
  132. hr = E_INVALIDARG;
  133. }
  134. else
  135. {
  136. //--- Debug Macro - open file for debugging output
  137. TTSDBG_OPENFILE;
  138. //--- Initialize sentence enumerator
  139. hr = m_cpSentEnum->SetFragList( pTextFragList, dwSpeakFlags );
  140. if( SUCCEEDED( hr ) )
  141. {
  142. // The following code is here just for testing.
  143. // It should be removed once all the tools accept the
  144. // new way of outputing debug info.
  145. if( rguidFormatId == SPDFID_Text )
  146. {
  147. //--- Enumerate and write out all sentence items.
  148. IEnumSENTITEM *pItemEnum;
  149. TTSSentItem Item;
  150. //--- Write unicode signature
  151. static const WCHAR Signature = 0xFEFF;
  152. hr = pOutputSite->Write( &Signature, sizeof(Signature), NULL );
  153. while( (hr = m_cpSentEnum->Next( &pItemEnum) ) == S_OK )
  154. {
  155. while( (hr = pItemEnum->Next( &Item )) == S_OK )
  156. {
  157. // Is there a valid normalized-word-list?
  158. if ( Item.pItemInfo->Type & eWORDLIST_IS_VALID )
  159. {
  160. for ( ULONG i = 0; i < Item.ulNumWords; i++ )
  161. {
  162. if ( Item.Words[i].pXmlState->eAction == SPVA_Speak ||
  163. Item.Words[i].pXmlState->eAction == SPVA_SpellOut )
  164. {
  165. ULONG cb = Item.Words[i].ulWordLen * sizeof( WCHAR );
  166. hr = pOutputSite->Write( Item.Words[i].pWordText, cb, NULL );
  167. if( hr == S_OK )
  168. {
  169. //--- Insert space between items
  170. hr = pOutputSite->Write( L" ", sizeof( WCHAR ), NULL );
  171. }
  172. }
  173. }
  174. }
  175. else // no word list - just write the original text.
  176. {
  177. ULONG cb = Item.ulItemSrcLen * sizeof( WCHAR );
  178. hr = pOutputSite->Write( Item.pItemSrcText, cb, NULL );
  179. if ( SUCCEEDED(hr) )
  180. {
  181. //--- Insert space between items
  182. hr = pOutputSite->Write( L" ", sizeof( WCHAR ), NULL );
  183. }
  184. }
  185. }
  186. pItemEnum->Release();
  187. //--- Insert mark between sentences
  188. if( SUCCEEDED( hr ) )
  189. {
  190. static const WCHAR CRLF[2] = { 0x000D, 0x000A };
  191. hr = pOutputSite->Write( CRLF, 2*sizeof(WCHAR), NULL );
  192. }
  193. }
  194. static const WCHAR ENDL = 0x0000;
  195. hr = pOutputSite->Write( &ENDL, sizeof(WCHAR), NULL );
  196. }
  197. else
  198. {
  199. //--- Render the text
  200. m_FEObj.PrepareSpeech( m_cpSentEnum, pOutputSite );
  201. m_BEObj.PrepareSpeech( pOutputSite );
  202. do
  203. {
  204. //--- Fill another frame of speech audio
  205. hr = m_BEObj.RenderFrame( );
  206. }
  207. while( (hr == S_OK) && (m_BEObj.GetSpeechState() == SPEECH_CONTINUE) );
  208. }
  209. }
  210. //--- Debug Macro - close debugging file
  211. TTSDBG_CLOSEFILE;
  212. }
  213. return hr;
  214. } /* CTTSEngine::Speak */
  215. /****************************************************************************
  216. * CTTSEngine::GetOutputFormat *
  217. *-----------------------------*
  218. * Description:
  219. *
  220. * Returns:
  221. *
  222. ******************************************************************* PACOG ***/
  223. STDMETHODIMP CTTSEngine::GetOutputFormat(const GUID * pTargetFormatId, const WAVEFORMATEX * /* pTargetWaveFormatEx */,
  224. GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx)
  225. {
  226. SPDBG_FUNC("CTTSEngine::GetOutputFormat");
  227. HRESULT hr = S_OK;
  228. if( ( SP_IS_BAD_WRITE_PTR(pDesiredFormatId) ) ||
  229. ( SP_IS_BAD_WRITE_PTR(ppCoMemDesiredWaveFormatEx) ) )
  230. {
  231. hr = E_INVALIDARG;
  232. }
  233. else if (pTargetFormatId == NULL || *pTargetFormatId != SPDFID_Text)
  234. {
  235. *pDesiredFormatId = SPDFID_WaveFormatEx;
  236. *ppCoMemDesiredWaveFormatEx = (WAVEFORMATEX *)::CoTaskMemAlloc(sizeof(WAVEFORMATEX));
  237. if (*ppCoMemDesiredWaveFormatEx)
  238. {
  239. **ppCoMemDesiredWaveFormatEx = m_VoiceInfo.WaveFormatEx;
  240. }
  241. else
  242. {
  243. hr = E_OUTOFMEMORY;
  244. }
  245. }
  246. else
  247. {
  248. *pDesiredFormatId = SPDFID_Text;
  249. *ppCoMemDesiredWaveFormatEx = NULL;
  250. }
  251. SPDBG_REPORT_ON_FAIL( hr );
  252. return hr;
  253. }
  254. /*****************************************************************************
  255. * CTTSEngine::InitDriver *
  256. *------------------------*
  257. * Description:
  258. * Init driver with new voice.
  259. ********************************************************************** MC ***/
  260. HRESULT CTTSEngine::InitDriver()
  261. {
  262. SPDBG_FUNC( "CTTSEngine::InitDriver" );
  263. HRESULT hr = S_OK;
  264. //--------------------------
  265. // Get voice information
  266. //--------------------------
  267. hr = m_pVoiceDataObj->GetVoiceInfo( &m_VoiceInfo );
  268. if( SUCCEEDED(hr) )
  269. {
  270. m_SampleRate = m_VoiceInfo.SampleRate;
  271. //-----------------------------
  272. // Reverb is always stereo
  273. //-----------------------------
  274. if (m_VoiceInfo.eReverbType != REVERB_TYPE_OFF )
  275. {
  276. //------------------
  277. // Stereo
  278. //------------------
  279. m_IsStereo = true;
  280. m_BytesPerSample = 4;
  281. }
  282. else
  283. {
  284. //------------------
  285. // MONO
  286. //------------------
  287. m_IsStereo = false;
  288. m_BytesPerSample = 2;
  289. }
  290. //--------------------------
  291. // Initialize BACKEND obj
  292. //--------------------------
  293. hr = m_BEObj.Init( m_pVoiceDataObj, &m_FEObj, &m_VoiceInfo );
  294. //--------------------------
  295. // Initialize FRONTEND obj
  296. //--------------------------
  297. if( SUCCEEDED( hr ))
  298. {
  299. hr = m_FEObj.Init( m_pVoiceDataObj, NULL, &m_VoiceInfo );
  300. }
  301. }
  302. return hr;
  303. } /* CTTSEngine::InitDriver */