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.

1263 lines
41 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // LocalTTSEngineSite.cpp: implementation of the CLocalTTSEngineSite class.
  3. //
  4. // Created by JOEM 02-2000
  5. // Copyright (C) 2000 Microsoft Corporation
  6. // All Rights Reserved
  7. //
  8. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  9. #include "LocalTTSEngineSite.h"
  10. #include <LIMITS>
  11. #include <spddkhlp.h>
  12. #include "vapiIO.h"
  13. // If buffer is used, the min size is one sec
  14. const int g_iMinBufferSize = 1;
  15. const int g_iMaxBufferSize = 60; // let's keep it reasonable, ok!
  16. const float g_dMinBufferShift = .25;
  17. const double g_dChunkSize = .10;
  18. const int g_iBase = 16;
  19. // Default duration of chunks written from buffer to SAPI
  20. /////////////////////////////////////////////////////////////////////////////
  21. // CLocalTTSEngineSite
  22. //
  23. // Construction/Destruction
  24. //
  25. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  26. CLocalTTSEngineSite::CLocalTTSEngineSite()
  27. {
  28. m_vcRef = 1;
  29. m_pMainOutputSite = NULL;
  30. m_pOutputFormatId = NULL;
  31. m_pOutputFormat = NULL;
  32. m_pcBuffer = NULL;
  33. m_ulBufferBytes = 0;
  34. m_ulBufferSeconds = 0;
  35. m_ulMinBufferShift = 0;
  36. m_ulDataEnd = 0;
  37. m_ulCurrentByte = 0;
  38. m_ulSkipForward = 0;
  39. m_pEventQueue = NULL;
  40. m_pCurrentEvent = NULL;
  41. m_pLastEvent = NULL;
  42. m_ullTotalBytesReceived = 0;
  43. m_ullPreviousBytesReceived = 0;
  44. m_ullBytesWritten = 0;
  45. m_ullBytesWrittenToSAPI = 0;
  46. m_lTotalBytesSkipped = 0;
  47. m_pTsm = NULL;
  48. m_flRateAdj = 1.0; // Regular rate unless user changes it.
  49. m_flVol = 1.0; // Full volume unless user changes it.
  50. }
  51. CLocalTTSEngineSite::~CLocalTTSEngineSite()
  52. {
  53. m_pMainOutputSite = NULL;
  54. if ( m_pOutputFormat )
  55. {
  56. free( m_pOutputFormat );
  57. m_pOutputFormat = NULL;
  58. m_pOutputFormatId = NULL;
  59. }
  60. Event* pEvent = m_pEventQueue;
  61. Event* pNextEvent = NULL;
  62. while ( pEvent )
  63. {
  64. pNextEvent = pEvent->pNext;
  65. delete pEvent;
  66. pEvent = pNextEvent;
  67. }
  68. if ( m_pcBuffer )
  69. {
  70. delete [] m_pcBuffer;
  71. m_pcBuffer = NULL;
  72. }
  73. if ( m_pTsm )
  74. {
  75. delete m_pTsm;
  76. m_pTsm = NULL;
  77. }
  78. }
  79. /////////////////////////////////////////////////////////////////////////////
  80. // CLocalTTSEngineSite::QueryInterface
  81. //
  82. //
  83. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  84. STDMETHODIMP CLocalTTSEngineSite::QueryInterface ( REFIID iid, void** ppv )
  85. {
  86. if ( iid == IID_ISpTTSEngineSite )
  87. {
  88. *ppv = (ISpTTSEngineSite*) this;
  89. }
  90. else if ( iid == IID_ISpTTSEngineSite )
  91. {
  92. *ppv = (ISpTTSEngineSite*) this;
  93. }
  94. else if ( iid == IID_ISpEventSink )
  95. {
  96. *ppv = (ISpEventSink*) this;
  97. }
  98. else
  99. {
  100. *ppv = NULL;
  101. return E_NOINTERFACE;
  102. }
  103. ((IUnknown*) *ppv)->AddRef();
  104. return S_OK;
  105. }
  106. /////////////////////////////////////////////////////////////////////////////
  107. // CLocalTTSEngineSite::AddRef
  108. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  109. ULONG CLocalTTSEngineSite::AddRef(void)
  110. {
  111. return InterlockedIncrement(&m_vcRef);
  112. }
  113. /////////////////////////////////////////////////////////////////////////////
  114. // CLocalTTSEngineSite::Release
  115. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  116. ULONG CLocalTTSEngineSite::Release(void)
  117. {
  118. if ( 0 == InterlockedDecrement(&m_vcRef) )
  119. {
  120. delete this;
  121. return 0;
  122. }
  123. return (ULONG) m_vcRef;
  124. }
  125. /////////////////////////////////////////////////////////////////////////////
  126. // CLocalTTSEngineSite::SetOutputSite
  127. //
  128. // Sets pointer to main SAPI output site.
  129. // Sets/resets data buffer and accumulators to zero.
  130. //
  131. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  132. void CLocalTTSEngineSite::SetOutputSite(ISpTTSEngineSite* pOutputSite)
  133. {
  134. SPDBG_FUNC( "CLocalTTSEngineSite::SetOutputSite" );
  135. SPDBG_ASSERT(pOutputSite);
  136. m_pMainOutputSite = pOutputSite;
  137. // flush the buffer
  138. m_ulCurrentByte = 0;
  139. m_ulDataEnd = 0;
  140. m_ulSkipForward = 0;
  141. memset( m_pcBuffer, 0, m_ulBufferBytes * sizeof(char) );
  142. // flush the event queue and start over
  143. Event* pEvent = m_pEventQueue;
  144. Event* pNextEvent = NULL;
  145. while ( pEvent )
  146. {
  147. pNextEvent = pEvent->pNext;
  148. delete pEvent;
  149. pEvent = pNextEvent;
  150. }
  151. m_pEventQueue = NULL;
  152. m_pCurrentEvent = NULL;
  153. m_pLastEvent = NULL;
  154. // reset counters
  155. m_ullTotalBytesReceived = 0;
  156. m_ullPreviousBytesReceived = 0;
  157. m_ullBytesWritten = 0;
  158. m_ullBytesWrittenToSAPI = 0;
  159. m_lTotalBytesSkipped = 0;
  160. m_flRateAdj = 1.0; // Regular rate unless user changes it.
  161. m_flVol = 1.0; // Full volume unless user changes it.
  162. }
  163. /////////////////////////////////////////////////////////////////////////////
  164. // CLocalTTSEngineSite::SetBufferSize
  165. //
  166. // Sets the size of the audio data buffer, and creates the buffer if the
  167. // output format is known (but Text output is not buffered).
  168. //
  169. // **Destroys contents of existing buffer.** That's ok, because this function
  170. // is not exposed to the application -- just to the engine, where speak calls
  171. // are synchronous.
  172. //
  173. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  174. STDMETHODIMP CLocalTTSEngineSite::SetBufferSize(const ULONG ulSeconds)
  175. {
  176. SPDBG_FUNC( "CLocalTTSEngineSite::SetBufferSize" );
  177. HRESULT hr = S_OK;
  178. // don't need to preserve contents of old buffer -- it's flushed between
  179. // speak calls anyway.
  180. if ( m_pcBuffer )
  181. {
  182. delete [] m_pcBuffer;
  183. m_pcBuffer = NULL;
  184. }
  185. m_ulBufferBytes = 0;
  186. m_ulBufferSeconds = 0;
  187. m_ulMinBufferShift = 0;
  188. m_ulDataEnd = 0;
  189. m_ulCurrentByte = 0;
  190. if ( ulSeconds )
  191. {
  192. if ( ulSeconds < g_iMinBufferSize )
  193. {
  194. m_ulBufferSeconds = g_iMinBufferSize;
  195. }
  196. else if ( ulSeconds > g_iMaxBufferSize )
  197. {
  198. m_ulBufferSeconds = g_iMaxBufferSize;
  199. }
  200. else
  201. {
  202. m_ulBufferSeconds = ulSeconds;
  203. }
  204. // check format -- don't set a buffer for text format
  205. if ( m_pOutputFormatId )
  206. {
  207. if ( *m_pOutputFormatId != SPDFID_Text )
  208. {
  209. // if the wav format is defined, allocate the buffer for the correct #secs of data
  210. if ( m_pOutputFormat )
  211. {
  212. m_ulBufferBytes = m_ulBufferSeconds * m_pOutputFormat->nAvgBytesPerSec;
  213. m_pcBuffer = new char[m_ulBufferBytes];
  214. if ( !m_pcBuffer )
  215. {
  216. m_ulBufferBytes = 0;
  217. m_ulBufferSeconds = 0;
  218. hr = E_OUTOFMEMORY;
  219. }
  220. if ( SUCCEEDED(hr) )
  221. {
  222. // Make the min shift approximately 1/4 of buffer
  223. // When the buffer is full, data shifts off the end by this amount.
  224. m_ulMinBufferShift = g_dMinBufferShift * m_ulBufferBytes;
  225. // data must shift by multiples of nBlockAlign
  226. m_ulMinBufferShift -= ( m_ulMinBufferShift % m_pOutputFormat->nBlockAlign );
  227. }
  228. }
  229. }
  230. else
  231. {
  232. m_ulBufferSeconds = 0; // can't buffer text - but not an error(?)
  233. }
  234. }
  235. }
  236. SPDBG_REPORT_ON_FAIL( hr );
  237. return hr;
  238. }
  239. //////////////////////////////////////////////////////////////////////
  240. // CLocalTTSEngineSite::SetOutputFormat
  241. //
  242. // Sets the format in which samples are sent to SAPI.
  243. // Also creates the rate changer.
  244. //
  245. ////////////////////////////////////////////////////// JOEM 01-2001 //
  246. STDMETHODIMP CLocalTTSEngineSite::SetOutputFormat(const GUID *pOutputFormatId, const WAVEFORMATEX *pOutputFormat)
  247. {
  248. SPDBG_FUNC( "CLocalTTSEngineSite::SetOutputFormat" );
  249. HRESULT hr = S_OK;
  250. SPDBG_ASSERT(pOutputFormatId);
  251. if ( pOutputFormatId && *pOutputFormatId == SPDFID_Text )
  252. {
  253. m_pOutputFormatId = pOutputFormatId;
  254. SetBufferSize(0); // deletes the current buffer, if any (can't buffer text)
  255. if ( m_pOutputFormat )
  256. {
  257. delete m_pOutputFormat;
  258. m_pOutputFormat = NULL;
  259. }
  260. }
  261. else if ( pOutputFormat )
  262. {
  263. // Do we need to change the format?
  264. if ( !m_pOutputFormat ||
  265. m_pOutputFormat->wFormatTag != pOutputFormat->wFormatTag ||
  266. m_pOutputFormat->nChannels != pOutputFormat->nChannels ||
  267. m_pOutputFormat->nSamplesPerSec != pOutputFormat->nSamplesPerSec ||
  268. m_pOutputFormat->nAvgBytesPerSec != pOutputFormat->nAvgBytesPerSec ||
  269. m_pOutputFormat->nBlockAlign != pOutputFormat->nBlockAlign ||
  270. m_pOutputFormat->wBitsPerSample != pOutputFormat->wBitsPerSample ||
  271. m_pOutputFormat->cbSize != pOutputFormat->cbSize
  272. )
  273. {
  274. // save these values to determine whether buffer and/or rate changer need adjusting
  275. // for the new format
  276. DWORD oldnAvgBytesPerSec = 0;
  277. DWORD oldnSamplesPerSec = 0;
  278. if ( m_pOutputFormat )
  279. {
  280. oldnAvgBytesPerSec = m_pOutputFormat->nAvgBytesPerSec;
  281. oldnSamplesPerSec = m_pOutputFormat->nSamplesPerSec;
  282. }
  283. // free the current waveformatex
  284. if ( m_pOutputFormat )
  285. {
  286. free(m_pOutputFormat);
  287. m_pOutputFormat = NULL;
  288. }
  289. // this needs to copy the output format, not just point to it,
  290. // because engine will pass in const pointer.
  291. m_pOutputFormat = (WAVEFORMATEX*) malloc( sizeof(WAVEFORMATEX) + pOutputFormat->cbSize );
  292. if ( !m_pOutputFormat )
  293. {
  294. hr = E_OUTOFMEMORY;
  295. }
  296. else
  297. {
  298. m_pOutputFormatId = pOutputFormatId;
  299. memcpy(m_pOutputFormat, pOutputFormat, sizeof(WAVEFORMATEX) + pOutputFormat->cbSize );
  300. }
  301. if ( SUCCEEDED(hr) )
  302. {
  303. // Re-adjust the buffer size for the new format, if necessary
  304. if ( oldnAvgBytesPerSec != m_pOutputFormat->nAvgBytesPerSec )
  305. {
  306. hr = SetBufferSize(m_ulBufferSeconds);
  307. }
  308. }
  309. // once we know the sampling frequency, we can create the rate changer
  310. if ( SUCCEEDED(hr) )
  311. {
  312. if ( !m_pTsm )
  313. {
  314. m_pTsm = new CTsm( g_dRateScale[BASE_RATE], m_pOutputFormat->nSamplesPerSec );
  315. }
  316. if ( !m_pTsm )
  317. {
  318. hr = E_OUTOFMEMORY;
  319. }
  320. if ( SUCCEEDED(hr) )
  321. {
  322. // Reset the rate changer sampling frequency, if necessary
  323. if ( oldnSamplesPerSec != m_pOutputFormat->nSamplesPerSec )
  324. {
  325. if ( m_pTsm->SetSamplingFrequency( m_pOutputFormat->nSamplesPerSec )
  326. != m_pOutputFormat->nSamplesPerSec )
  327. {
  328. delete m_pTsm;
  329. m_pTsm = NULL;
  330. hr = E_FAIL;
  331. }
  332. }
  333. }
  334. }
  335. }
  336. }
  337. SPDBG_REPORT_ON_FAIL( hr );
  338. return hr;
  339. }
  340. /////////////////////////////////////////////////////////////////////////////
  341. // CLocalTTSEngineSite::GetActions
  342. //
  343. // When using a buffer, mask all actions except abort. This module handles
  344. // the real-time changes, so it makes the engine output regular rate and vol
  345. // all the time. (But the engine handles XML-based rate/vol changes.)
  346. //
  347. // When not buffering, pass the call to SAPI, but OR'd with vol and rate.
  348. //
  349. //////////////////////////////////////////////////////////// JOEM 02-2000 //
  350. DWORD CLocalTTSEngineSite::GetActions( void )
  351. {
  352. if ( m_pcBuffer )
  353. {
  354. return m_pMainOutputSite->GetActions() & SPVES_ABORT;
  355. }
  356. else
  357. {
  358. // When prompt eng calls GetVolume or GetRate, SAPI turns off the
  359. // SPVES_VOLUME/SPVES_RATE flags. OR them here to force the TTS engine
  360. // to call GetRate and GetVolume too.
  361. return m_pMainOutputSite->GetActions() | SPVES_VOLUME | SPVES_RATE;
  362. }
  363. }
  364. /////////////////////////////////////////////////////////////////////////////
  365. // CLocalTTSEngineSite::GetRate (ISpTTSEngineSite::GetRate)
  366. //
  367. // When using a buffer, simply sets plRateAdjust to 0 to make the engine
  368. // use normal rate (module controls real-time rate changes).
  369. //
  370. // When not buffering, pass the call to SAPI.
  371. //
  372. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  373. STDMETHODIMP CLocalTTSEngineSite::GetRate ( long* plRateAdjust )
  374. {
  375. SPDBG_FUNC( "CLocalTTSEngineSite::GetRate" );
  376. HRESULT hr = S_OK;
  377. if ( m_pcBuffer )
  378. {
  379. *plRateAdjust = 0;
  380. }
  381. else
  382. {
  383. hr = m_pMainOutputSite->GetRate ( plRateAdjust );
  384. }
  385. SPDBG_REPORT_ON_FAIL( hr );
  386. return hr;
  387. }
  388. /////////////////////////////////////////////////////////////////////////////
  389. // CLocalTTSEngineSite::GetVolume (ISpTTSEngineSite::GetVolume)
  390. //
  391. // When using a buffer, simply sets punVolume to 100 to make the engine use
  392. // full volume (module controls real-time vol changes).
  393. //
  394. // When not buffering, pass the call to SAPI.
  395. //
  396. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  397. STDMETHODIMP CLocalTTSEngineSite::GetVolume ( USHORT* punVolume )
  398. {
  399. SPDBG_FUNC( "CLocalTTSEngineSite::GetVolume" );
  400. HRESULT hr = S_OK;
  401. if ( m_pcBuffer )
  402. {
  403. *punVolume = 100;
  404. }
  405. else
  406. {
  407. hr = m_pMainOutputSite->GetVolume ( punVolume );
  408. }
  409. SPDBG_REPORT_ON_FAIL( hr );
  410. return hr;
  411. }
  412. /////////////////////////////////////////////////////////////////////////////
  413. // CLocalTTSEngineSite::GetSkipInfo (ISpTTSEngineSite::GetSkipInfo)
  414. //
  415. // When using a buffer, simply returns 0 to prevent the engine from skipping
  416. // (module controls skips).
  417. //
  418. // When not buffering, pass the call to SAPI.
  419. //
  420. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  421. STDMETHODIMP CLocalTTSEngineSite::GetSkipInfo ( SPVSKIPTYPE* peType, long* plNumItems )
  422. {
  423. SPDBG_FUNC( "CLocalTTSEngineSite::GetSkipInfo" );
  424. HRESULT hr = S_OK;
  425. if ( m_pcBuffer )
  426. {
  427. *peType = SPVST_SENTENCE;
  428. *plNumItems = 0;
  429. }
  430. else
  431. {
  432. hr = m_pMainOutputSite->GetSkipInfo ( peType, plNumItems );
  433. }
  434. SPDBG_REPORT_ON_FAIL( hr );
  435. return hr;
  436. }
  437. /////////////////////////////////////////////////////////////////////////////
  438. // CLocalTTSEngineSite::CompleteSkip (ISpTTSEngineSite::CompleteSkip)
  439. //
  440. // When using a buffer, this just returns.
  441. //
  442. // When not buffering, pass the call to SAPI.
  443. //
  444. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  445. STDMETHODIMP CLocalTTSEngineSite::CompleteSkip ( long lNumSkipped )
  446. {
  447. SPDBG_FUNC( "CLocalTTSEngineSite::CompleteSkip" );
  448. HRESULT hr = S_OK;
  449. if ( !m_pcBuffer )
  450. {
  451. hr = m_pMainOutputSite->CompleteSkip ( lNumSkipped );
  452. }
  453. SPDBG_REPORT_ON_FAIL( hr );
  454. return hr;
  455. }
  456. /////////////////////////////////////////////////////////////////////////////
  457. // CLocalTTSEngineSite::AddEvents (ISpTTSEngineSite::AddEvents)
  458. //
  459. // Two engines (Prompt and TTS) might be writing to this output site.
  460. // Each will not know that the other is sending data, so events
  461. // won't have the correct ullAudioStreamOffset.
  462. //
  463. // Consequently, CLocalTTSEngineSite::UpdateBytesWritten must be called
  464. // after each time the Prompt engine issues a TTS->speak call and after
  465. // each time the PE calls CLocalTTSEngineSite::Write.
  466. //
  467. // Note that when this is used by a single engine, there is no need to
  468. // (or harm in) calling UpdateBytesWritten. Consequently, TTS engines
  469. // require no modification -- the Prompt Engine manages AudioStreamOffset
  470. // when there are 2 engines writing data.
  471. //
  472. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  473. STDMETHODIMP CLocalTTSEngineSite::AddEvents(const SPEVENT* pEventArray, ULONG ulCount )
  474. {
  475. SPDBG_FUNC( "CLocalTTSEngineSite::AddEvents" );
  476. HRESULT hr = S_OK;
  477. ULONG i = 0;
  478. SPDBG_ASSERT(pEventArray || !ulCount);
  479. // Are we buffering?
  480. if ( m_pcBuffer )
  481. {
  482. Event* pNewEvent = NULL;
  483. for ( i=0; SUCCEEDED(hr) && i<ulCount; i++ )
  484. {
  485. // Make a new Event structure
  486. pNewEvent = new Event;
  487. if ( !pNewEvent )
  488. {
  489. hr = E_OUTOFMEMORY;
  490. }
  491. if ( SUCCEEDED(hr) )
  492. {
  493. pNewEvent->pPrev = NULL;
  494. pNewEvent->pNext = NULL;
  495. memcpy(&pNewEvent->event, &pEventArray[i], sizeof(SPEVENT) );
  496. // ullAudioStreamOffset adjusted here since two engines may be writing data
  497. pNewEvent->event.ullAudioStreamOffset += m_ullPreviousBytesReceived;
  498. // Put it in the event queue, sorted
  499. // Is this the only event in the queue?
  500. if ( !m_pEventQueue )
  501. {
  502. m_pEventQueue = pNewEvent;
  503. m_pCurrentEvent = pNewEvent;
  504. m_pLastEvent = pNewEvent;
  505. }
  506. else
  507. {
  508. // Does the new event go last?
  509. if ( m_pLastEvent && m_pLastEvent->event.ullAudioStreamOffset <= pNewEvent->event.ullAudioStreamOffset )
  510. {
  511. m_pLastEvent->pNext = pNewEvent;
  512. pNewEvent->pPrev = m_pLastEvent;
  513. m_pLastEvent = pNewEvent;
  514. }
  515. else
  516. {
  517. // figure out where it goes -- most likely it goes near the end, so step
  518. // backward through the list
  519. Event* pInsertHere = m_pLastEvent;
  520. while ( pInsertHere )
  521. {
  522. if ( pInsertHere->event.ullAudioStreamOffset <= pNewEvent->event.ullAudioStreamOffset )
  523. {
  524. pNewEvent->pPrev = pInsertHere;
  525. pInsertHere->pNext->pPrev = pNewEvent;
  526. pNewEvent->pNext = pInsertHere->pNext;
  527. pInsertHere->pNext = pNewEvent;
  528. }
  529. else
  530. {
  531. pInsertHere = pInsertHere->pPrev;
  532. }
  533. }
  534. // did we reach the front of the list?
  535. if ( !pInsertHere )
  536. {
  537. // insert it at the beginning
  538. pNewEvent->pNext = m_pEventQueue;
  539. m_pEventQueue->pPrev = pNewEvent;
  540. m_pEventQueue = pNewEvent;
  541. }
  542. } // else
  543. } // else
  544. //if there's no current event, make the first in this array current.
  545. if ( !m_pCurrentEvent )
  546. {
  547. m_pCurrentEvent = pNewEvent;
  548. }
  549. } // if ( SUCCEEDED(hr) )
  550. } // for ( i=0; SUCCEEDED(hr) && i<ulCount; i++ )
  551. }
  552. else
  553. {
  554. // no buffer -- just send the events
  555. SPEVENT* pEvents = const_cast<SPEVENT*> (pEventArray);
  556. for ( i=0; i<ulCount; i++ )
  557. {
  558. pEvents[i].ullAudioStreamOffset += m_ullPreviousBytesReceived;
  559. }
  560. hr = m_pMainOutputSite->AddEvents(pEvents, ulCount);
  561. }
  562. SPDBG_REPORT_ON_FAIL( hr );
  563. return hr;
  564. }
  565. /////////////////////////////////////////////////////////////////////////////
  566. // CLocalTTSEngineSite::SendEvents
  567. //
  568. // Steps through the event buffer, sending events that should occur within
  569. // the current block of data.
  570. //
  571. // The event's ullAudioStreamOffset must be adjust by the count of bytes
  572. // skipped (includes skip forward and backward). The sum must then be scaled
  573. // to match the cumulative real-time rate adjustments that have occurred
  574. // (ratio of bytes-sent-to-SAPI to the unaltered byte count).
  575. //
  576. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  577. STDMETHODIMP CLocalTTSEngineSite::SendEvents()
  578. {
  579. SPDBG_FUNC( "CLocalTTSEngineSite::SendEvents" );
  580. HRESULT hr = S_OK;
  581. ULONG ulEventPos = 0;
  582. ULONG ulOriginalOffset = 0;
  583. float flRateAdj = 1.0;
  584. // was there a previous rate adjustment to factor in?
  585. if ( m_ullBytesWrittenToSAPI != m_ullBytesWritten )
  586. {
  587. flRateAdj = (float)m_ullBytesWrittenToSAPI / m_ullBytesWritten;
  588. }
  589. while ( SUCCEEDED(hr) && m_pCurrentEvent )
  590. {
  591. // only send events up to the current byte count
  592. if ( m_pCurrentEvent->event.ullAudioStreamOffset <= (m_ullBytesWritten + m_lTotalBytesSkipped) )
  593. {
  594. ulOriginalOffset = m_pCurrentEvent->event.ullAudioStreamOffset;
  595. // Adjust the cb by amount skipped
  596. // BytesSkipped should never be greater than the current event's position!!
  597. // If this happens, RescheduleEvents is not working properly.
  598. SPDBG_ASSERT(m_lTotalBytesSkipped <= (long)m_pCurrentEvent->event.ullAudioStreamOffset);
  599. m_pCurrentEvent->event.ullAudioStreamOffset -= m_lTotalBytesSkipped;
  600. // Adjust by proportion rate change
  601. m_pCurrentEvent->event.ullAudioStreamOffset *= flRateAdj;
  602. // Make sure it's a multiple of nBlockAlign
  603. m_pCurrentEvent->event.ullAudioStreamOffset -= (m_pCurrentEvent->event.ullAudioStreamOffset % m_pOutputFormat->nBlockAlign );
  604. hr = m_pMainOutputSite->AddEvents(&m_pCurrentEvent->event, 1);
  605. // restore the original in case we need to skip back
  606. m_pCurrentEvent->event.ullAudioStreamOffset = ulOriginalOffset;
  607. m_pCurrentEvent = m_pCurrentEvent->pNext;
  608. }
  609. else
  610. {
  611. break;
  612. }
  613. }
  614. SPDBG_REPORT_ON_FAIL( hr );
  615. return hr;
  616. }
  617. /////////////////////////////////////////////////////////////////////////////
  618. // CLocalTTSEngineSite::RescheduleEvents
  619. //
  620. // Resets the pointer to the current event.
  621. //
  622. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  623. void CLocalTTSEngineSite::RescheduleEvents(Event* pStart)
  624. {
  625. SPDBG_FUNC( "CLocalTTSEngineSite::RescheduleEvents" );
  626. Event* pEvent = pStart;
  627. // Reschedules (or skips) events based on bytes skipped (forward or backward)
  628. while ( pEvent && ( pEvent->event.ullAudioStreamOffset < m_ullBytesWritten + m_lTotalBytesSkipped ) )
  629. {
  630. pEvent = pEvent->pNext;
  631. }
  632. m_pCurrentEvent = pEvent;
  633. }
  634. /////////////////////////////////////////////////////////////////////////////
  635. // CLocalTTSEngineSite::FlushEvents
  636. //
  637. // Some events are flushed when corresponding audio data is pushed off the
  638. // end of the buffer.
  639. //
  640. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  641. void CLocalTTSEngineSite::FlushEvents(const ULONG cb)
  642. {
  643. SPDBG_FUNC( "CLocalTTSEngineSite::FlushEvents" );
  644. Event* pEvent = m_pEventQueue;
  645. Event* pNextEvent = NULL;
  646. while ( pEvent && pEvent->event.ullAudioStreamOffset <= cb )
  647. {
  648. pNextEvent = pEvent->pNext;
  649. delete pEvent;
  650. pEvent = pNextEvent;
  651. if ( pEvent )
  652. {
  653. pEvent->pPrev = NULL;
  654. }
  655. }
  656. if ( pEvent )
  657. {
  658. m_pEventQueue = pEvent;
  659. }
  660. else
  661. {
  662. m_pEventQueue = NULL;
  663. m_pCurrentEvent = NULL;
  664. m_pLastEvent = NULL;
  665. }
  666. }
  667. /////////////////////////////////////////////////////////////////////////////
  668. // CLocalTTSEngineSite::Write
  669. //
  670. // Copies the data (pBuff) onto the end of the audio buffer (at current empty
  671. // location), pushing data off the front of the buffer to make room,
  672. // if necessary.
  673. //
  674. // If buffer size is too small, some of the data is written directly to
  675. // the SAPI output site and the rest will be buffered.
  676. //
  677. // If no buffer exists, all of the data is written directly to SAPI.
  678. //
  679. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  680. STDMETHODIMP CLocalTTSEngineSite::Write( const void* pBuff, ULONG cb, ULONG *pcbWritten )
  681. {
  682. SPDBG_FUNC( "CLocalTTSEngineSite::Write" );
  683. HRESULT hr = S_OK;
  684. long lSpaceNeeded = 0;
  685. char* pcStart = NULL;
  686. ULONG ulBytesToWrite = 0;
  687. bool fAbort = false;
  688. char* pcBuff = (char*)pBuff;
  689. pcStart = pcBuff;
  690. m_ullTotalBytesReceived += cb;
  691. // Are we buffering the samples, or just sending them?
  692. if ( m_pcBuffer )
  693. {
  694. // Do we need extra space?
  695. lSpaceNeeded = ( m_ulDataEnd + cb ) - m_ulBufferBytes;
  696. // if out of space, push some off the front to make room
  697. if ( lSpaceNeeded > 0 )
  698. {
  699. // Is the buffer big enough?
  700. if ( cb > m_ulBufferBytes )
  701. {
  702. ulBytesToWrite = cb - m_ulBufferBytes;
  703. hr = WriteToSAPI( pcBuff, ulBytesToWrite, &fAbort );
  704. if ( SUCCEEDED(hr) )
  705. {
  706. // we're going to replace the entire buffer with what's left
  707. // so the current data in the buffer is garbage now.
  708. m_ulDataEnd = 0;
  709. pcStart = &pcBuff[ulBytesToWrite]; // make pcStart point to what's left after WriteToSapi
  710. // Flush the entire event buffer
  711. FlushEvents(m_ullBytesWritten + m_lTotalBytesSkipped);
  712. }
  713. }
  714. else
  715. {
  716. // how much should we shift off the end?
  717. lSpaceNeeded = ( lSpaceNeeded > m_ulMinBufferShift ) ? lSpaceNeeded : m_ulMinBufferShift;
  718. // Move the stuff we're saving to the beginning of the buffer (overwrite the shifted amount)
  719. memmove( m_pcBuffer, &m_pcBuffer[ lSpaceNeeded ], (m_ulDataEnd - lSpaceNeeded) * sizeof(char) );
  720. // The data end now shifts toward front of buffer
  721. m_ulDataEnd -= lSpaceNeeded;
  722. pcStart = pcBuff; // make pcStart point to all of the new data
  723. // Flush everything received (minus the new bytes) minus what's left to buffer
  724. FlushEvents(m_ullTotalBytesReceived - cb - (m_ulBufferBytes - lSpaceNeeded));
  725. }
  726. }
  727. if ( SUCCEEDED(hr) )
  728. {
  729. // go to the end of the data we're keeping
  730. m_ulCurrentByte = m_ulDataEnd;
  731. // copy new data onto end of buffer.
  732. memcpy( &m_pcBuffer[m_ulCurrentByte], pcStart, cb - ulBytesToWrite );
  733. // Mark the new end
  734. m_ulDataEnd += (cb - ulBytesToWrite);
  735. if ( !fAbort )
  736. {
  737. hr = WriteBuffer();
  738. }
  739. }
  740. }
  741. else
  742. {
  743. hr = WriteToSAPI( pcBuff, cb, &fAbort );
  744. }
  745. if ( SUCCEEDED(hr) && pcbWritten )
  746. {
  747. *pcbWritten = cb;
  748. }
  749. SPDBG_REPORT_ON_FAIL( hr );
  750. return hr;
  751. }
  752. /////////////////////////////////////////////////////////////////////////////
  753. // CLocalTTSEngineSite::WriteBuffer
  754. //
  755. // Sends data from the buffer to SAPI (via WriteToSAPI) in small chunks,
  756. // checking for skip/abort actions. (WriteToSAPI does vol/rate changes).
  757. //
  758. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  759. STDMETHODIMP CLocalTTSEngineSite::WriteBuffer()
  760. {
  761. SPDBG_FUNC( "CLocalTTSEngineSite::WriteBuffer" );
  762. HRESULT hr = S_OK;
  763. ULONG nBytesToWrite = 0;
  764. bool fAbort = false;
  765. ULONG ulChunkSize = 0;
  766. ulChunkSize = g_dChunkSize * m_pOutputFormat->nAvgBytesPerSec;
  767. ulChunkSize -= (ulChunkSize % m_pOutputFormat->nBlockAlign); // write in multiples of nBlockAlign
  768. // Try to write one full chunk (approx. 0.1 sec) of audio per loop
  769. while ( SUCCEEDED(hr) && m_ulCurrentByte < m_ulDataEnd )
  770. {
  771. // Stop speaking?
  772. if ( fAbort || ( m_pMainOutputSite->GetActions() & SPVES_ABORT ) )
  773. {
  774. break;
  775. }
  776. // Still skipping forward?
  777. if ( m_ulSkipForward > 0 )
  778. {
  779. if ( m_ulDataEnd - m_ulCurrentByte > m_ulSkipForward )
  780. {
  781. // there is some data in buffer that can be written
  782. m_ulCurrentByte += m_ulSkipForward; // move the current byte forward by the skip amount
  783. m_lTotalBytesSkipped += m_ulSkipForward; // keep accumulating
  784. m_ulSkipForward = 0; // no more to skip
  785. RescheduleEvents(m_pCurrentEvent); // skip associated events
  786. }
  787. else
  788. {
  789. // skip all of the rest of the data in the buffer and await more
  790. m_ulSkipForward -= ( m_ulDataEnd - m_ulCurrentByte ); // reduce bytes left to skip
  791. m_lTotalBytesSkipped += ( m_ulDataEnd - m_ulCurrentByte ); // keep accumulating
  792. m_ulCurrentByte = m_ulDataEnd; // move to end of buffered data
  793. m_pCurrentEvent = m_pLastEvent; // move to end of event buffer
  794. break; // no data to be written
  795. }
  796. }
  797. // New skip?
  798. if( m_pMainOutputSite->GetActions() & SPVES_SKIP )
  799. {
  800. SPVSKIPTYPE SkipType;
  801. long lSkipCount = 0;
  802. hr = m_pMainOutputSite->GetSkipInfo( &SkipType, &lSkipCount );
  803. if ( SUCCEEDED(hr) )
  804. {
  805. long lBytesToSkip = 0;
  806. long lSkipped = 0;
  807. lBytesToSkip = lSkipCount * m_pOutputFormat->nAvgBytesPerSec;
  808. lBytesToSkip *= m_flRateAdj; // we're skipping by seconds, so rate-adjust
  809. lBytesToSkip -= ( lBytesToSkip % m_pOutputFormat->nBlockAlign ); // need multiple of nBlockAlign
  810. // skipping forward?
  811. if ( lBytesToSkip > 0 )
  812. {
  813. m_ulSkipForward += lBytesToSkip;
  814. lSkipped = lBytesToSkip;
  815. }
  816. else // skipping backward
  817. {
  818. // don't skip backward past the beginning
  819. if ( (long) m_ulCurrentByte + lBytesToSkip < 0 )
  820. {
  821. lSkipped -= m_ulCurrentByte; // just go back to beginning
  822. m_ulCurrentByte = 0;
  823. }
  824. else
  825. {
  826. lSkipped = lBytesToSkip;
  827. m_ulCurrentByte += lSkipped; // lBytesSkipped is negative
  828. }
  829. m_lTotalBytesSkipped += lSkipped;
  830. RescheduleEvents(m_pEventQueue);
  831. }
  832. hr = m_pMainOutputSite->CompleteSkip( lSkipCount );
  833. continue;
  834. }
  835. }
  836. if ( SUCCEEDED(hr) )
  837. {
  838. // Do we have a full chunk of audio samples?
  839. if ( m_ulDataEnd - m_ulCurrentByte > ulChunkSize )
  840. {
  841. // Yes? Write a full chunk
  842. nBytesToWrite = ulChunkSize;
  843. }
  844. else
  845. {
  846. // No? Write all that we have
  847. nBytesToWrite = m_ulDataEnd - m_ulCurrentByte;
  848. // this should always be a multiple of nBlockAlign already!
  849. SPDBG_ASSERT(nBytesToWrite == (nBytesToWrite - (nBytesToWrite % m_pOutputFormat->nBlockAlign) ) );
  850. }
  851. if ( nBytesToWrite )
  852. {
  853. hr = WriteToSAPI( (void*)&m_pcBuffer[m_ulCurrentByte], nBytesToWrite, &fAbort );
  854. }
  855. }
  856. if ( SUCCEEDED(hr) )
  857. {
  858. m_ulCurrentByte += nBytesToWrite;
  859. }
  860. }
  861. SPDBG_REPORT_ON_FAIL( hr );
  862. return hr;
  863. }
  864. /////////////////////////////////////////////////////////////////////////////
  865. // CLocalTTSEngineSite::WriteToSAPI
  866. //
  867. // Forwards the data to the SAPI output site, adjusting vol/rate if necessary.
  868. // Accumulates count of bytes to be written, and bytes actually written to SAPI.
  869. //
  870. //////////////////////////////////////////////////////////// JOEM 01-2001 //
  871. STDMETHODIMP CLocalTTSEngineSite::WriteToSAPI( const void* pvBuff, const ULONG cb, bool* pfAbort )
  872. {
  873. SPDBG_FUNC( "CLocalTTSEngineSite::WriteToSAPI" );
  874. HRESULT hr = S_OK;
  875. void* pvTsmBuff = NULL;
  876. void* pvVolBuff = NULL;
  877. int iNumOutSamples = 0;
  878. ULONG ulOutCb = 0;
  879. long lRateAdj = 0;
  880. const void* pvSendBuff = pvBuff; // this is what we'll send to SAPI, unless Tsm/Vol changes it
  881. SPDBG_ASSERT(pvBuff);
  882. SPDBG_ASSERT(cb);
  883. SPDBG_ASSERT(pfAbort);
  884. if ( m_pOutputFormatId && *m_pOutputFormatId != SPDFID_Text )
  885. {
  886. iNumOutSamples = cb / m_pOutputFormat->nBlockAlign;
  887. if ( m_pcBuffer )
  888. {
  889. // check for rate change
  890. if ( m_pMainOutputSite->GetActions() & SPVES_RATE )
  891. {
  892. hr = m_pMainOutputSite->GetRate( &lRateAdj );
  893. if ( SUCCEEDED(hr) && lRateAdj )
  894. {
  895. ComputeRateAdj(lRateAdj, &m_flRateAdj);
  896. m_pTsm->SetScaleFactor( m_flRateAdj );
  897. }
  898. }
  899. // real-time rate change
  900. if ( SUCCEEDED(hr) && m_pTsm && m_flRateAdj != 1.0 )
  901. {
  902. int iTsmResult = 0;
  903. if ( iNumOutSamples > m_pTsm->GetFrameLen() )
  904. {
  905. iTsmResult = m_pTsm->AdjustTimeScale(pvBuff, iNumOutSamples, &pvTsmBuff, &iNumOutSamples, m_pOutputFormat);
  906. if ( iTsmResult == 0 )
  907. {
  908. hr = E_FAIL;
  909. }
  910. if ( SUCCEEDED(hr) )
  911. {
  912. // send the Tsm modified buff instead of the original
  913. pvSendBuff = pvTsmBuff;
  914. }
  915. }
  916. }
  917. // real-time volume change
  918. if ( SUCCEEDED(hr) )
  919. {
  920. if ( m_pMainOutputSite->GetActions() & SPVES_VOLUME )
  921. {
  922. USHORT unVol = 0;
  923. hr = m_pMainOutputSite->GetVolume( &unVol );
  924. if ( SUCCEEDED(hr) && unVol != 100 )
  925. {
  926. m_flVol = ((float) unVol) / 100; // make dVol fractional
  927. }
  928. }
  929. if ( m_flVol != 1.0 )
  930. {
  931. hr = ApplyGain( pvSendBuff, &pvVolBuff, iNumOutSamples );
  932. // Did ApplyGain need to create a new buffer?
  933. if ( pvVolBuff )
  934. {
  935. // send the volume modified buff instead of the original
  936. pvSendBuff = pvVolBuff;
  937. }
  938. }
  939. }
  940. } // if ( m_pcBuffer )
  941. } // if ( m_pOutputFormatId && *m_pOutputFormatId != SPDFID_Text )
  942. // stop speaking?
  943. if ( m_pMainOutputSite->GetActions() & SPVES_ABORT )
  944. {
  945. *pfAbort = true;
  946. }
  947. if ( SUCCEEDED(hr) && !*pfAbort )
  948. {
  949. ULONG ulOutCb = 0;
  950. m_ullBytesWritten += cb;
  951. if ( m_pOutputFormatId && *m_pOutputFormatId != SPDFID_Text )
  952. {
  953. ulOutCb = iNumOutSamples * m_pOutputFormat->nBlockAlign;
  954. m_ullBytesWrittenToSAPI += ulOutCb;
  955. // send all the buffered events up to the current byte count
  956. hr = SendEvents();
  957. }
  958. else
  959. {
  960. ulOutCb = cb;
  961. m_ullBytesWrittenToSAPI += cb;
  962. }
  963. hr = m_pMainOutputSite->Write(pvSendBuff, ulOutCb, NULL);
  964. }
  965. if ( pvTsmBuff )
  966. {
  967. delete [] pvTsmBuff;
  968. pvTsmBuff = NULL;
  969. }
  970. if ( pvVolBuff )
  971. {
  972. delete [] pvVolBuff;
  973. pvVolBuff = NULL;
  974. }
  975. SPDBG_REPORT_ON_FAIL( hr );
  976. return hr;
  977. }
  978. //////////////////////////////////////////////////////////////////////
  979. // CLocalTTSEngineSite::ComputeRateAdj
  980. //
  981. // Computes the rate multiplier.
  982. //
  983. /////////////////////////////////////////////////////// JOEM 11-2000 //
  984. void CLocalTTSEngineSite::ComputeRateAdj(const long lRate, float* flRate)
  985. {
  986. SPDBG_FUNC( "CLocalTTSEngineSite::ComputeRateAdj" );
  987. SPDBG_ASSERT(flRate);
  988. if ( lRate < 0 )
  989. {
  990. if ( lRate < MIN_RATE )
  991. {
  992. *flRate = 1.0 / g_dRateScale[0 - MIN_RATE];
  993. }
  994. else
  995. {
  996. *flRate = 1.0 / g_dRateScale[0 - lRate];
  997. }
  998. }
  999. else
  1000. {
  1001. if ( lRate > MAX_RATE )
  1002. {
  1003. *flRate = g_dRateScale[MAX_RATE];
  1004. }
  1005. else
  1006. {
  1007. *flRate = g_dRateScale[lRate];
  1008. }
  1009. }
  1010. }
  1011. //////////////////////////////////////////////////////////////////////
  1012. // CLocalTTSEngineSite::ApplyGain
  1013. //
  1014. // Real-time volume adjustment.
  1015. //
  1016. ////////////////////////////////////////////////////// JOEM 01-2001 //
  1017. STDMETHODIMP CLocalTTSEngineSite::ApplyGain(const void* pvInBuff, void** ppvOutBuff, const int iNumSamples)
  1018. {
  1019. SPDBG_FUNC( "CLocalTTSEngineSite::ApplyGain" );
  1020. HRESULT hr = S_OK;
  1021. int i = 0;
  1022. SPDBG_ASSERT(pvInBuff);
  1023. SPDBG_ASSERT(iNumSamples);
  1024. // Apply Volume
  1025. if ( SUCCEEDED(hr) && m_flVol != 1.0 )
  1026. {
  1027. long lGain = (long) ( m_flVol * (1 << g_iBase) );
  1028. if ( m_pOutputFormat->wFormatTag == WAVE_FORMAT_ALAW || m_pOutputFormat->wFormatTag == WAVE_FORMAT_MULAW )
  1029. {
  1030. short* pnBuff = NULL;
  1031. // need to convert samples
  1032. int iOriginalFormatType = VapiIO::TypeOf (m_pOutputFormat);
  1033. if ( iOriginalFormatType == -1 )
  1034. {
  1035. hr = E_FAIL;
  1036. }
  1037. // Allocate the intermediate buffer
  1038. if ( SUCCEEDED(hr) )
  1039. {
  1040. pnBuff = new short[iNumSamples];
  1041. if ( !pnBuff )
  1042. {
  1043. hr = E_OUTOFMEMORY;
  1044. }
  1045. }
  1046. // Allocate the final (out) buffer
  1047. if ( SUCCEEDED(hr) )
  1048. {
  1049. *ppvOutBuff = new char[iNumSamples * VapiIO::SizeOf(iOriginalFormatType)];
  1050. if ( !*ppvOutBuff )
  1051. {
  1052. hr = E_OUTOFMEMORY;
  1053. }
  1054. }
  1055. // Convert to something we can use
  1056. if ( SUCCEEDED(hr) )
  1057. {
  1058. if ( 0 == VapiIO::DataFormatConversion ((char *)pvInBuff, iOriginalFormatType, (char*)pnBuff, VAPI_PCM16, iNumSamples) )
  1059. {
  1060. hr = E_FAIL;
  1061. }
  1062. }
  1063. // Apply gain
  1064. if ( SUCCEEDED(hr) )
  1065. {
  1066. for ( i=0; i<iNumSamples; i++ )
  1067. {
  1068. pnBuff[i] = (short) ( ( pnBuff[i] * lGain ) >> g_iBase );
  1069. }
  1070. }
  1071. // convert it back (from intermediate buff to final out buff)
  1072. if ( SUCCEEDED(hr) )
  1073. {
  1074. if ( 0 == VapiIO::DataFormatConversion ((char *)pnBuff, VAPI_PCM16, (char*)*ppvOutBuff, iOriginalFormatType, iNumSamples) )
  1075. {
  1076. hr = E_FAIL;
  1077. }
  1078. }
  1079. if ( pnBuff )
  1080. {
  1081. delete [] pnBuff;
  1082. pnBuff = NULL;
  1083. }
  1084. }
  1085. else if ( m_pOutputFormat->wFormatTag == WAVE_FORMAT_PCM )
  1086. {
  1087. // no converting necessary
  1088. switch ( m_pOutputFormat->nBlockAlign )
  1089. {
  1090. case 1:
  1091. for ( i=0; i<iNumSamples; i++ )
  1092. {
  1093. ((char*)pvInBuff)[i] = (char) ( (((char*)pvInBuff)[i] * lGain) >> g_iBase );
  1094. }
  1095. break;
  1096. case 2:
  1097. for ( i=0; i<iNumSamples; i++ )
  1098. {
  1099. ((short*)pvInBuff)[i] = (short) ( (((short*)pvInBuff)[i] * lGain) >> g_iBase );
  1100. }
  1101. break;
  1102. default:
  1103. hr = E_FAIL;
  1104. }
  1105. }
  1106. else
  1107. {
  1108. hr = E_FAIL;
  1109. }
  1110. }
  1111. if ( FAILED(hr) )
  1112. {
  1113. if ( *ppvOutBuff )
  1114. {
  1115. delete [] *ppvOutBuff;
  1116. *ppvOutBuff = NULL;
  1117. }
  1118. }
  1119. SPDBG_REPORT_ON_FAIL( hr );
  1120. return hr;
  1121. }