|
|
/******************************************************************************
* PitchProsody.cpp * *--------------------* * * This is an implementation of the PitchProsody class. *------------------------------------------------------------------------------ * Copyright (C) 1999 Microsoft Corporation Date: 04/28/99 * All Rights Reserved * *********************************************************************** MC ****/
//--- Additional includes
#include "stdafx.h"
#ifndef SPDebug_h
#include <spdebug.h>
#endif
#ifndef AlloOps_H
#include "AlloOps.h"
#endif
#ifndef Frontend_H
#include "Frontend.h"
#endif
//-----------------------------
// Data.cpp
//-----------------------------
extern const float g_PitchScale[];
//--------------------------------
// Interpolation direction
//--------------------------------
enum INTERP_DIR { GOING_UP, GOING_DOWN, };
#define M_PI 3.14159265358979323846
#define MAX_ORDER 4096
/*****************************************************************************
* HzToOct * *---------* * Description: * Convert liner freq ro exp pitch * 0.69314718 is log of 2 * 1.021975 is offset for middle C * ********************************************************************** MC ***/ float HzToOct( float cps) { SPDBG_FUNC( "HzToOct" );
return (float)(log(cps / 1.021975) / 0.69314718); } /* HzToOct */
/*****************************************************************************
* OctToHz * *---------* * Description: * Convert from exp pitch to linear freq ********************************************************************** MC ***/ float OctToHz( float oct) { SPDBG_FUNC( "OctToHz" );
return (float)(pow(2, oct) * 1.021975); } /* OctToHz */
/*****************************************************************************
* CPitchProsody::DoPitchControl * *-------------------------------* * Description: * Scale speech pitch to user control * ********************************************************************** MC ***/ float CPitchProsody::DoPitchControl( long pitchControl, float basePitch ) { SPDBG_FUNC( "CPitchProsody::DoPitchControl" ); float newPitch;
if( pitchControl < 0 ) { //--------------------------------
// DECREASE the pitch
//--------------------------------
if( pitchControl < MIN_USER_PITCH ) { pitchControl = MIN_USER_PITCH; // clip to min
} newPitch = (float)basePitch / g_PitchScale[0 - pitchControl]; } else { //--------------------------------
// INCREASE the pitch
//--------------------------------
if( pitchControl > MAX_USER_PITCH ) { pitchControl = MAX_USER_PITCH; // clip to max
} newPitch = (float)basePitch * g_PitchScale[pitchControl]; } return newPitch; } /* CPitchProsody::DoPitchControl */
/*****************************************************************************
* CPitchProsody::SetDefaultPitch * *--------------------------------* * Description: * Init pitch knots to monotone in case there's a failure in this object. * ********************************************************************** MC ***/ void CPitchProsody::SetDefaultPitch() { SPDBG_FUNC( "CPitchProsody::SetDefaultPitch" ); CAlloCell *pCurCell;
pCurCell = m_pAllos->GetHeadCell(); while( pCurCell ) { float relTime, timeK; float normalPitch; long knot;
normalPitch = pCurCell->m_Pitch_LO + ((pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO) / 2); timeK = pCurCell->m_ftDuration / KNOTS_PER_PHON; relTime = 0; for( knot = 0; knot < KNOTS_PER_PHON; knot++ ) { pCurCell->m_ftPitch[knot] = normalPitch; pCurCell->m_ftTime[knot] = relTime; relTime += timeK; } pCurCell = m_pAllos->GetNextCell(); } } /* CPitchProsody::SetDefaultPitch */
/*****************************************************************************
* CPitchProsody::AlloPitch * *--------------------------* * Description: * Tag pitch highlights * ********************************************************************** MC ***/ void CPitchProsody::AlloPitch( CAlloList *pAllos, float baseLine, float pitchRange ) { SPDBG_FUNC( "CAlloOps::AlloPitch" ); CAlloCell *pCurCell; bool skipInitialSil; long quantTotal, index; m_pAllos = pAllos; m_numOfCells = m_pAllos->GetCount(); m_Tune_Style = DESCEND_TUNE; // NOTE: maybe set from rules
m_TotalDur = 0; quantTotal = 0; m_OffsTime = 0; skipInitialSil = true;
//------------------------------
// Calculate total duration
// (exclude surrounding silence)
//------------------------------
index = 0; pCurCell = m_pAllos->GetHeadCell(); while( pCurCell ) { if( (skipInitialSil) && (pCurCell->m_allo == _SIL_) ) { //---------------------------------
// Skip leading silence
//---------------------------------
m_OffsTime += pCurCell->m_ftDuration; } else if( (index == (m_numOfCells -1)) && (pCurCell->m_allo == _SIL_) ) { //---------------------------------
// Skip term silence
//---------------------------------
break; } else { pCurCell->m_PitchBufStart = quantTotal; m_TotalDur += pCurCell->m_ftDuration; quantTotal = (long)(m_TotalDur / PITCH_BUF_RES); pCurCell->m_PitchBufEnd = quantTotal; skipInitialSil = false; } index++; pCurCell = pAllos->GetNextCell(); }
//------------------------------
// Init pitch range
//------------------------------
pCurCell = m_pAllos->GetHeadCell(); while( pCurCell ) { float hzVal, pitchK, rangeTemp;
//---------------------------------------
// Scale to possible pitch control
//---------------------------------------
rangeTemp = pitchRange * pCurCell->m_PitchRangeScale; hzVal = DoPitchControl( pCurCell->m_user_Pitch, baseLine ); pitchK = HzToOct( hzVal ) + pCurCell->m_PitchBaseOffs; pCurCell->m_Pitch_HI = OctToHz( pitchK + rangeTemp ); pCurCell->m_Pitch_LO = OctToHz( pitchK - rangeTemp );
pCurCell = pAllos->GetNextCell(); }
//--------------------------------------------
// In case we fail somewhere, set values to
// a known valid state (monotone).
//--------------------------------------------
SetDefaultPitch();
if( m_TotalDur > 0 ) { //--------------------------------------------
// Generate pitch targets
//--------------------------------------------
PitchTrack(); }
} /* CPitchProsody::AlloPitch */
/*****************************************************************************
* LineInterpContour * *--------------------* * Description: * Does linear interpolation over the pitch contour * ********************************************************************** MC ***/ void LineInterpContour( long cNumOfPoints, float *pPoints ) { SPDBG_FUNC( "LineInterpContour" ); long endAnch,startAnch, i; float bPoint1, ePoint1; //----------------------------------------------------
// Scan forward from beginning to find 1st non-zero enrty
// Use it as the START point.
//----------------------------------------------------
for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ ) { if( pPoints[startAnch] != 0 ) { break; } } bPoint1 = pPoints[startAnch]; //----------------------------------------------------
// Scan back from end to find 1st non-zero enrty
// Use it as the END point.
//----------------------------------------------------
for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- ) { if( pPoints[endAnch] != 0 ) { break; } } ePoint1 = pPoints[endAnch]; long firstp = 0; long lastp = 0; while( firstp < cNumOfPoints ) { //-------------------------------------------
// Find beginning and end of current section
//-------------------------------------------
while( pPoints[firstp] != 0 ) { if( ++firstp >= cNumOfPoints-1 ) { break; } } if( firstp >= cNumOfPoints-1 ) { //--------------------------------------
// There's nothing to interpolate!
//--------------------------------------
break; }
lastp = firstp+1; while( pPoints[lastp] == 0 ) { if( ++lastp >= cNumOfPoints ) { lastp = cNumOfPoints; break; } } lastp--;
if( lastp >= firstp ) { if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) ) { break; } //-------------------------------------------
// Do the interpolate
//-------------------------------------------
float bPoint,ePoint; if( firstp == 0 ) { bPoint = bPoint1; } else { bPoint = pPoints[firstp - 1]; } if( lastp == cNumOfPoints-1 ) { ePoint = ePoint1; } else { ePoint = pPoints[lastp + 1]; } float pointSpread = ePoint - bPoint; float timeSpread = (float) ((lastp - firstp)+2); float inc = pointSpread / timeSpread; float theBase = bPoint; for( i = firstp; i <= lastp; i++ ) { theBase += inc; pPoints[i] = theBase; } } else { pPoints[firstp] = pPoints[lastp+1]; } firstp = lastp+1; } } /* LineInterpContour */
/*****************************************************************************
* Interpolate2 * *---------------* * Description: * Do a 2nd order interpolation, a little nicer than just linear * ********************************************************************** MC ***/ void Interpolate2( INTERP_DIR direction, float *m_theFitPoints, long theStart, long len, float theAmp, float theBase) { SPDBG_FUNC( "Interpolate2" ); long midPoint = len / 2; long i;
theAmp -= theBase;
for( i = theStart; i < theStart + len;i++ ) { if (direction == GOING_UP) { if( i < theStart + midPoint ) { m_theFitPoints[i] = theBase + (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) * (((float)i - (float)theStart) / (float)len)); } else { m_theFitPoints[i] = (theBase + theAmp) - ((2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) * (1 - ((float)i - (float)theStart) / (float)len))); } } else if( direction == GOING_DOWN ) {
if( i < theStart + midPoint ) { m_theFitPoints[i] = theBase + theAmp - (2 * theAmp) * ((((float)i - (float)theStart) / (float)len) * (((float)i - (float)theStart) / (float)len)); } else { m_theFitPoints[i] = theBase + (2 * theAmp) * ((1 - ((float)i - (float)theStart) / (float)len) * (1 - ((float)i - (float)theStart) / (float)len)); } } } } /* Interpolate2 */
/*****************************************************************************
* SecondOrderInterp * *--------------------* * Description: * Does 2nd order interpolation over the pitch contour * ********************************************************************** MC ***/ void SecondOrderInterp( long cNumOfPoints, float *pPoints ) { SPDBG_FUNC( "SecondOrderInterp" ); long endAnch,startAnch; float bPoint1, ePoint1;
//----------------------------------------------------
// Scan forward from beginning to find 1st non-zero enrty
// Use it as the START point.
//----------------------------------------------------
for( startAnch = 0; startAnch < cNumOfPoints; startAnch++ ) { if( pPoints[startAnch] != 0 ) { break; } } bPoint1 = pPoints[startAnch]; //----------------------------------------------------
// Scan back from end to find 1st non-zero enrty
// Use it as the END point.
//----------------------------------------------------
for( endAnch = cNumOfPoints-1; endAnch >= 0; endAnch-- ) { if( pPoints[endAnch] != 0 ) { break; } } ePoint1 = pPoints[endAnch];
long firstp = 0; long lastp = 0;
while( firstp < cNumOfPoints-1 ) {
//------------------------------------------------
// Find beginning and end of current section
//------------------------------------------------
while( pPoints[firstp] != 0 ) { if( ++firstp >= cNumOfPoints-1 ) { break; } } if( firstp >= cNumOfPoints-1 ) { //--------------------------------------
// There's nothing to interpolate!
//--------------------------------------
break; }
lastp = firstp + 1; while( pPoints[lastp] == 0 ) { if( ++lastp >= cNumOfPoints ) { lastp = cNumOfPoints; break; } } lastp--;
if( lastp >= firstp ) { if( (lastp >= cNumOfPoints) || (firstp >= cNumOfPoints) ) { break; }
//--------------------------------
// Do the interpolate
//--------------------------------
float bPoint, ePoint;
if( firstp == 0 ) { bPoint = bPoint1; } else { bPoint = pPoints[firstp - 1]; }
long theIndex = lastp + 1;
if( lastp == cNumOfPoints-1 ) { ePoint = ePoint1; } else { ePoint = pPoints[theIndex]; }
//--------------------------------
// call the 2nd order routine
//--------------------------------
if( ePoint - bPoint > 0 ) { Interpolate2( GOING_UP, pPoints, firstp, (lastp - firstp) + 1, ePoint, bPoint ); } else { Interpolate2( GOING_DOWN, pPoints, firstp, (lastp - firstp) + 1, bPoint, ePoint ); }
} else { pPoints[firstp] = pPoints[lastp+1]; }
firstp = lastp+1; }
//---------------------------------
// IIR Filter
//---------------------------------
#define kPointDelay 1
float filter_Out1, filter_In_Gain, filter_FB_Gain; float lastPoint; long i;
//--------------------------------------------------
// Skip filter if audio len less than delay
//--------------------------------------------------
if( cNumOfPoints > kPointDelay ) { filter_In_Gain = 0.10f; filter_FB_Gain = 1.0f - filter_In_Gain; filter_Out1 = pPoints[0]; for( i = 0; i < cNumOfPoints; i++ ) { filter_Out1 = (filter_In_Gain * pPoints[i]) + (filter_FB_Gain * filter_Out1); pPoints[i] = filter_Out1; } for( i = kPointDelay; i < cNumOfPoints; i++ ) { pPoints[i-kPointDelay] = pPoints[i]; } i = (cNumOfPoints - kPointDelay) -1; lastPoint = pPoints[i++]; for( ; i < cNumOfPoints; i++ ) { pPoints[i] = lastPoint; } } } /* SecondOrderInterp */
/*****************************************************************************
* CPitchProsody::NewTarget * *---------------------------* * Description: * Insert pitch target into 'm_pContBuf' * ********************************************************************** MC ***/ void CPitchProsody::NewTarget( long index, float value ) { SPDBG_FUNC( "CPitchProsody::NewTarget" );
m_pContBuf[index] = value;
//--- Debug Macro - add pitch to target list for later debugging output
TTSDBG_ADDPITCHTARGET( m_OffsTime + (PITCH_BUF_RES * index), value, m_CurAccent );
} /* CPitchProsody::NewTarget */
/*****************************************************************************
* CPitchProsody::GetKnots * *-------------------------* * Description: * Assign pitch knots based on entries in a contour buffer. * ********************************************************************** MC ***/ void CPitchProsody::GetKnots () { SPDBG_FUNC( "CPitchProsody::GetKnots" ); CAlloCell *pCurCell; float distK, scale; float pitchRange; long knot, loc, index; bool skipInitialSil;
skipInitialSil = true; pCurCell = m_pAllos->GetHeadCell(); index = 0; while( pCurCell ) { if( index >= m_numOfCells-1 ) { //-----------------------
// Skip last allo
//-----------------------
break; } if( (!skipInitialSil) || (pCurCell->m_allo != _SIL_) ) { pitchRange = pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO; distK = 1.0f / KNOTS_PER_PHON; scale = 0; for( knot = 0; knot < KNOTS_PER_PHON; knot++ ) { loc = pCurCell->m_PitchBufStart + (long)((pCurCell->m_PitchBufEnd - pCurCell->m_PitchBufStart) * scale); pCurCell->m_ftPitch[knot] = pCurCell->m_Pitch_LO + (m_pContBuf[loc] * pitchRange); pCurCell->m_ftTime[knot] = scale * pCurCell->m_ftDuration; scale += distK; } skipInitialSil = false; } pCurCell = m_pAllos->GetNextCell(); index++; } } /* CPitchProsody::GetKnots */
/*****************************************************************************
* CPitchProsody::PitchTrack * *----------------------------* * Description: * Tag pitch highlights * ********************************************************************** MC ***/ void CPitchProsody::PitchTrack() { SPDBG_FUNC( "CPitchProsody::PitchTrack" ); long i; CAlloCell *pCurCell, *pNextCell; bool initialWord; // 1st word in phrase
long wordCntDwn; float curProm; // Current accent prominence
long cNumOfPoints; float *pRefBuf, *pCeilBuf, *pFloorBuf; float lastProm; long loc; float value;
pRefBuf = pCeilBuf = pFloorBuf = m_pContBuf = NULL; cNumOfPoints = (long)(m_TotalDur / PITCH_BUF_RES); pRefBuf = new float[cNumOfPoints]; pCeilBuf = new float[cNumOfPoints]; pFloorBuf = new float[cNumOfPoints]; m_pContBuf = new float[cNumOfPoints];
if( pRefBuf && pCeilBuf && pFloorBuf && m_pContBuf) { //--------------------------------------------
// Initialize buffers to zero
//--------------------------------------------
for (i = 0; i < cNumOfPoints; i++) { pCeilBuf[i] = 0; pFloorBuf[i] = 0.00001f; pRefBuf[i] = 0; m_pContBuf[i] = 0; }
//--------------------------------------------
// Linear CEILING slope
//--------------------------------------------
if( m_Tune_Style == DESCEND_TUNE ) { pCeilBuf[0] = 1.0; pCeilBuf[cNumOfPoints-1] = 0.70f; ::LineInterpContour( cNumOfPoints, pCeilBuf ); } else if (m_Tune_Style == ASCEND_TUNE) { pCeilBuf[0] = 0.9f; pCeilBuf[cNumOfPoints-1] = 1.0f; ::LineInterpContour( cNumOfPoints, pCeilBuf ); } else if (m_Tune_Style == FLAT_TUNE) { pCeilBuf[0] = 1.0f; pCeilBuf[cNumOfPoints-1] = 1.0f; ::LineInterpContour( cNumOfPoints, pCeilBuf ); }
//--------------------------------------------
// Linear REFERENCE slope
//--------------------------------------------
pRefBuf[0] = (float) (pFloorBuf[0] + (pCeilBuf[0] - pFloorBuf[0]) * 0.33f); pRefBuf[cNumOfPoints-1] = (float) (pFloorBuf[0] + (pCeilBuf[cNumOfPoints-1] - pFloorBuf[cNumOfPoints-1]) * 0.33f); ::LineInterpContour( cNumOfPoints,pRefBuf );
//--------------------------------------------
// Final contour buffer
//--------------------------------------------
m_pContBuf[0] = pRefBuf[0]; m_pContBuf[cNumOfPoints-1] = 0.0001f; // Something very small
long iPrevBegin, iPrevEnd, iCurBegin; long iCurEnd, iNextBegin, iNextEnd; float cCurLen; long iCellindex;
initialWord = true; iCellindex = 0; pCurCell = m_pAllos->GetHeadCell(); while( pCurCell->m_allo == _SIL_ ) { //---------------------------------
// Skip leading silence
//---------------------------------
pCurCell = m_pAllos->GetNextCell(); iCellindex++; } wordCntDwn = 1; // Skip 1st word
lastProm = 0; iPrevBegin = iPrevEnd = 0;
pNextCell = m_pAllos->GetNextCell(); while( pCurCell ) { if( iCellindex >= m_numOfCells-1 ) { //-----------------------
// Skip last allo
//-----------------------
break; } //-----------------------------------
// Get CURRENT allo
//-----------------------------------
iCurBegin = pCurCell->m_PitchBufStart; iCurEnd = pCurCell->m_PitchBufEnd; cCurLen = (float)(iCurEnd - iCurBegin); curProm = pCurCell->m_Accent_Prom * (float)0.1;
//-----------------------------------
// Get NEXT allo
//-----------------------------------
iNextBegin = pNextCell->m_PitchBufStart; iNextEnd = pNextCell->m_PitchBufEnd;
m_CurAccent = pCurCell->m_ToBI_Accent; //---------------------
// Diagnostic
//---------------------
m_CurAccentSource = pCurCell->m_AccentSource; m_CurBoundarySource = pCurCell->m_BoundarySource; m_pCurTextStr = pCurCell->m_pTextStr;
switch( pCurCell->m_ToBI_Accent ) { case K_RSTAR: break;
case K_HSTAR: { if( !initialWord ) // We never add a 'leg' to a phrase-initial word
{ //----------------------------------------------
// Add a L leg to start to previous allo
//----------------------------------------------
if( iPrevBegin ) { loc = (long) ((iCurBegin + (cCurLen * 0.1f))); value = ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
value = pRefBuf[loc] + (value * 0.25f); // L+H*
NewTarget( iPrevBegin, value ); //NewTarget( loc, value );
} } //----------------------------------------------
// Now plug in the H target
//
// If we're at a boundary, insert H at
// allo mid-point else insert at allo start
//----------------------------------------------
if( pCurCell->m_ToBI_Boundary != K_NOBND ) { //---------------------------
// Insert H* at allo start
//---------------------------
loc = (long) iCurBegin; } else { //---------------------------
// Insert H* at allo mid-point
//---------------------------
loc = (long) (iCurBegin + (cCurLen * K_HSTAR_OFFSET)); } value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
NewTarget( loc, value ); } break;
case K_LSTAR: { //------------------------------------
// Insert L* at mid-point
//------------------------------------
loc = (long) (iCurBegin + (cCurLen * 0.3f)); value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
NewTarget( loc, value ); } break;
case K_LSTARH: { //----------------------------------------------
// Insert L* at current start
//----------------------------------------------
value = pRefBuf[iCurBegin] - ((pRefBuf[iCurBegin] - pFloorBuf[iCurBegin]) * curProm); // L*+H
NewTarget( iCurBegin, value ); if( iNextBegin ) { //----------------------------------------------
// Insert H at next end
// set prom gain?
//----------------------------------------------
value = pRefBuf[iNextEnd] - ((pRefBuf[iNextEnd] - pFloorBuf[iNextEnd]) * (curProm /* * .3 */ )); NewTarget( iNextEnd, value ); } lastProm = 0; } break;
case K_LHSTAR: { loc = (long) (iCurBegin + (cCurLen * 0.3f)); if( iPrevBegin ) { //----------------------------------------------
// Insert L at previous start
//----------------------------------------------
value = (pRefBuf[iPrevBegin] - ((pRefBuf[iPrevBegin] - pFloorBuf[iPrevBegin]) * (curProm * 0.3f))); // L+H*
NewTarget( iPrevBegin, value ); } //----------------------------------------------
// Insert H* at current mid-point
//----------------------------------------------
value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
NewTarget( loc, value ); lastProm = curProm; } break;
case K_HSTARLSTAR: { //value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H*
value = pRefBuf[0] + ((pCeilBuf[0] - pRefBuf[0]) * curProm); // H*
NewTarget( iCurBegin, value );
loc = (long) (iCurBegin + (cCurLen * 0.75f)); value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L*
NewTarget( loc, value ); lastProm = curProm; } break; case K_DHSTAR: { loc = (long) ( iCurBegin + (cCurLen * 0.0f) ); if( lastProm ) { lastProm *= K_HDOWNSTEP_COEFF; value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * lastProm); // !H*
NewTarget( loc, value ); } //-----------------------------------------
// no previous H*, treat !H* like an H*
//-----------------------------------------
else { value = pRefBuf[loc] + ((pCeilBuf[loc] - pRefBuf[loc]) * curProm); // H*
NewTarget( loc, value ); lastProm = curProm; } } break;
default: // Unknown accent specfied
break; }
//-------------------------------------------------------------
// if there's a boundary, fill in pitch value(s)
// assume the boundary is set to correct (voiced) final phone
//-------------------------------------------------------------
curProm = pCurCell->m_Boundary_Prom * (float)0.1; m_CurAccent =(TOBI_ACCENT) pCurCell->m_ToBI_Boundary; //---------------------
// Diagnostic
//---------------------
m_CurAccentSource = pCurCell->m_AccentSource; m_CurBoundarySource = pCurCell->m_BoundarySource; m_pCurTextStr = pCurCell->m_pTextStr; switch( pCurCell->m_ToBI_Boundary ) { case K_LMINUS: { value = pRefBuf[iCurEnd] - ((pRefBuf[iCurEnd] - pFloorBuf[iCurEnd]) * curProm); // L-
NewTarget( iCurEnd, value ); } break;
case K_HMINUS: { value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H-
NewTarget( iCurEnd, value ); } break;
//case K_LPERC:
//case K_HPERC:
case K_LMINUSLPERC: { value = pFloorBuf[iCurEnd]; //NewTarget( iCurEnd, value );
NewTarget( iCurBegin, value ); } break;
case K_HMINUSHPERC: { value = pCeilBuf[iCurEnd]; NewTarget( iCurEnd, value ); } break;
case K_LMINUSHPERC: // L-H%
{ //---------------------------------------
// comma continuation rise
//---------------------------------------
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// L starts at middle of previous phon
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
loc = iPrevBegin + (iPrevEnd - iPrevBegin) / 2; value = pRefBuf[loc] - ((pRefBuf[loc] - pFloorBuf[loc]) * curProm); // L-
NewTarget( loc, value ); //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// H at end of current phon
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
value = pRefBuf[iCurEnd] + ((pCeilBuf[iCurEnd] - pRefBuf[iCurEnd]) * curProm); // H%
NewTarget( iCurEnd, value ); } break;
case K_HMINUSLPERC: { //---------------------------------------
// accent extension followed by sharp drop
//---------------------------------------
value = pRefBuf[iCurBegin] + ((pCeilBuf[iCurBegin] - pRefBuf[iCurBegin]) * curProm); // H-
NewTarget( iCurBegin, value ); value = pFloorBuf[iCurEnd]; // L%
//loc = iCurBegin + ((iCurEnd - iCurBegin) * 0.1f);
NewTarget( iCurEnd, value ); } break;
default: break; } //----------------------------
// Unflag initial word
//----------------------------
if( (initialWord) && (pCurCell->m_ctrlFlags & WORD_START) ) { wordCntDwn--; if( wordCntDwn < 0 ) { initialWord = false; } }
//----------------------------
// Setup for next allo
//----------------------------
iPrevBegin = iCurBegin; iPrevEnd = iCurEnd;
pCurCell = pNextCell; pNextCell = m_pAllos->GetNextCell(); iCellindex++; }
//--- Debug Macro - Log pitch data to stream
TTSDBG_LOGTOBI;
::SecondOrderInterp( cNumOfPoints, m_pContBuf ); GetKnots(); }
if( pRefBuf ) { delete pRefBuf; } if( pCeilBuf ) { delete pCeilBuf; } if( pFloorBuf ) { delete pFloorBuf; } if( m_pContBuf ) { delete m_pContBuf; } } /* CPitchProsody::PitchTrack */
|