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

/******************************************************************************
* 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
class CFIRFilter
{
public:
//-------------------------------------------------
// Methods
//-------------------------------------------------
void Make_Filter( float freq1, long order, float srate );
void DoFilter (float *src, float *dst, long len);
void Design_Lowpass (float freq);
//-------------------------------------------------
// Member Variables
//-------------------------------------------------
float m_Coeff[MAX_ORDER];
float m_SRate;
long m_Order;
long m_HalfOrder;
};
//-----------------------------------------------
// Design a low pass filter
//-----------------------------------------------
void CFIRFilter::Design_Lowpass (float freq)
{
float half_Filt[MAX_ORDER];
double w;
long i;
//----------------------------------------------------------
// generate one half of coefficients from sinc() function
//----------------------------------------------------------
w = 2.0 * M_PI * freq;
half_Filt[0] = (float)(w / M_PI);
for (i = 1; i <= m_HalfOrder; i++)
{
half_Filt[i] = (float)(sin(i * w) / (i * M_PI));
}
//----------------------------------------------------------
// window with (half-)hamming window
//----------------------------------------------------------
for (i = 0; i <= m_HalfOrder; i++)
{
half_Filt[i] *= (float)(0.54 + 0.46 * cos(i * M_PI / m_HalfOrder));
}
//----------------------------------------------------------
// copy as symmetric filter
//----------------------------------------------------------
for (i = 0; i < m_Order; i++)
{
m_Coeff[i] = half_Filt[abs(m_HalfOrder - i)];
}
}
//-----------------------------------------------
// Do the filtering
//-----------------------------------------------
void CFIRFilter::DoFilter (float *src, float *dst, long len)
{
#define kWakeSamples 1000;
long i,j;
float *sp;
float sum;
long lenAdj;
lenAdj = len - m_Order;
if (lenAdj >= 0)
{
for (i = 0; i < m_HalfOrder; i++)
{
*dst++ = src[0];
}
for (i = 0; i < lenAdj; i++)
{
sum = (float)0.0;
sp = src + i;
for (j = 0; j < m_Order; j++)
{
sum += ((float)*sp++) * m_Coeff[j];
}
*dst++ = sum;
}
for (i = 0; i < m_HalfOrder; i++)
{
*dst++ = src[len-1];
}
}
}
void CFIRFilter::Make_Filter( float freq1, long order, float srate )
{
m_SRate = srate;
m_Order = order;
m_HalfOrder = m_Order / 2;
Design_Lowpass (freq1 / m_SRate);
}
/*****************************************************************************
* 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, int baseLine, int 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 + 0.5);
pCurCell->m_PitchBufEnd = quantTotal;
skipInitialSil = false;
}
index++;
pCurCell = pAllos->GetNextCell();
}
//------------------------------
// Init pitch range
//------------------------------
pCurCell = m_pAllos->GetHeadCell();
while( pCurCell )
{
float hzVal;
//---------------------------------------
// Scale to possible pitch control
//---------------------------------------
hzVal = DoPitchControl( pCurCell->m_user_Pitch, (float)baseLine );
pCurCell->m_Pitch_HI = hzVal + ( pitchRange / 2 );
pCurCell->m_Pitch_LO = hzVal - ( pitchRange / 2 );
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();
}
pCurCell = m_pAllos->GetHeadCell();
while ( pCurCell )
{
for ( int i = pCurCell->m_PitchBufStart; i < pCurCell->m_PitchBufEnd; i++ )
{
if ( 0.0 < m_pContBuf[i] && m_pContBuf[i] < 1.0 )
{
m_pContBuf[i] = pCurCell->m_Pitch_LO +
( m_pContBuf[i] * ( pCurCell->m_Pitch_HI - pCurCell->m_Pitch_LO ) );
}
}
pCurCell = m_pAllos->GetNextCell();
}
} /* 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;
}
//---------------------------------
// FIR Filter
//---------------------------------
/*CFIRFilter filterObj;
float *pOrig;
pOrig = new float[cNumOfPoints];
memcpy( pOrig, pPoints, cNumOfPoints * sizeof(float));
if( pOrig )
{
filterObj.Make_Filter( 5, // Freq
10, // order
100 // SR
);
filterObj.DoFilter( pOrig, pPoints, cNumOfPoints);
delete pOrig;
}*/
//---------------------------------
// 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 = NULL;
cNumOfPoints = (long)(m_TotalDur / PITCH_BUF_RES + 0.5);
pRefBuf = new float[cNumOfPoints];
pCeilBuf = new float[cNumOfPoints];
pFloorBuf = new float[cNumOfPoints];
if ( m_pContBuf )
{
delete m_pContBuf;
m_pContBuf = NULL;
}
m_pContBuf = new float[cNumOfPoints];
m_ulNumPoints = 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;
}
} /* CPitchProsody::PitchTrack */
void CPitchProsody::GetContour( float** ppf0, ULONG *ulNumf0 )
{
*ppf0 = new float[ m_ulNumPoints ];
float *Array = *ppf0;
for ( ULONG i = 0; i < m_ulNumPoints; i++ )
{
Array[i] = m_pContBuf[i];
}
*ulNumf0 = m_ulNumPoints;
}