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.

1210 lines
35 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, float baseLine, float 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);
  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, pitchK, rangeTemp;
  274. //---------------------------------------
  275. // Scale to possible pitch control
  276. //---------------------------------------
  277. rangeTemp = pitchRange * pCurCell->m_PitchRangeScale;
  278. hzVal = DoPitchControl( pCurCell->m_user_Pitch, baseLine );
  279. pitchK = HzToOct( hzVal ) + pCurCell->m_PitchBaseOffs;
  280. pCurCell->m_Pitch_HI = OctToHz( pitchK + rangeTemp );
  281. pCurCell->m_Pitch_LO = OctToHz( pitchK - rangeTemp );
  282. pCurCell = pAllos->GetNextCell();
  283. }
  284. //--------------------------------------------
  285. // In case we fail somewhere, set values to
  286. // a known valid state (monotone).
  287. //--------------------------------------------
  288. SetDefaultPitch();
  289. if( m_TotalDur > 0 )
  290. {
  291. //--------------------------------------------
  292. // Generate pitch targets
  293. //--------------------------------------------
  294. PitchTrack();
  295. }
  296. } /* CPitchProsody::AlloPitch */
  297. /*****************************************************************************
  298. * LineInterpContour *
  299. *--------------------*
  300. * Description:
  301. * Does linear interpolation over the pitch contour
  302. *
  303. ********************************************************************** MC ***/
  304. void LineInterpContour( long cNumOfPoints, float *pPoints )
  305. {
  306. SPDBG_FUNC( "LineInterpContour" );
  307. long endAnch,startAnch, i;
  308. float bPoint1, ePoint1;
  309. //----------------------------------------------------
  310. // Scan forward from beginning to find 1st non-zero enrty
  311. // Use it as the START point.
  312. //----------------------------------------------------
  313. for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ )
  314. {
  315. if( pPoints[startAnch] != 0 )
  316. {
  317. break;
  318. }
  319. }
  320. bPoint1 = pPoints[startAnch];
  321. //----------------------------------------------------
  322. // Scan back from end to find 1st non-zero enrty
  323. // Use it as the END point.
  324. //----------------------------------------------------
  325. for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- )
  326. {
  327. if( pPoints[endAnch] != 0 )
  328. {
  329. break;
  330. }
  331. }
  332. ePoint1 = pPoints[endAnch];
  333. long firstp = 0;
  334. long lastp = 0;
  335. while( firstp < cNumOfPoints )
  336. {
  337. //-------------------------------------------
  338. // Find beginning and end of current section
  339. //-------------------------------------------
  340. while( pPoints[firstp] != 0 )
  341. {
  342. if( ++firstp >= cNumOfPoints-1 )
  343. {
  344. break;
  345. }
  346. }
  347. if( firstp >= cNumOfPoints-1 )
  348. {
  349. //--------------------------------------
  350. // There's nothing to interpolate!
  351. //--------------------------------------
  352. break;
  353. }
  354. lastp = firstp+1;
  355. while( pPoints[lastp] == 0 )
  356. {
  357. if( ++lastp >= cNumOfPoints )
  358. {
  359. lastp = cNumOfPoints;
  360. break;
  361. }
  362. }
  363. lastp--;
  364. if( lastp >= firstp )
  365. {
  366. if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) )
  367. {
  368. break;
  369. }
  370. //-------------------------------------------
  371. // Do the interpolate
  372. //-------------------------------------------
  373. float bPoint,ePoint;
  374. if( firstp == 0 )
  375. {
  376. bPoint = bPoint1;
  377. }
  378. else
  379. {
  380. bPoint = pPoints[firstp - 1];
  381. }
  382. if( lastp == cNumOfPoints-1 )
  383. {
  384. ePoint = ePoint1;
  385. }
  386. else
  387. {
  388. ePoint = pPoints[lastp + 1];
  389. }
  390. float pointSpread = ePoint - bPoint;
  391. float timeSpread = (float) ((lastp - firstp)+2);
  392. float inc = pointSpread / timeSpread;
  393. float theBase = bPoint;
  394. for( i = firstp; i <= lastp; i++ )
  395. {
  396. theBase += inc;
  397. pPoints[i] = theBase;
  398. }
  399. }
  400. else
  401. {
  402. pPoints[firstp] = pPoints[lastp+1];
  403. }
  404. firstp = lastp+1;
  405. }
  406. } /* LineInterpContour */
  407. /*****************************************************************************
  408. * Interpolate2 *
  409. *---------------*
  410. * Description:
  411. * Do a 2nd order interpolation, a little nicer than just linear
  412. *
  413. ********************************************************************** MC ***/
  414. void Interpolate2( INTERP_DIR direction, float *m_theFitPoints, long theStart, long len, float theAmp, float theBase)
  415. {
  416. SPDBG_FUNC( "Interpolate2" );
  417. long midPoint = len / 2;
  418. long i;
  419. theAmp -= theBase;
  420. for( i = theStart; i < theStart + len;i++ )
  421. {
  422. if (direction == GOING_UP)
  423. {
  424. if( i < theStart + midPoint )
  425. {
  426. m_theFitPoints[i] = theBase +
  427. (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) *
  428. (((float)i - (float)theStart) / (float)len));
  429. }
  430. else
  431. {
  432. m_theFitPoints[i] = (theBase + theAmp) -
  433. ((2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) *
  434. (1 - ((float)i - (float)theStart) / (float)len)));
  435. }
  436. }
  437. else if( direction == GOING_DOWN )
  438. {
  439. if( i < theStart + midPoint )
  440. {
  441. m_theFitPoints[i] = theBase +
  442. theAmp - (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) *
  443. (((float)i - (float)theStart) / (float)len));
  444. }
  445. else
  446. {
  447. m_theFitPoints[i] = theBase +
  448. (2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) *
  449. (1 - ((float)i - (float)theStart) / (float)len));
  450. }
  451. }
  452. }
  453. } /* Interpolate2 */
  454. /*****************************************************************************
  455. * SecondOrderInterp *
  456. *--------------------*
  457. * Description:
  458. * Does 2nd order interpolation over the pitch contour
  459. *
  460. ********************************************************************** MC ***/
  461. void SecondOrderInterp( long cNumOfPoints, float *pPoints )
  462. {
  463. SPDBG_FUNC( "SecondOrderInterp" );
  464. long endAnch,startAnch;
  465. float bPoint1, ePoint1;
  466. //----------------------------------------------------
  467. // Scan forward from beginning to find 1st non-zero enrty
  468. // Use it as the START point.
  469. //----------------------------------------------------
  470. for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ )
  471. {
  472. if( pPoints[startAnch] != 0 )
  473. {
  474. break;
  475. }
  476. }
  477. bPoint1 = pPoints[startAnch];
  478. //----------------------------------------------------
  479. // Scan back from end to find 1st non-zero enrty
  480. // Use it as the END point.
  481. //----------------------------------------------------
  482. for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- )
  483. {
  484. if( pPoints[endAnch] != 0 )
  485. {
  486. break;
  487. }
  488. }
  489. ePoint1 = pPoints[endAnch];
  490. long firstp = 0;
  491. long lastp = 0;
  492. while( firstp < cNumOfPoints-1 )
  493. {
  494. //------------------------------------------------
  495. // Find beginning and end of current section
  496. //------------------------------------------------
  497. while( pPoints[firstp] != 0 )
  498. {
  499. if( ++firstp >= cNumOfPoints-1 )
  500. {
  501. break;
  502. }
  503. }
  504. if( firstp >= cNumOfPoints-1 )
  505. {
  506. //--------------------------------------
  507. // There's nothing to interpolate!
  508. //--------------------------------------
  509. break;
  510. }
  511. lastp = firstp + 1;
  512. while( pPoints[lastp] == 0 )
  513. {
  514. if( ++lastp >= cNumOfPoints )
  515. {
  516. lastp = cNumOfPoints;
  517. break;
  518. }
  519. }
  520. lastp--;
  521. if( lastp >= firstp )
  522. {
  523. if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) )
  524. {
  525. break;
  526. }
  527. //--------------------------------
  528. // Do the interpolate
  529. //--------------------------------
  530. float bPoint, ePoint;
  531. if( firstp == 0 )
  532. {
  533. bPoint = bPoint1;
  534. }
  535. else
  536. {
  537. bPoint = pPoints[firstp - 1];
  538. }
  539. long theIndex = lastp + 1;
  540. if( lastp == cNumOfPoints-1 )
  541. {
  542. ePoint = ePoint1;
  543. }
  544. else
  545. {
  546. ePoint = pPoints[theIndex];
  547. }
  548. //--------------------------------
  549. // call the 2nd order routine
  550. //--------------------------------
  551. if( ePoint - bPoint > 0 )
  552. {
  553. Interpolate2( GOING_UP, pPoints, firstp, (lastp - firstp) + 1, ePoint, bPoint );
  554. }
  555. else
  556. {
  557. Interpolate2( GOING_DOWN, pPoints, firstp, (lastp - firstp) + 1, bPoint, ePoint );
  558. }
  559. }
  560. else
  561. {
  562. pPoints[firstp] = pPoints[lastp+1];
  563. }
  564. firstp = lastp+1;
  565. }
  566. //---------------------------------
  567. // FIR Filter
  568. //---------------------------------
  569. /*CFIRFilter filterObj;
  570. float *pOrig;
  571. pOrig = new float[cNumOfPoints];
  572. memcpy( pOrig, pPoints, cNumOfPoints * sizeof(float));
  573. if( pOrig )
  574. {
  575. filterObj.Make_Filter( 5, // Freq
  576. 10, // order
  577. 100 // SR
  578. );
  579. filterObj.DoFilter( pOrig, pPoints, cNumOfPoints);
  580. delete pOrig;
  581. }*/
  582. //---------------------------------
  583. // IIR Filter
  584. //---------------------------------
  585. #define kPointDelay 1
  586. float filter_Out1, filter_In_Gain, filter_FB_Gain;
  587. float lastPoint;
  588. long i;
  589. //--------------------------------------------------
  590. // Skip filter if audio len less than delay
  591. //--------------------------------------------------
  592. if( cNumOfPoints > kPointDelay )
  593. {
  594. filter_In_Gain = 0.10f;
  595. filter_FB_Gain = 1.0f - filter_In_Gain;
  596. filter_Out1 = pPoints[0];
  597. for( i = 0; i < cNumOfPoints; i++ )
  598. {
  599. filter_Out1 = (filter_In_Gain * pPoints[i]) + (filter_FB_Gain * filter_Out1);
  600. pPoints[i] = filter_Out1;
  601. }
  602. for( i = kPointDelay; i < cNumOfPoints; i++ )
  603. {
  604. pPoints[i-kPointDelay] = pPoints[i];
  605. }
  606. i = (cNumOfPoints - kPointDelay) -1;
  607. lastPoint = pPoints[i++];
  608. for( ; i < cNumOfPoints; i++ )
  609. {
  610. pPoints[i] = lastPoint;
  611. }
  612. }
  613. } /* SecondOrderInterp */
  614. /*****************************************************************************
  615. * CPitchProsody::NewTarget *
  616. *---------------------------*
  617. * Description:
  618. * Insert pitch target into 'm_pContBuf'
  619. *
  620. ********************************************************************** MC ***/
  621. void CPitchProsody::NewTarget( long index, float value )
  622. {
  623. SPDBG_FUNC( "CPitchProsody::NewTarget" );
  624. m_pContBuf[index] = value;
  625. //--- Debug Macro - add pitch to target list for later debugging output
  626. TTSDBG_ADDPITCHTARGET( m_OffsTime + (PITCH_BUF_RES * index), value, m_CurAccent );
  627. } /* CPitchProsody::NewTarget */
  628. /*****************************************************************************
  629. * CPitchProsody::GetKnots *
  630. *-------------------------*
  631. * Description:
  632. * Assign pitch knots based on entries in a contour buffer.
  633. *
  634. ********************************************************************** MC ***/
  635. void CPitchProsody::GetKnots ()
  636. {
  637. SPDBG_FUNC( "CPitchProsody::GetKnots" );
  638. CAlloCell *pCurCell;
  639. float distK, scale;
  640. float pitchRange;
  641. long knot, loc, index;
  642. bool skipInitialSil;
  643. skipInitialSil = true;
  644. pCurCell = m_pAllos->GetHeadCell();
  645. index = 0;
  646. while( pCurCell )
  647. {
  648. if( index >= m_numOfCells-1 )
  649. {
  650. //-----------------------
  651. // Skip last allo
  652. //-----------------------
  653. break;
  654. }
  655. if( (!skipInitialSil) || (pCurCell->m_allo != _SIL_) )
  656. {
  657. pitchRange = pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO;
  658. distK = 1.0f / KNOTS_PER_PHON;
  659. scale = 0;
  660. for( knot = 0; knot < KNOTS_PER_PHON; knot++ )
  661. {
  662. loc = pCurCell->m_PitchBufStart + (long)((pCurCell->m_PitchBufEnd - pCurCell->m_PitchBufStart) * scale);
  663. pCurCell->m_ftPitch[knot] = pCurCell->m_Pitch_LO + (m_pContBuf[loc] * pitchRange);
  664. pCurCell->m_ftTime[knot] = scale * pCurCell->m_ftDuration;
  665. scale += distK;
  666. }
  667. skipInitialSil = false;
  668. }
  669. pCurCell = m_pAllos->GetNextCell();
  670. index++;
  671. }
  672. } /* CPitchProsody::GetKnots */
  673. /*****************************************************************************
  674. * CPitchProsody::PitchTrack *
  675. *----------------------------*
  676. * Description:
  677. * Tag pitch highlights
  678. *
  679. ********************************************************************** MC ***/
  680. void CPitchProsody::PitchTrack()
  681. {
  682. SPDBG_FUNC( "CPitchProsody::PitchTrack" );
  683. long i;
  684. CAlloCell *pCurCell, *pNextCell;
  685. bool initialWord; // 1st word in phrase
  686. long wordCntDwn;
  687. float curProm; // Current accent prominence
  688. long cNumOfPoints;
  689. float *pRefBuf, *pCeilBuf, *pFloorBuf;
  690. float lastProm;
  691. long loc;
  692. float value;
  693. pRefBuf = pCeilBuf = pFloorBuf = m_pContBuf = NULL;
  694. cNumOfPoints = (long)(m_TotalDur / PITCH_BUF_RES);
  695. pRefBuf = new float[cNumOfPoints];
  696. pCeilBuf = new float[cNumOfPoints];
  697. pFloorBuf = new float[cNumOfPoints];
  698. m_pContBuf = new float[cNumOfPoints];
  699. if( pRefBuf && pCeilBuf && pFloorBuf && m_pContBuf)
  700. {
  701. //--------------------------------------------
  702. // Initialize buffers to zero
  703. //--------------------------------------------
  704. for (i = 0; i < cNumOfPoints; i++)
  705. {
  706. pCeilBuf[i] = 0;
  707. pFloorBuf[i] = 0.00001f;
  708. pRefBuf[i] = 0;
  709. m_pContBuf[i] = 0;
  710. }
  711. //--------------------------------------------
  712. // Linear CEILING slope
  713. //--------------------------------------------
  714. if( m_Tune_Style == DESCEND_TUNE )
  715. {
  716. pCeilBuf[0] = 1.0;
  717. pCeilBuf[cNumOfPoints-1] = 0.70f;
  718. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  719. }
  720. else if (m_Tune_Style == ASCEND_TUNE)
  721. {
  722. pCeilBuf[0] = 0.9f;
  723. pCeilBuf[cNumOfPoints-1] = 1.0f;
  724. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  725. }
  726. else if (m_Tune_Style == FLAT_TUNE)
  727. {
  728. pCeilBuf[0] = 1.0f;
  729. pCeilBuf[cNumOfPoints-1] = 1.0f;
  730. ::LineInterpContour( cNumOfPoints, pCeilBuf );
  731. }
  732. //--------------------------------------------
  733. // Linear REFERENCE slope
  734. //--------------------------------------------
  735. pRefBuf[0] = (float) (pFloorBuf[0] + (pCeilBuf[0] - pFloorBuf[0]) * 0.33f);
  736. pRefBuf[cNumOfPoints-1] = (float) (pFloorBuf[0] + (pCeilBuf[cNumOfPoints-1] - pFloorBuf[cNumOfPoints-1]) * 0.33f);
  737. ::LineInterpContour( cNumOfPoints,pRefBuf );
  738. //--------------------------------------------
  739. // Final contour buffer
  740. //--------------------------------------------
  741. m_pContBuf[0] = pRefBuf[0];
  742. m_pContBuf[cNumOfPoints-1] = 0.0001f; // Something very small
  743. long iPrevBegin, iPrevEnd, iCurBegin;
  744. long iCurEnd, iNextBegin, iNextEnd;
  745. float cCurLen;
  746. long iCellindex;
  747. initialWord = true;
  748. iCellindex = 0;
  749. pCurCell = m_pAllos->GetHeadCell();
  750. while( pCurCell->m_allo == _SIL_ )
  751. {
  752. //---------------------------------
  753. // Skip leading silence
  754. //---------------------------------
  755. pCurCell = m_pAllos->GetNextCell();
  756. iCellindex++;
  757. }
  758. wordCntDwn = 1; // Skip 1st word
  759. lastProm = 0;
  760. iPrevBegin = iPrevEnd = 0;
  761. pNextCell = m_pAllos->GetNextCell();
  762. while( pCurCell )
  763. {
  764. if( iCellindex >= m_numOfCells-1 )
  765. {
  766. //-----------------------
  767. // Skip last allo
  768. //-----------------------
  769. break;
  770. }
  771. //-----------------------------------
  772. // Get CURRENT allo
  773. //-----------------------------------
  774. iCurBegin = pCurCell->m_PitchBufStart;
  775. iCurEnd = pCurCell->m_PitchBufEnd;
  776. cCurLen = (float)(iCurEnd - iCurBegin);
  777. curProm = pCurCell->m_Accent_Prom * (float)0.1;
  778. //-----------------------------------
  779. // Get NEXT allo
  780. //-----------------------------------
  781. iNextBegin = pNextCell->m_PitchBufStart;
  782. iNextEnd = pNextCell->m_PitchBufEnd;
  783. m_CurAccent = pCurCell->m_ToBI_Accent;
  784. //---------------------
  785. // Diagnostic
  786. //---------------------
  787. m_CurAccentSource = pCurCell->m_AccentSource;
  788. m_CurBoundarySource = pCurCell->m_BoundarySource;
  789. m_pCurTextStr = pCurCell->m_pTextStr;
  790. switch( pCurCell->m_ToBI_Accent )
  791. {
  792. case K_RSTAR:
  793. break;
  794. case K_HSTAR:
  795. {
  796. if( !initialWord ) // We never add a 'leg' to a phrase-initial word
  797. {
  798. //----------------------------------------------
  799. // Add a L leg to start to previous allo
  800. //----------------------------------------------
  801. if( iPrevBegin )
  802. {
  803. loc = (long) ((iCurBegin + (cCurLen * 0.1f)));
  804. value = ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  805. value = pRefBuf[loc] + (value * 0.25f); // L+H*
  806. NewTarget( iPrevBegin, value );
  807. //NewTarget( loc, value );
  808. }
  809. }
  810. //----------------------------------------------
  811. // Now plug in the H target
  812. //
  813. // If we're at a boundary, insert H at
  814. // allo mid-point else insert at allo start
  815. //----------------------------------------------
  816. if( pCurCell->m_ToBI_Boundary != K_NOBND )
  817. {
  818. //---------------------------
  819. // Insert H* at allo start
  820. //---------------------------
  821. loc = (long) iCurBegin;
  822. }
  823. else
  824. {
  825. //---------------------------
  826. // Insert H* at allo mid-point
  827. //---------------------------
  828. loc = (long) (iCurBegin + (cCurLen * K_HSTAR_OFFSET));
  829. }
  830. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  831. NewTarget( loc, value );
  832. }
  833. break;
  834. case K_LSTAR:
  835. {
  836. //------------------------------------
  837. // Insert L* at mid-point
  838. //------------------------------------
  839. loc = (long) (iCurBegin + (cCurLen * 0.3f));
  840. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
  841. NewTarget( loc, value );
  842. }
  843. break;
  844. case K_LSTARH:
  845. {
  846. //----------------------------------------------
  847. // Insert L* at current start
  848. //----------------------------------------------
  849. value = pRefBuf[iCurBegin] - ((pRefBuf[iCurBegin] - pFloorBuf[iCurBegin]) * curProm); // L*+H
  850. NewTarget( iCurBegin, value );
  851. if( iNextBegin )
  852. {
  853. //----------------------------------------------
  854. // Insert H at next end
  855. // set prom gain?
  856. //----------------------------------------------
  857. value = pRefBuf[iNextEnd] - ((pRefBuf[iNextEnd] - pFloorBuf[iNextEnd]) * (curProm /* * .3 */ ));
  858. NewTarget( iNextEnd, value );
  859. }
  860. lastProm = 0;
  861. }
  862. break;
  863. case K_LHSTAR:
  864. {
  865. loc = (long) (iCurBegin + (cCurLen * 0.3f));
  866. if( iPrevBegin )
  867. {
  868. //----------------------------------------------
  869. // Insert L at previous start
  870. //----------------------------------------------
  871. value = (pRefBuf[iPrevBegin] - ((pRefBuf[iPrevBegin] - pFloorBuf[iPrevBegin]) * (curProm * 0.3f))); // L+H*
  872. NewTarget( iPrevBegin, value );
  873. }
  874. //----------------------------------------------
  875. // Insert H* at current mid-point
  876. //----------------------------------------------
  877. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  878. NewTarget( loc, value );
  879. lastProm = curProm;
  880. }
  881. break;
  882. case K_HSTARLSTAR:
  883. {
  884. //value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H*
  885. value = pRefBuf[0] + ((pCeilBuf[0] - pRefBuf[0]) * curProm); // H*
  886. NewTarget( iCurBegin, value );
  887. loc = (long) (iCurBegin + (cCurLen * 0.75f));
  888. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
  889. NewTarget( loc, value );
  890. lastProm = curProm;
  891. }
  892. break;
  893. case K_DHSTAR:
  894. {
  895. loc = (long) ( iCurBegin + (cCurLen * 0.0f) );
  896. if( lastProm )
  897. {
  898. lastProm *= K_HDOWNSTEP_COEFF;
  899. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * lastProm); // !H*
  900. NewTarget( loc, value );
  901. }
  902. //-----------------------------------------
  903. // no previous H*, treat !H* like an H*
  904. //-----------------------------------------
  905. else
  906. {
  907. value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
  908. NewTarget( loc, value );
  909. lastProm = curProm;
  910. }
  911. }
  912. break;
  913. default: // Unknown accent specfied
  914. break;
  915. }
  916. //-------------------------------------------------------------
  917. // if there's a boundary, fill in pitch value(s)
  918. // assume the boundary is set to correct (voiced) final phone
  919. //-------------------------------------------------------------
  920. curProm = pCurCell->m_Boundary_Prom * (float)0.1;
  921. m_CurAccent =(TOBI_ACCENT) pCurCell->m_ToBI_Boundary;
  922. //---------------------
  923. // Diagnostic
  924. //---------------------
  925. m_CurAccentSource = pCurCell->m_AccentSource;
  926. m_CurBoundarySource = pCurCell->m_BoundarySource;
  927. m_pCurTextStr = pCurCell->m_pTextStr;
  928. switch( pCurCell->m_ToBI_Boundary )
  929. {
  930. case K_LMINUS:
  931. {
  932. value = pRefBuf[iCurEnd] - ((pRefBuf[iCurEnd] - pFloorBuf[iCurEnd]) * curProm); // L-
  933. NewTarget( iCurEnd, value );
  934. }
  935. break;
  936. case K_HMINUS:
  937. {
  938. value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H-
  939. NewTarget( iCurEnd, value );
  940. }
  941. break;
  942. //case K_LPERC:
  943. //case K_HPERC:
  944. case K_LMINUSLPERC:
  945. {
  946. value = pFloorBuf[iCurEnd];
  947. //NewTarget( iCurEnd, value );
  948. NewTarget( iCurBegin, value );
  949. }
  950. break;
  951. case K_HMINUSHPERC:
  952. {
  953. value = pCeilBuf[iCurEnd];
  954. NewTarget( iCurEnd, value );
  955. }
  956. break;
  957. case K_LMINUSHPERC: // L-H%
  958. {
  959. //---------------------------------------
  960. // comma continuation rise
  961. //---------------------------------------
  962. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  963. // L starts at middle of previous phon
  964. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  965. loc = iPrevBegin + (iPrevEnd - iPrevBegin) / 2;
  966. value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L-
  967. NewTarget( loc, value );
  968. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  969. // H at end of current phon
  970. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  971. value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H%
  972. NewTarget( iCurEnd, value );
  973. }
  974. break;
  975. case K_HMINUSLPERC:
  976. {
  977. //---------------------------------------
  978. // accent extension followed by sharp drop
  979. //---------------------------------------
  980. value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H-
  981. NewTarget( iCurBegin, value );
  982. value = pFloorBuf[iCurEnd]; // L%
  983. //loc = iCurBegin + ((iCurEnd - iCurBegin) * 0.1f);
  984. NewTarget( iCurEnd, value );
  985. }
  986. break;
  987. default:
  988. break;
  989. }
  990. //----------------------------
  991. // Unflag initial word
  992. //----------------------------
  993. if( (initialWord) && (pCurCell->m_ctrlFlags & WORD_START) )
  994. {
  995. wordCntDwn--;
  996. if( wordCntDwn < 0 )
  997. {
  998. initialWord = false;
  999. }
  1000. }
  1001. //----------------------------
  1002. // Setup for next allo
  1003. //----------------------------
  1004. iPrevBegin = iCurBegin;
  1005. iPrevEnd = iCurEnd;
  1006. pCurCell = pNextCell;
  1007. pNextCell = m_pAllos->GetNextCell();
  1008. iCellindex++;
  1009. }
  1010. //--- Debug Macro - Log pitch data to stream
  1011. TTSDBG_LOGTOBI;
  1012. ::SecondOrderInterp( cNumOfPoints, m_pContBuf );
  1013. GetKnots();
  1014. }
  1015. if( pRefBuf )
  1016. {
  1017. delete pRefBuf;
  1018. }
  1019. if( pCeilBuf )
  1020. {
  1021. delete pCeilBuf;
  1022. }
  1023. if( pFloorBuf )
  1024. {
  1025. delete pFloorBuf;
  1026. }
  1027. if( m_pContBuf )
  1028. {
  1029. delete m_pContBuf;
  1030. }
  1031. } /* CPitchProsody::PitchTrack */