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.

1234 lines
36 KiB

  1. /******************************************************************************
  2. * PitchProsody.cpp *
  3. *--------------------*
  4. *
  5. * This is an implementation of the PitchProsody class.
  6. *------------------------------------------------------------------------------
  7. * Copyright (C) 1999 Microsoft Corporation Date: 04/28/99
  8. * All Rights Reserved
  9. *
  10. *********************************************************************** MC ****/
  11. //--- Additional includes
  12. #include "stdafx.h"
  13. #ifndef SPDebug_h
  14. #include <spdebug.h>
  15. #endif
  16. #ifndef AlloOps_H
  17. #include "AlloOps.h"
  18. #endif
  19. #ifndef Frontend_H
  20. #include "Frontend.h"
  21. #endif
  22. //-----------------------------
  23. // Data.cpp
  24. //-----------------------------
  25. extern const float g_PitchScale[];
  26. //--------------------------------
  27. // Interpolation direction
  28. //--------------------------------
  29. enum INTERP_DIR
  30. {
  31. GOING_UP,
  32. GOING_DOWN,
  33. };
  34. #define M_PI 3.14159265358979323846
  35. #define MAX_ORDER 4096
  36. class CFIRFilter
  37. {
  38. public:
  39. //-------------------------------------------------
  40. // Methods
  41. //-------------------------------------------------
  42. void Make_Filter( float freq1, long order, float srate );
  43. void DoFilter (float *src, float *dst, long len);
  44. void Design_Lowpass (float freq);
  45. //-------------------------------------------------
  46. // Member Variables
  47. //-------------------------------------------------
  48. float m_Coeff[MAX_ORDER];
  49. float m_SRate;
  50. long m_Order;
  51. long m_HalfOrder;
  52. };
  53. //-----------------------------------------------
  54. // Design a low pass filter
  55. //-----------------------------------------------
  56. void CFIRFilter::Design_Lowpass (float freq)
  57. {
  58. float half_Filt[MAX_ORDER];
  59. double w;
  60. long i;
  61. //----------------------------------------------------------
  62. // generate one half of coefficients from sinc() function
  63. //----------------------------------------------------------
  64. w = 2.0 * M_PI * freq;
  65. half_Filt[0] = (float)(w / M_PI);
  66. for (i = 1; i <= m_HalfOrder; i++)
  67. {
  68. half_Filt[i] = (float)(sin(i * w) / (i * M_PI));
  69. }
  70. //----------------------------------------------------------
  71. // window with (half-)hamming window
  72. //----------------------------------------------------------
  73. for (i = 0; i <= m_HalfOrder; i++)
  74. {
  75. half_Filt[i] *= (float)(0.54 + 0.46 * cos(i * M_PI / m_HalfOrder));
  76. }
  77. //----------------------------------------------------------
  78. // copy as symmetric filter
  79. //----------------------------------------------------------
  80. for (i = 0; i < m_Order; i++)
  81. {
  82. m_Coeff[i] = half_Filt[abs(m_HalfOrder - i)];
  83. }
  84. }
  85. //-----------------------------------------------
  86. // Do the filtering
  87. //-----------------------------------------------
  88. void CFIRFilter::DoFilter (float *src, float *dst, long len)
  89. {
  90. #define kWakeSamples 1000;
  91. long i,j;
  92. float *sp;
  93. float sum;
  94. long lenAdj;
  95. lenAdj = len - m_Order;
  96. if (lenAdj >= 0)
  97. {
  98. for (i = 0; i < m_HalfOrder; i++)
  99. {
  100. *dst++ = src[0];
  101. }
  102. for (i = 0; i < lenAdj; i++)
  103. {
  104. sum = (float)0.0;
  105. sp = src + i;
  106. for (j = 0; j < m_Order; j++)
  107. {
  108. sum += ((float)*sp++) * m_Coeff[j];
  109. }
  110. *dst++ = sum;
  111. }
  112. for (i = 0; i < m_HalfOrder; i++)
  113. {
  114. *dst++ = src[len-1];
  115. }
  116. }
  117. }
  118. void CFIRFilter::Make_Filter( float freq1, long order, float srate )
  119. {
  120. m_SRate = srate;
  121. m_Order = order;
  122. m_HalfOrder = m_Order / 2;
  123. Design_Lowpass (freq1 / m_SRate);
  124. }
  125. /*****************************************************************************
  126. * HzToOct *
  127. *---------*
  128. * Description:
  129. * Convert liner freq ro exp pitch
  130. * 0.69314718 is log of 2
  131. * 1.021975 is offset for middle C
  132. *
  133. ********************************************************************** MC ***/
  134. float HzToOct( float cps)
  135. {
  136. SPDBG_FUNC( "HzToOct" );
  137. return (float)(log(cps / 1.021975) / 0.69314718);
  138. } /* HzToOct */
  139. /*****************************************************************************
  140. * OctToHz *
  141. *---------*
  142. * Description:
  143. * Convert from exp pitch to linear freq
  144. ********************************************************************** MC ***/
  145. float OctToHz( float oct)
  146. {
  147. SPDBG_FUNC( "OctToHz" );
  148. return (float)(pow(2, oct) * 1.021975);
  149. } /* OctToHz */
  150. /*****************************************************************************
  151. * CPitchProsody::DoPitchControl *
  152. *-------------------------------*
  153. * Description:
  154. * Scale speech pitch to user control
  155. *
  156. ********************************************************************** MC ***/
  157. float CPitchProsody::DoPitchControl( long pitchControl, float basePitch )
  158. {
  159. SPDBG_FUNC( "CPitchProsody::DoPitchControl" );
  160. float newPitch;
  161. if( pitchControl < 0 )
  162. {
  163. //--------------------------------
  164. // DECREASE the pitch
  165. //--------------------------------
  166. if( pitchControl < MIN_USER_PITCH )
  167. {
  168. pitchControl = MIN_USER_PITCH; // clip to min
  169. }
  170. newPitch = (float)basePitch / g_PitchScale[0 - pitchControl];
  171. }
  172. else
  173. {
  174. //--------------------------------
  175. // INCREASE the pitch
  176. //--------------------------------
  177. if( pitchControl > MAX_USER_PITCH )
  178. {
  179. pitchControl = MAX_USER_PITCH; // clip to max
  180. }
  181. newPitch = (float)basePitch * g_PitchScale[pitchControl];
  182. }
  183. return newPitch;
  184. } /* CPitchProsody::DoPitchControl */
  185. /*****************************************************************************
  186. * CPitchProsody::SetDefaultPitch *
  187. *--------------------------------*
  188. * Description:
  189. * Init pitch knots to monotone in case there's a failure in this object.
  190. *
  191. ********************************************************************** MC ***/
  192. void CPitchProsody::SetDefaultPitch()
  193. {
  194. SPDBG_FUNC( "CPitchProsody::SetDefaultPitch" );
  195. CAlloCell *pCurCell;
  196. pCurCell = m_pAllos->GetHeadCell();
  197. while( pCurCell )
  198. {
  199. float relTime, timeK;
  200. float normalPitch;
  201. long knot;
  202. normalPitch = pCurCell->m_Pitch_LO + ((pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO) / 2);
  203. timeK = pCurCell->m_ftDuration / KNOTS_PER_PHON;
  204. relTime = 0;
  205. for( knot = 0; knot < KNOTS_PER_PHON; knot++ )
  206. {
  207. pCurCell->m_ftPitch[knot] = normalPitch;
  208. pCurCell->m_ftTime[knot] = relTime;
  209. relTime += timeK;
  210. }
  211. pCurCell = m_pAllos->GetNextCell();
  212. }
  213. } /* CPitchProsody::SetDefaultPitch */
  214. /*****************************************************************************
  215. * CPitchProsody::AlloPitch *
  216. *--------------------------*
  217. * Description:
  218. * Tag pitch highlights
  219. *
  220. ********************************************************************** MC ***/
  221. void CPitchProsody::AlloPitch( CAlloList *pAllos, int baseLine, int pitchRange )
  222. {
  223. SPDBG_FUNC( "CAlloOps::AlloPitch" );
  224. CAlloCell *pCurCell;
  225. bool skipInitialSil;
  226. long quantTotal, index;
  227. m_pAllos = pAllos;
  228. m_numOfCells = m_pAllos->GetCount();
  229. m_Tune_Style = DESCEND_TUNE; // NOTE: maybe set from rules
  230. m_TotalDur = 0;
  231. quantTotal = 0;
  232. m_OffsTime = 0;
  233. skipInitialSil = true;
  234. //------------------------------
  235. // Calculate total duration
  236. // (exclude surrounding silence)
  237. //------------------------------
  238. index = 0;
  239. pCurCell = m_pAllos->GetHeadCell();
  240. while( pCurCell )
  241. {
  242. if( (skipInitialSil) && (pCurCell->m_allo == _SIL_) )
  243. {
  244. //---------------------------------
  245. // Skip leading silence
  246. //---------------------------------
  247. m_OffsTime += pCurCell->m_ftDuration;
  248. }
  249. else if( (index == (m_numOfCells -1)) && (pCurCell->m_allo == _SIL_) )
  250. {
  251. //---------------------------------
  252. // Skip term silence
  253. //---------------------------------
  254. break;
  255. }
  256. else
  257. {
  258. pCurCell->m_PitchBufStart = quantTotal;
  259. m_TotalDur += pCurCell->m_ftDuration;
  260. quantTotal = (long)(m_TotalDur / PITCH_BUF_RES + 0.5);
  261. pCurCell->m_PitchBufEnd = quantTotal;
  262. skipInitialSil = false;
  263. }
  264. index++;
  265. pCurCell = pAllos->GetNextCell();
  266. }
  267. //------------------------------
  268. // Init pitch range
  269. //------------------------------
  270. pCurCell = m_pAllos->GetHeadCell();
  271. while( pCurCell )
  272. {
  273. float hzVal;
  274. //---------------------------------------
  275. // Scale to possible pitch control
  276. //---------------------------------------
  277. hzVal = DoPitchControl( pCurCell->m_user_Pitch, (float)baseLine );
  278. pCurCell->m_Pitch_HI = hzVal + ( pitchRange / 2 );
  279. pCurCell->m_Pitch_LO = hzVal - ( pitchRange / 2 );
  280. pCurCell = pAllos->GetNextCell();
  281. }
  282. //--------------------------------------------
  283. // In case we fail somewhere, set values to
  284. // a known valid state (monotone).
  285. //--------------------------------------------
  286. SetDefaultPitch();
  287. if( m_TotalDur > 0 )
  288. {
  289. //--------------------------------------------
  290. // Generate pitch targets
  291. //--------------------------------------------
  292. PitchTrack();
  293. }
  294. pCurCell = m_pAllos->GetHeadCell();
  295. while ( pCurCell )
  296. {
  297. for ( int i = pCurCell->m_PitchBufStart; i < pCurCell->m_PitchBufEnd; i++ )
  298. {
  299. if ( 0.0 < m_pContBuf[i] && m_pContBuf[i] < 1.0 )
  300. {
  301. m_pContBuf[i] = pCurCell->m_Pitch_LO +
  302. ( m_pContBuf[i] * ( pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO ) );
  303. }
  304. }
  305. pCurCell = m_pAllos->GetNextCell();
  306. }
  307. } /* CPitchProsody::AlloPitch */
  308. /*****************************************************************************
  309. * LineInterpContour *
  310. *--------------------*
  311. * Description:
  312. * Does linear interpolation over the pitch contour
  313. *
  314. ********************************************************************** MC ***/
  315. void LineInterpContour( long cNumOfPoints, float *pPoints )
  316. {
  317. SPDBG_FUNC( "LineInterpContour" );
  318. long endAnch,startAnch, i;
  319. float bPoint1, ePoint1;
  320. //----------------------------------------------------
  321. // Scan forward from beginning to find 1st non-zero enrty
  322. // Use it as the START point.
  323. //----------------------------------------------------
  324. for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ )
  325. {
  326. if( pPoints[startAnch] != 0 )
  327. {
  328. break;
  329. }
  330. }
  331. bPoint1 = pPoints[startAnch];
  332. //----------------------------------------------------
  333. // Scan back from end to find 1st non-zero enrty
  334. // Use it as the END point.
  335. //----------------------------------------------------
  336. for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- )
  337. {
  338. if( pPoints[endAnch] != 0 )
  339. {
  340. break;
  341. }
  342. }
  343. ePoint1 = pPoints[endAnch];
  344. long firstp = 0;
  345. long lastp = 0;
  346. while( firstp < cNumOfPoints )
  347. {
  348. //-------------------------------------------
  349. // Find beginning and end of current section
  350. //-------------------------------------------
  351. while( pPoints[firstp] != 0 )
  352. {
  353. if( ++firstp >= cNumOfPoints-1 )
  354. {
  355. break;
  356. }
  357. }
  358. if( firstp >= cNumOfPoints-1 )
  359. {
  360. //--------------------------------------
  361. // There's nothing to interpolate!
  362. //--------------------------------------
  363. break;
  364. }
  365. lastp = firstp+1;
  366. while( pPoints[lastp] == 0 )
  367. {
  368. if( ++lastp >= cNumOfPoints )
  369. {
  370. lastp = cNumOfPoints;
  371. break;
  372. }
  373. }
  374. lastp--;
  375. if( lastp >= firstp )
  376. {
  377. if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) )
  378. {
  379. break;
  380. }
  381. //-------------------------------------------
  382. // Do the interpolate
  383. //-------------------------------------------
  384. float bPoint,ePoint;
  385. if( firstp == 0 )
  386. {
  387. bPoint = bPoint1;
  388. }
  389. else
  390. {
  391. bPoint = pPoints[firstp - 1];
  392. }
  393. if( lastp == cNumOfPoints-1 )
  394. {
  395. ePoint = ePoint1;
  396. }
  397. else
  398. {
  399. ePoint = pPoints[lastp + 1];
  400. }
  401. float pointSpread = ePoint - bPoint;
  402. float timeSpread = (float) ((lastp - firstp)+2);
  403. float inc = pointSpread / timeSpread;
  404. float theBase = bPoint;
  405. for( i = firstp; i <= lastp; i++ )
  406. {
  407. theBase += inc;
  408. pPoints[i] = theBase;
  409. }
  410. }
  411. else
  412. {
  413. pPoints[firstp] = pPoints[lastp+1];
  414. }
  415. firstp = lastp+1;
  416. }
  417. } /* LineInterpContour */
  418. /*****************************************************************************
  419. * Interpolate2 *
  420. *---------------*
  421. * Description:
  422. * Do a 2nd order interpolation, a little nicer than just linear
  423. *
  424. ********************************************************************** MC ***/
  425. void Interpolate2( INTERP_DIR direction, float *m_theFitPoints, long theStart, long len, float theAmp, float theBase)
  426. {
  427. SPDBG_FUNC( "Interpolate2" );
  428. long midPoint = len / 2;
  429. long i;
  430. theAmp -= theBase;
  431. for( i = theStart; i < theStart + len;i++ )
  432. {
  433. if (direction == GOING_UP)
  434. {
  435. if( i < theStart + midPoint )
  436. {
  437. m_theFitPoints[i] = theBase +
  438. (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) *
  439. (((float)i - (float)theStart) / (float)len));
  440. }
  441. else
  442. {
  443. m_theFitPoints[i] = (theBase + theAmp) -
  444. ((2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) *
  445. (1 - ((float)i - (float)theStart) / (float)len)));
  446. }
  447. }
  448. else if( direction == GOING_DOWN )
  449. {
  450. if( i < theStart + midPoint )
  451. {
  452. m_theFitPoints[i] = theBase +
  453. theAmp - (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) *
  454. (((float)i - (float)theStart) / (float)len));
  455. }
  456. else
  457. {
  458. m_theFitPoints[i] = theBase +
  459. (2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) *
  460. (1 - ((float)i - (float)theStart) / (float)len));
  461. }
  462. }
  463. }
  464. } /* Interpolate2 */
  465. /*****************************************************************************
  466. * SecondOrderInterp *
  467. *--------------------*
  468. * Description:
  469. * Does 2nd order interpolation over the pitch contour
  470. *
  471. ********************************************************************** MC ***/
  472. void SecondOrderInterp( long cNumOfPoints, float *pPoints )
  473. {
  474. SPDBG_FUNC( "SecondOrderInterp" );
  475. long endAnch,startAnch;
  476. float bPoint1, ePoint1;
  477. //----------------------------------------------------
  478. // Scan forward from beginning to find 1st non-zero enrty
  479. // Use it as the START point.
  480. //----------------------------------------------------
  481. for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ )
  482. {
  483. if( pPoints[startAnch] != 0 )
  484. {
  485. break;
  486. }
  487. }
  488. bPoint1 = pPoints[startAnch];
  489. //----------------------------------------------------
  490. // Scan back from end to find 1st non-zero enrty
  491. // Use it as the END point.
  492. //----------------------------------------------------
  493. for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- )
  494. {
  495. if( pPoints[endAnch] != 0 )
  496. {
  497. break;
  498. }
  499. }
  500. ePoint1 = pPoints[endAnch];
  501. long firstp = 0;
  502. long lastp = 0;
  503. while( firstp < cNumOfPoints-1 )
  504. {
  505. //------------------------------------------------
  506. // Find beginning and end of current section
  507. //------------------------------------------------
  508. while( pPoints[firstp] != 0 )
  509. {
  510. if( ++firstp >= cNumOfPoints-1 )
  511. {
  512. break;
  513. }
  514. }
  515. if( firstp >= cNumOfPoints-1 )
  516. {
  517. //--------------------------------------
  518. // There's nothing to interpolate!
  519. //--------------------------------------
  520. break;
  521. }
  522. lastp = firstp + 1;
  523. while( pPoints[lastp] == 0 )
  524. {
  525. if( ++lastp >= cNumOfPoints )
  526. {
  527. lastp = cNumOfPoints;
  528. break;
  529. }
  530. }
  531. lastp--;
  532. if( lastp >= firstp )
  533. {
  534. if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) )
  535. {
  536. break;
  537. }
  538. //--------------------------------
  539. // Do the interpolate
  540. //--------------------------------
  541. float bPoint, ePoint;
  542. if( firstp == 0 )
  543. {
  544. bPoint = bPoint1;
  545. }
  546. else
  547. {
  548. bPoint = pPoints[firstp - 1];
  549. }
  550. long theIndex = lastp + 1;
  551. if( lastp == cNumOfPoints-1 )
  552. {
  553. ePoint = ePoint1;
  554. }
  555. else
  556. {
  557. ePoint = pPoints[theIndex];
  558. }
  559. //--------------------------------
  560. // call the 2nd order routine
  561. //--------------------------------
  562. if( ePoint - bPoint > 0 )
  563. {
  564. Interpolate2( GOING_UP, pPoints, firstp, (lastp - firstp) + 1, ePoint, bPoint );
  565. }
  566. else
  567. {
  568. Interpolate2( GOING_DOWN, pPoints, firstp, (lastp - firstp) + 1, bPoint, ePoint );
  569. }
  570. }
  571. else
  572. {
  573. pPoints[firstp] = pPoints[lastp+1];
  574. }
  575. firstp = lastp+1;
  576. }
  577. //---------------------------------
  578. // FIR Filter
  579. //---------------------------------
  580. /*CFIRFilter filterObj;
  581. float *pOrig;
  582. pOrig = new float[cNumOfPoints];
  583. memcpy( pOrig, pPoints, cNumOfPoints * sizeof(float));
  584. if( pOrig )
  585. {
  586. filterObj.Make_Filter( 5, // Freq
  587. 10, // order
  588. 100 // SR
  589. );
  590. filterObj.DoFilter( pOrig, pPoints, cNumOfPoints);
  591. delete pOrig;
  592. }*/
  593. //---------------------------------
  594. // IIR Filter
  595. //---------------------------------
  596. #define kPointDelay 1
  597. float filter_Out1, filter_In_Gain, filter_FB_Gain;
  598. float lastPoint;
  599. long i;
  600. //--------------------------------------------------
  601. // Skip filter if audio len less than delay
  602. //--------------------------------------------------
  603. if( cNumOfPoints > kPointDelay )
  604. {
  605. filter_In_Gain = 0.10f;
  606. filter_FB_Gain = 1.0f - filter_In_Gain;
  607. filter_Out1 = pPoints[0];
  608. for( i = 0; i < cNumOfPoints; i++ )
  609. {
  610. filter_Out1 = (filter_In_Gain * pPoints[i]) + (filter_FB_Gain * filter_Out1);
  611. pPoints[i] = filter_Out1;
  612. }
  613. for( i = kPointDelay; i < cNumOfPoints; i++ )
  614. {
  615. pPoints[i-kPointDelay] = pPoints[i];
  616. }
  617. i = (cNumOfPoints - kPointDelay) -1;
  618. lastPoint = pPoints[i++];
  619. for( ; i < cNumOfPoints; i++ )
  620. {
  621. pPoints[i] = lastPoint;
  622. }
  623. }
  624. } /* SecondOrderInterp */
  625. /*****************************************************************************
  626. * CPitchProsody::NewTarget *
  627. *---------------------------*
  628. * Description:
  629. * Insert pitch target into 'm_pContBuf'
  630. *
  631. ********************************************************************** MC ***/
  632. void CPitchProsody::NewTarget( long index, float value )
  633. {
  634. SPDBG_FUNC( "CPitchProsody::NewTarget" );
  635. m_pContBuf[index] = value;
  636. //--- Debug Macro - add pitch to target list for later debugging output
  637. TTSDBG_ADDPITCHTARGET( m_OffsTime + (PITCH_BUF_RES * index), value, m_CurAccent );
  638. } /* CPitchProsody::NewTarget */
  639. /*****************************************************************************
  640. * CPitchProsody::GetKnots *
  641. *-------------------------*
  642. * Description:
  643. * Assign pitch knots based on entries in a contour buffer.
  644. *
  645. ********************************************************************** MC ***/
  646. void CPitchProsody::GetKnots ()
  647. {
  648. SPDBG_FUNC( "CPitchProsody::GetKnots" );
  649. CAlloCell *pCurCell;
  650. float distK, scale;
  651. float pitchRange;
  652. long knot, loc, index;
  653. bool skipInitialSil;
  654. skipInitialSil = true;
  655. pCurCell = m_pAllos->GetHeadCell();
  656. index = 0;
  657. while( pCurCell )
  658. {
  659. if( index >= m_numOfCells-1 )
  660. {
  661. //-----------------------
  662. // Skip last allo
  663. //-----------------------
  664. break;
  665. }
  666. if( (!skipInitialSil) || (pCurCell->m_allo != _SIL_) )
  667. {
  668. pitchRange = pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO;
  669. distK = 1.0f / KNOTS_PER_PHON;
  670. scale = 0;
  671. for( knot = 0; knot < KNOTS_PER_PHON; knot++ )
  672. {
  673. loc = pCurCell->m_PitchBufStart + (long)((pCurCell->m_PitchBufEnd - pCurCell->m_PitchBufStart) * scale);
  674. pCurCell->m_ftPitch[knot] = pCurCell->m_Pitch_LO + (m_pContBuf[loc] * pitchRange);
  675. pCurCell->m_ftTime[knot] = scale * pCurCell->m_ftDuration;
  676. scale += distK;
  677. }
  678. skipInitialSil = false;
  679. }
  680. pCurCell = m_pAllos->GetNextCell();
  681. index++;
  682. }
  683. } /* CPitchProsody::GetKnots */
  684. /*****************************************************************************
  685. * CPitchProsody::PitchTrack *
  686. *----------------------------*
  687. * Description:
  688. * Tag pitch highlights
  689. *
  690. ********************************************************************** MC ***/
  691. void CPitchProsody::PitchTrack()
  692. {
  693. SPDBG_FUNC( "CPitchProsody::PitchTrack" );
  694. long i;
  695. CAlloCell *pCurCell, *pNextCell;
  696. bool initialWord; // 1st word in phrase
  697. long wordCntDwn;
  698. float curProm; // Current accent prominence
  699. long cNumOfPoints;
  700. float *pRefBuf, *pCeilBuf, *pFloorBuf;
  701. float lastProm;
  702. long loc;
  703. float value;
  704. pRefBuf = pCeilBuf = pFloorBuf = NULL;
  705. cNumOfPoints = (long)(m_TotalDur / PITCH_BUF_RES + 0.5);
  706. pRefBuf = new float[cNumOfPoints];
  707. pCeilBuf = new float[cNumOfPoints];
  708. pFloorBuf = new float[cNumOfPoints];
  709. if ( m_pContBuf )
  710. {
  711. delete m_pContBuf;
  712. m_pContBuf = NULL;
  713. }
  714. m_pContBuf = new float[cNumOfPoints];
  715. m_ulNumPoints = cNumOfPoints;
  716. if( pRefBuf && pCeilBuf && pFloorBuf && m_pContBuf)
  717. {
  718. //--------------------------------------------
  719. // Initialize buffers to zero
  720. //--------------------------------------------
  721. for (i = 0; i < cNumOfPoints; i++)
  722. {
  723. pCeilBuf[i] = 0;
  724. pFloorBuf[i] = 0.00001f;
  725. pRefBuf[i] = 0;
  726. m_pContBuf[i] = 0;
  727. }
  728. //--------------------------------------------
  729. // Linear CEILING slope
  730. //--------------------------------------------
  731. if( m_Tune_Style == DESCEND_TUNE )
  732. {
  733. pCeilBuf[0] = 1.0;
  734. pCeilBuf[cNumOfPoints-1] = 0.70f;
  735. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  736. }
  737. else if (m_Tune_Style == ASCEND_TUNE)
  738. {
  739. pCeilBuf[0] = 0.9f;
  740. pCeilBuf[cNumOfPoints-1] = 1.0f;
  741. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  742. }
  743. else if (m_Tune_Style == FLAT_TUNE)
  744. {
  745. pCeilBuf[0] = 1.0f;
  746. pCeilBuf[cNumOfPoints-1] = 1.0f;
  747. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  748. }
  749. //--------------------------------------------
  750. // Linear REFERENCE slope
  751. //--------------------------------------------
  752. pRefBuf[0] = (float) (pFloorBuf[0] + (pCeilBuf[0] - pFloorBuf[0]) * 0.33f);
  753. pRefBuf[cNumOfPoints-1] = (float) (pFloorBuf[0] + (pCeilBuf[cNumOfPoints-1] - pFloorBuf[cNumOfPoints-1]) * 0.33f);
  754. ::LineInterpContour( cNumOfPoints,pRefBuf );
  755. //--------------------------------------------
  756. // Final contour buffer
  757. //--------------------------------------------
  758. m_pContBuf[0] = pRefBuf[0];
  759. m_pContBuf[cNumOfPoints-1] = 0.0001f; // Something very small
  760. long iPrevBegin, iPrevEnd, iCurBegin;
  761. long iCurEnd, iNextBegin, iNextEnd;
  762. float cCurLen;
  763. long iCellindex;
  764. initialWord = true;
  765. iCellindex = 0;
  766. pCurCell = m_pAllos->GetHeadCell();
  767. while( pCurCell->m_allo == _SIL_ )
  768. {
  769. //---------------------------------
  770. // Skip leading silence
  771. //---------------------------------
  772. pCurCell = m_pAllos->GetNextCell();
  773. iCellindex++;
  774. }
  775. wordCntDwn = 1; // Skip 1st word
  776. lastProm = 0;
  777. iPrevBegin = iPrevEnd = 0;
  778. pNextCell = m_pAllos->GetNextCell();
  779. while( pCurCell )
  780. {
  781. if( iCellindex >= m_numOfCells-1 )
  782. {
  783. //-----------------------
  784. // Skip last allo
  785. //-----------------------
  786. break;
  787. }
  788. //-----------------------------------
  789. // Get CURRENT allo
  790. //-----------------------------------
  791. iCurBegin = pCurCell->m_PitchBufStart;
  792. iCurEnd = pCurCell->m_PitchBufEnd;
  793. cCurLen = (float)(iCurEnd - iCurBegin);
  794. curProm = pCurCell->m_Accent_Prom * (float)0.1;
  795. //-----------------------------------
  796. // Get NEXT allo
  797. //-----------------------------------
  798. iNextBegin = pNextCell->m_PitchBufStart;
  799. iNextEnd = pNextCell->m_PitchBufEnd;
  800. m_CurAccent = pCurCell->m_ToBI_Accent;
  801. //---------------------
  802. // Diagnostic
  803. //---------------------
  804. m_CurAccentSource = pCurCell->m_AccentSource;
  805. m_CurBoundarySource = pCurCell->m_BoundarySource;
  806. m_pCurTextStr = pCurCell->m_pTextStr;
  807. switch( pCurCell->m_ToBI_Accent )
  808. {
  809. case K_RSTAR:
  810. break;
  811. case K_HSTAR:
  812. {
  813. if( !initialWord ) // We never add a 'leg' to a phrase-initial word
  814. {
  815. //----------------------------------------------
  816. // Add a L leg to start to previous allo
  817. //----------------------------------------------
  818. if( iPrevBegin )
  819. {
  820. loc = (long) ((iCurBegin + (cCurLen * 0.1f)));
  821. value = ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  822. value = pRefBuf[loc] + (value * 0.25f); // L+H*
  823. NewTarget( iPrevBegin, value );
  824. //NewTarget( loc, value );
  825. }
  826. }
  827. //----------------------------------------------
  828. // Now plug in the H target
  829. //
  830. // If we're at a boundary, insert H at
  831. // allo mid-point else insert at allo start
  832. //----------------------------------------------
  833. if( pCurCell->m_ToBI_Boundary != K_NOBND )
  834. {
  835. //---------------------------
  836. // Insert H* at allo start
  837. //---------------------------
  838. loc = (long) iCurBegin;
  839. }
  840. else
  841. {
  842. //---------------------------
  843. // Insert H* at allo mid-point
  844. //---------------------------
  845. loc = (long) (iCurBegin + (cCurLen * K_HSTAR_OFFSET));
  846. }
  847. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  848. NewTarget( loc, value );
  849. }
  850. break;
  851. case K_LSTAR:
  852. {
  853. //------------------------------------
  854. // Insert L* at mid-point
  855. //------------------------------------
  856. loc = (long) (iCurBegin + (cCurLen * 0.3f));
  857. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
  858. NewTarget( loc, value );
  859. }
  860. break;
  861. case K_LSTARH:
  862. {
  863. //----------------------------------------------
  864. // Insert L* at current start
  865. //----------------------------------------------
  866. value = pRefBuf[iCurBegin] - ((pRefBuf[iCurBegin] - pFloorBuf[iCurBegin]) * curProm); // L*+H
  867. NewTarget( iCurBegin, value );
  868. if( iNextBegin )
  869. {
  870. //----------------------------------------------
  871. // Insert H at next end
  872. // set prom gain?
  873. //----------------------------------------------
  874. value = pRefBuf[iNextEnd] - ((pRefBuf[iNextEnd] - pFloorBuf[iNextEnd]) * (curProm /* * .3 */ ));
  875. NewTarget( iNextEnd, value );
  876. }
  877. lastProm = 0;
  878. }
  879. break;
  880. case K_LHSTAR:
  881. {
  882. loc = (long) (iCurBegin + (cCurLen * 0.3f));
  883. if( iPrevBegin )
  884. {
  885. //----------------------------------------------
  886. // Insert L at previous start
  887. //----------------------------------------------
  888. value = (pRefBuf[iPrevBegin] - ((pRefBuf[iPrevBegin] - pFloorBuf[iPrevBegin]) * (curProm * 0.3f))); // L+H*
  889. NewTarget( iPrevBegin, value );
  890. }
  891. //----------------------------------------------
  892. // Insert H* at current mid-point
  893. //----------------------------------------------
  894. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  895. NewTarget( loc, value );
  896. lastProm = curProm;
  897. }
  898. break;
  899. case K_HSTARLSTAR:
  900. {
  901. //value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H*
  902. value = pRefBuf[0] + ((pCeilBuf[0] - pRefBuf[0]) * curProm); // H*
  903. NewTarget( iCurBegin, value );
  904. loc = (long) (iCurBegin + (cCurLen * 0.75f));
  905. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
  906. NewTarget( loc, value );
  907. lastProm = curProm;
  908. }
  909. break;
  910. case K_DHSTAR:
  911. {
  912. loc = (long) ( iCurBegin + (cCurLen * 0.0f) );
  913. if( lastProm )
  914. {
  915. lastProm *= K_HDOWNSTEP_COEFF;
  916. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * lastProm); // !H*
  917. NewTarget( loc, value );
  918. }
  919. //-----------------------------------------
  920. // no previous H*, treat !H* like an H*
  921. //-----------------------------------------
  922. else
  923. {
  924. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  925. NewTarget( loc, value );
  926. lastProm = curProm;
  927. }
  928. }
  929. break;
  930. default: // Unknown accent specfied
  931. break;
  932. }
  933. //-------------------------------------------------------------
  934. // if there's a boundary, fill in pitch value(s)
  935. // assume the boundary is set to correct (voiced) final phone
  936. //-------------------------------------------------------------
  937. curProm = pCurCell->m_Boundary_Prom * (float)0.1;
  938. m_CurAccent =(TOBI_ACCENT) pCurCell->m_ToBI_Boundary;
  939. //---------------------
  940. // Diagnostic
  941. //---------------------
  942. m_CurAccentSource = pCurCell->m_AccentSource;
  943. m_CurBoundarySource = pCurCell->m_BoundarySource;
  944. m_pCurTextStr = pCurCell->m_pTextStr;
  945. switch( pCurCell->m_ToBI_Boundary )
  946. {
  947. case K_LMINUS:
  948. {
  949. value = pRefBuf[iCurEnd] - ((pRefBuf[iCurEnd] - pFloorBuf[iCurEnd]) * curProm); // L-
  950. NewTarget( iCurEnd, value );
  951. }
  952. break;
  953. case K_HMINUS:
  954. {
  955. value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H-
  956. NewTarget( iCurEnd, value );
  957. }
  958. break;
  959. //case K_LPERC:
  960. //case K_HPERC:
  961. case K_LMINUSLPERC:
  962. {
  963. value = pFloorBuf[iCurEnd];
  964. //NewTarget( iCurEnd, value );
  965. NewTarget( iCurBegin, value );
  966. }
  967. break;
  968. case K_HMINUSHPERC:
  969. {
  970. value = pCeilBuf[iCurEnd];
  971. NewTarget( iCurEnd, value );
  972. }
  973. break;
  974. case K_LMINUSHPERC: // L-H%
  975. {
  976. //---------------------------------------
  977. // comma continuation rise
  978. //---------------------------------------
  979. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  980. // L starts at middle of previous phon
  981. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  982. loc = iPrevBegin + (iPrevEnd - iPrevBegin) / 2;
  983. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L-
  984. NewTarget( loc, value );
  985. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  986. // H at end of current phon
  987. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  988. value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H%
  989. NewTarget( iCurEnd, value );
  990. }
  991. break;
  992. case K_HMINUSLPERC:
  993. {
  994. //---------------------------------------
  995. // accent extension followed by sharp drop
  996. //---------------------------------------
  997. value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H-
  998. NewTarget( iCurBegin, value );
  999. value = pFloorBuf[iCurEnd]; // L%
  1000. //loc = iCurBegin + ((iCurEnd - iCurBegin) * 0.1f);
  1001. NewTarget( iCurEnd, value );
  1002. }
  1003. break;
  1004. default:
  1005. break;
  1006. }
  1007. //----------------------------
  1008. // Unflag initial word
  1009. //----------------------------
  1010. if( (initialWord) && (pCurCell->m_ctrlFlags & WORD_START) )
  1011. {
  1012. wordCntDwn--;
  1013. if( wordCntDwn < 0 )
  1014. {
  1015. initialWord = false;
  1016. }
  1017. }
  1018. //----------------------------
  1019. // Setup for next allo
  1020. //----------------------------
  1021. iPrevBegin = iCurBegin;
  1022. iPrevEnd = iCurEnd;
  1023. pCurCell = pNextCell;
  1024. pNextCell = m_pAllos->GetNextCell();
  1025. iCellindex++;
  1026. }
  1027. //--- Debug Macro - Log pitch data to stream
  1028. TTSDBG_LOGTOBI;
  1029. ::SecondOrderInterp( cNumOfPoints, m_pContBuf );
  1030. GetKnots();
  1031. }
  1032. if( pRefBuf )
  1033. {
  1034. delete pRefBuf;
  1035. }
  1036. if( pCeilBuf )
  1037. {
  1038. delete pCeilBuf;
  1039. }
  1040. if( pFloorBuf )
  1041. {
  1042. delete pFloorBuf;
  1043. }
  1044. } /* CPitchProsody::PitchTrack */
  1045. void CPitchProsody::GetContour( float** ppf0, ULONG *ulNumf0 )
  1046. {
  1047. *ppf0 = new float[ m_ulNumPoints ];
  1048. float *Array = *ppf0;
  1049. for ( ULONG i = 0; i < m_ulNumPoints; i++ )
  1050. {
  1051. Array[i] = m_pContBuf[i];
  1052. }
  1053. *ulNumf0 = m_ulNumPoints;
  1054. }