windows-nt/Source/XPSP1/NT/enduser/speech/tts/msttsdrv/engine/duration.cpp
2020-09-26 16:20:57 +08:00

336 lines
8.7 KiB
C++

/******************************************************************************
* Duration.cpp *
*--------------*
*
*------------------------------------------------------------------------------
* 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 Frontend_H
#include "Frontend.h"
#endif
#ifndef AlloOps_H
#include "AlloOps.h"
#endif
//-----------------------------
// Data.cpp
//-----------------------------
extern const unsigned long g_AlloFlags[];
extern const float g_BoundryDurTbl[];
extern const float g_BoundryStretchTbl[];
/*****************************************************************************
* CDuration::Pause_Insertion *
*----------------------------*
* Description:
* Duration Rule #1 - Pause Insertion
*
********************************************************************** MC ***/
void CDuration::Pause_Insertion( long userDuration, long silBreak )
{
SPDBG_FUNC( "CDuration::Pause_Insertion" );
if( userDuration )
{
m_DurHold = ((float)userDuration / 1000);
m_TotalDurScale = 1.0;
}
else if( silBreak )
{
m_DurHold = ((float)silBreak / 1000);
}
else
{
if( m_CurBoundary != NULL_BOUNDARY)
{
m_DurHold = g_BoundryDurTbl[(long)m_CurBoundary];
//m_DurHold *= m_TotalDurScale;
//----------------------------
// Clip to limits
//----------------------------
if( m_DurHold > MAX_SIL_DUR )
{
m_DurHold = MAX_SIL_DUR;
}
/*else if( m_DurHold < MIN_ALLO_DUR )
{
m_DurHold = MIN_ALLO_DUR;
}*/
}
}
} /* CDuration::Pause_Insertion */
/*****************************************************************************
* CDuration::PhraseFinal_Lengthen *
*---------------------------------*
* Description:
* Duration Rule #2 - Phrase-final Lengthening
*
********************************************************************** MC ***/
void CDuration::PhraseFinal_Lengthen( long /*cellCount*/ )
{
SPDBG_FUNC( "CDuration::PhraseFinal_Lengthen" );
float stretchGain;
if( m_cur_SyllableType & TERM_END_SYLL)
{
if( (m_cur_Stress) && (m_cur_VowelFlag) )
{
stretchGain = g_BoundryStretchTbl[(long)m_NextBoundary];
m_DurHold *= stretchGain;
//----------------------------
// Clip to limits
//----------------------------
if( m_DurHold > MAX_ALLO_DUR )
{
m_DurHold = MAX_ALLO_DUR;
}
else if( m_DurHold < MIN_ALLO_DUR )
{
m_DurHold = MIN_ALLO_DUR;
}
}
}
} /* CDuration::PhraseFinal_Lengthen */
#define EMPH_VOWEL_GAIN 1.0f
#define EMPH_CONS_GAIN 1.25f
#define EMPH_VOWEL_MIN 0.060f
#define EMPH_CONS_MIN 0.020f
#define EMPH_MIN_DUR 0.150f
/*****************************************************************************
* CDuration::Emphatic_Lenghen *
*-----------------------------*
* Description:
* Duration Rule #8 - Lengthening for emphasis
*
********************************************************************** MC ***/
long CDuration::Emphatic_Lenghen( long lastStress )
{
SPDBG_FUNC( "CDuration::Emphatic_Lenghen" );
long eFlag;
bool isEmph;
eFlag = lastStress;
if( m_cur_Stress & EMPHATIC_STRESS )
{
isEmph = true;
}
else
{
isEmph = false;
}
if( (m_cur_PhonCtrl & WORD_INITIAL_CONSONANT) ||
( m_cur_VowelFlag && (!isEmph)) )
{
eFlag = false; // start of a new word OR non-emph vowel
}
if( isEmph )
{
eFlag = true; // continue lengthening until above condition is met
}
if( eFlag )
{
/*if( m_DurHold < EMPH_MIN_DUR )
{
m_durationPad += EMPH_MIN_DUR - m_DurHold;
}*/
float durDiff;
if( m_cur_VowelFlag)
{
durDiff = (m_DurHold * EMPH_VOWEL_GAIN) - m_DurHold;
if( durDiff < EMPH_VOWEL_MIN )
{
durDiff = EMPH_VOWEL_MIN;
}
}
else
{
durDiff = (m_DurHold * EMPH_CONS_GAIN) - m_DurHold;
if( durDiff < EMPH_CONS_MIN )
{
durDiff = EMPH_CONS_MIN;
}
}
m_durationPad += durDiff; // lengthen phon for emph
}
return eFlag;
} /* CDuration::Emphatic_Lenghen */
/*****************************************************************************
* CDuration::AlloDuration *
*-------------------------*
* Description:
* Calculate durations
*
********************************************************************** MC ***/
void CDuration::AlloDuration( CAlloList *pAllos, float rateRatio )
{
SPDBG_FUNC( "CDuration::AlloDuration" );
long eFlag;
CAlloCell *pPrevCell, *pCurCell, *pNextCell, *pNext2Cell;
long numOfCells;
long userDuration, silBreak;
numOfCells = pAllos->GetCount();
if( numOfCells > 0 )
{
eFlag = false;
//------------------------------
// Fill the pipeline
//------------------------------
pPrevCell = pAllos->GetHeadCell();
pCurCell = pAllos->GetNextCell();
pNextCell = pAllos->GetNextCell();
pNext2Cell = pAllos->GetNextCell();
//------------------------------
// 1st allo is always SIL
//------------------------------
pPrevCell->m_ftDuration = pPrevCell->m_UnitDur = PITCH_BUF_RES; // initial SIL
while( pCurCell )
{
//------------------
// Current
//------------------
m_cur_Phon = pCurCell->m_allo;
m_cur_PhonCtrl = pCurCell->m_ctrlFlags;
m_cur_SyllableType = m_cur_PhonCtrl & SYLLABLE_TYPE_FIELD;
m_cur_Stress = m_cur_PhonCtrl & STRESS_FIELD;
m_cur_PhonFlags = ::g_AlloFlags[m_cur_Phon];
userDuration = pCurCell->m_user_Break;
silBreak = pCurCell->m_Sil_Break;
if( m_cur_PhonFlags & KVOWELF)
{
m_cur_VowelFlag = true;
}
else
{
m_cur_VowelFlag = false;
}
m_CurBoundary = pCurCell->m_TuneBoundaryType;
m_NextBoundary = pCurCell->m_NextTuneBoundaryType;
m_TotalDurScale = rateRatio * pCurCell->m_DurScale * pCurCell->m_ProsodyDurScale;
m_DurHold = pCurCell->m_UnitDur;
m_durationPad = 0;
if( pCurCell->m_user_Emph > 0 )
{
m_cur_Stress |= EMPHATIC_STRESS;
}
//------------------
// Prev
//------------------
m_prev_Phon = pPrevCell->m_allo;
m_prev_PhonCtrl = pPrevCell->m_ctrlFlags;
m_prev_PhonFlags = ::g_AlloFlags[m_prev_Phon];
//------------------
// Next
//------------------
if( pNextCell )
{
m_next_Phon = pNextCell->m_allo;
m_next_PhonCtrl = pNextCell->m_ctrlFlags;
}
else
{
m_next_Phon = _SIL_;
m_next_PhonCtrl = 0;
}
m_next_PhonFlags = ::g_AlloFlags[m_next_Phon];
//------------------
// 2 phons ahead
//------------------
if( pNext2Cell )
{
m_next2_Phon = pNext2Cell->m_allo;
m_next2_PhonCtrl = pNext2Cell->m_ctrlFlags;
}
else
{
m_next2_Phon = _SIL_;
m_next2_PhonCtrl = 0;
}
m_next2_PhonFlags = ::g_AlloFlags[m_next2_Phon];
if( m_cur_Phon == _SIL_ )
{
//-------------------------------------------
// #1 - Pause Insertion
//-------------------------------------------
Pause_Insertion( userDuration, silBreak );
}
else
{
//-------------------------------------------
// #2 - Phrase-final Lengthening
//-------------------------------------------
PhraseFinal_Lengthen( numOfCells );
//-------------------------------------------
// #8 Lengthening for emphasis
//-------------------------------------------
eFlag = Emphatic_Lenghen( eFlag );
}
pCurCell->m_ftDuration = ((m_DurHold + m_durationPad) / m_TotalDurScale);
//---------------------------------
// Shift the pipeline once
//---------------------------------
pPrevCell = pCurCell;
pCurCell = pNextCell;
pNextCell = pNext2Cell;
pNext2Cell = pAllos->GetNextCell();
}
}
} /* CDuration::AlloDuration */