4034 lines
112 KiB
C++
4034 lines
112 KiB
C++
/*******************************************************************************
|
||
* Frontend.cpp *
|
||
*--------------*
|
||
* Description:
|
||
* This module is the main implementation file for the CFrontend class.
|
||
*-------------------------------------------------------------------------------
|
||
* Created By: mc Date: 03/12/99
|
||
* Copyright (C) 1999 Microsoft Corporation
|
||
* All Rights Reserved
|
||
*
|
||
*******************************************************************************/
|
||
|
||
//--- Additional includes
|
||
#include "stdafx.h"
|
||
#include "ms_entropicengine.h"
|
||
#include "Frontend.h"
|
||
#include "spdebug.h"
|
||
#include "FeedChain.h"
|
||
#include "AlloOps.h"
|
||
#include "sapi.h"
|
||
|
||
#include "StdSentEnum.h"
|
||
|
||
static bool IsVowel ( char* ph );
|
||
|
||
//-----------------------------
|
||
// Data.cpp
|
||
//-----------------------------
|
||
extern const short g_IPAToAllo[];
|
||
extern const float g_RateScale[];
|
||
|
||
inline short GetPhoneF0( float *pF0Contour, float CurrentTime, float Length )
|
||
{
|
||
float Total = 0;
|
||
int startIndex = (int) ( CurrentTime / PITCH_BUF_RES + 0.5 );
|
||
int endIndex = (int) ( ( CurrentTime + Length ) / PITCH_BUF_RES + 0.5 );
|
||
|
||
for ( int i = startIndex; i < endIndex; i++ )
|
||
{
|
||
Total += pF0Contour[i];
|
||
}
|
||
|
||
Total /= endIndex - startIndex;
|
||
|
||
return (short) Total;
|
||
}
|
||
|
||
const char* OldMapPhoneSet (ALLO_CODE code)
|
||
{
|
||
static struct tagPhoneMap {
|
||
const char* name;
|
||
ALLO_CODE code;
|
||
} phoneMap [] = {
|
||
{"iy", _IY_},
|
||
{"ih", _IH_},
|
||
{"eh", _EH_},
|
||
{"ae", _AE_},
|
||
{"aa", _AA_},
|
||
{"ah", _AH_},
|
||
{"ao", _AO_},
|
||
{"uh", _UH_},
|
||
{"ax", _AX_},
|
||
{"axr", _ER_}, // or "er"
|
||
{"ey", _EY_},
|
||
{"ay", _AY_},
|
||
{"oy", _OY_},
|
||
{"aw", _AW_},
|
||
{"ow", _OW_},
|
||
{"uw", _UW_},
|
||
{"ix", _IX_},
|
||
{"sil", _SIL_},
|
||
{"w", _w_},
|
||
{"y", _y_},
|
||
{"r", _r_},
|
||
{"l", _l_},
|
||
{"hh", _h_},
|
||
{"m", _m_},
|
||
{"n", _n_},
|
||
{"ng", _NG_},
|
||
{"f", _f_},
|
||
{"v", _v_},
|
||
{"th", _TH_},
|
||
{"dh", _DH_},
|
||
{"s", _s_},
|
||
{"z", _z_},
|
||
{"sh", _SH_},
|
||
{"zh", _ZH_},
|
||
{"p", _p_},
|
||
{"b", _b_},
|
||
{"t", _t_},
|
||
{"d", _d_},
|
||
{"k", _k_},
|
||
{"g", _g_},
|
||
{"ch", _CH_},
|
||
{"jh", _JH_},
|
||
{"dx", _DX_},
|
||
{"", _STRESS1_},
|
||
{"", _STRESS2_},
|
||
{"", _EMPHSTRESS_},
|
||
{"", _SYLLABLE_}
|
||
};
|
||
static int nPhonesMap = sizeof (phoneMap) / sizeof(phoneMap[0]);
|
||
int i;
|
||
|
||
for ( i = 0; i < nPhonesMap; i++ )
|
||
{
|
||
if (code == phoneMap[i].code)
|
||
{
|
||
return phoneMap[i].name;
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
|
||
const char* NewMapPhoneSet (ALLO_CODE code)
|
||
{
|
||
static struct tagPhoneMap {
|
||
const char* name;
|
||
ALLO_CODE code;
|
||
} phoneMap [] = {
|
||
{"iy", _IY_},
|
||
{"ih", _IH_},
|
||
{"eh", _EH_},
|
||
{"ae", _AE_},
|
||
{"aa", _AA_},
|
||
{"ah", _AH_},
|
||
{"ao", _AO_},
|
||
{"uh", _UH_},
|
||
{"ax", _AX_},
|
||
{"er", _ER_}, // or "er"
|
||
{"ey", _EY_},
|
||
{"ay", _AY_},
|
||
{"oy", _OY_},
|
||
{"aw", _AW_},
|
||
{"ow", _OW_},
|
||
{"uw", _UW_},
|
||
{"ix", _IX_},
|
||
{"sil", _SIL_},
|
||
{"w", _w_},
|
||
{"y", _y_},
|
||
{"r", _r_},
|
||
{"l", _l_},
|
||
{"h", _h_},
|
||
{"m", _m_},
|
||
{"n", _n_},
|
||
{"ng", _NG_},
|
||
{"f", _f_},
|
||
{"v", _v_},
|
||
{"th", _TH_},
|
||
{"dh", _DH_},
|
||
{"s", _s_},
|
||
{"z", _z_},
|
||
{"sh", _SH_},
|
||
{"zh", _ZH_},
|
||
{"p", _p_},
|
||
{"b", _b_},
|
||
{"t", _t_},
|
||
{"d", _d_},
|
||
{"k", _k_},
|
||
{"g", _g_},
|
||
{"ch", _CH_},
|
||
{"jh", _JH_},
|
||
{"dx", _DX_},
|
||
{"", _STRESS1_},
|
||
{"", _STRESS2_},
|
||
{"", _EMPHSTRESS_},
|
||
{"", _SYLLABLE_}
|
||
};
|
||
static int nPhonesMap = sizeof (phoneMap) / sizeof(phoneMap[0]);
|
||
int i;
|
||
|
||
for ( i = 0; i < nPhonesMap; i++ )
|
||
{
|
||
if (code == phoneMap[i].code)
|
||
{
|
||
return phoneMap[i].name;
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::CFrontend *
|
||
*----------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
CFrontend::CFrontend()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::CFrontend" );
|
||
#ifdef USE_VOICEDATAOBJ
|
||
m_pUnits = NULL;
|
||
#endif
|
||
m_unitCount = 0;
|
||
m_CurUnitIndex = 0;
|
||
m_pAllos = NULL;
|
||
m_pSrcObj = NULL;
|
||
m_fNewPhoneSet = FALSE;
|
||
} /* CFrontend::CFrontend */
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::~CFrontend *
|
||
*-----------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
CFrontend::~CFrontend()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::~CFrontend" );
|
||
|
||
#ifdef USE_VOICEDATAOBJ
|
||
DisposeUnits();
|
||
#endif
|
||
if( m_pAllos )
|
||
{
|
||
delete m_pAllos;
|
||
m_pAllos = NULL;
|
||
}
|
||
DeleteTokenList();
|
||
} /* CFrontend::~CFrontend */
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::CntrlToRatio *
|
||
*-------------------------*
|
||
* Description:
|
||
* Return rate ratio from control
|
||
*
|
||
********************************************************************** MC ***/
|
||
float CFrontend::CntrlToRatio( long rateControl )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::CntrlToRatio" );
|
||
float rateRatio;
|
||
|
||
if( rateControl < 0 )
|
||
{
|
||
//--------------------------------
|
||
// DECREASE the rate
|
||
//--------------------------------
|
||
if( rateControl < MIN_USER_RATE )
|
||
{
|
||
rateControl = MIN_USER_RATE; // clip to min
|
||
}
|
||
rateRatio = 1.0f / ::g_RateScale[0 - rateControl];
|
||
}
|
||
else
|
||
{
|
||
//--------------------------------
|
||
// INCREASE the rate
|
||
//--------------------------------
|
||
if( rateControl > MAX_USER_RATE )
|
||
{
|
||
rateControl = MAX_USER_RATE; // clip to max
|
||
}
|
||
rateRatio = ::g_RateScale[rateControl];
|
||
}
|
||
|
||
return rateRatio;
|
||
} /* CFrontend::CntrlToRatio */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::Init *
|
||
*-----------------*
|
||
* Description:
|
||
* Init voice dependent variables, call once when object is created+++
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
HRESULT CFontend::Init( CVoiceData* pVoiceDataObj, CFeedChain *pSrcObj, MSVOICEINFO* pVoiceInfo,
|
||
EntropicPitchInfo PitchInfo, bool fNewPhoneSet )
|
||
#else
|
||
HRESULT CFrontend::Init( void* pVoiceDataObj, CFeedChain *pSrcObj, void* pVoiceInfo,
|
||
EntropicPitchInfo PitchInfo, bool fNewPhoneSet )
|
||
#endif
|
||
{
|
||
SPDBG_FUNC( "CFrontend::Init" );
|
||
HRESULT hr = S_OK;
|
||
|
||
m_pSrcObj = pSrcObj;
|
||
m_BasePitch = PitchInfo.BasePitch;
|
||
#ifdef USE_VOICEDATAOBJ
|
||
m_pVoiceDataObj = pVoiceDataObj;
|
||
m_ProsodyGain = ((float)pVoiceInfo->ProsodyGain) / 100.0f;
|
||
m_SampleRate = (float)pVoiceInfo->SampleRate;
|
||
#endif
|
||
|
||
// NOTE: move these to voice data?
|
||
// m_VoiceWPM = pVoiceInfo->Rate;
|
||
// m_PitchRange = pVoiceInfo->PitchRange;
|
||
m_VoiceWPM = 180;
|
||
m_PitchRange = PitchInfo.Range;
|
||
|
||
m_RateRatio_API = m_RateRatio_PROSODY = 1.0f;
|
||
m_fNewPhoneSet = fNewPhoneSet;
|
||
|
||
return hr;
|
||
} /* CFrontend::Init */
|
||
|
||
|
||
|
||
|
||
|
||
static ULONG IPA_to_Allo( WCHAR* pSrc, ALLO_CODE* pDest )
|
||
{
|
||
ULONG iIpa, iAllo, i;
|
||
ULONG gotMatch; // for debugging
|
||
|
||
iIpa = iAllo = 0;
|
||
while( pSrc[iIpa] > 0 )
|
||
{
|
||
gotMatch = false;
|
||
//-----------------------------------------
|
||
// ...then search for single word IPA's
|
||
//-----------------------------------------
|
||
for( i = 0; i < NUMBER_OF_ALLO; i++ )
|
||
{
|
||
if( pSrc[iIpa] == g_IPAToAllo[i] )
|
||
{
|
||
pDest[iAllo] = (ALLO_CODE)i;
|
||
gotMatch = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( gotMatch )
|
||
{
|
||
iAllo++;
|
||
}
|
||
/*else
|
||
{
|
||
// Should NEVER get here. Unsupported IPA unicode!
|
||
// Ignore it and go on.
|
||
}*/
|
||
|
||
//----------------------------------
|
||
// Clip at max length
|
||
//----------------------------------
|
||
if( iAllo >= (SP_MAX_PRON_LENGTH-1) )
|
||
{
|
||
iAllo = SP_MAX_PRON_LENGTH-1;
|
||
break;
|
||
}
|
||
iIpa++;
|
||
}
|
||
return iAllo;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::AlloToUnit *
|
||
*-----------------------*
|
||
* Description:
|
||
* Transform ALLO stream into backend UNIT stream+++
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
HRESULT CFrontend::AlloToUnit( CAlloList *pAllos, UNITINFO *pu )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::AlloToUnit" );
|
||
bool bFirstPass;
|
||
long msPhon, attr;
|
||
ULONG numOfCells;
|
||
CAlloCell *pCurCell, *pNextCell;
|
||
HRESULT hr = S_OK;
|
||
|
||
bFirstPass = true;
|
||
numOfCells = pAllos->GetCount();
|
||
pCurCell = pAllos->GetHeadCell();
|
||
pNextCell = pAllos->GetNextCell();
|
||
while( pCurCell )
|
||
{
|
||
//--------------------------------------
|
||
// Get next allo ID
|
||
//--------------------------------------
|
||
if( pNextCell )
|
||
{
|
||
pu->NextAlloID = (USHORT)pNextCell->m_allo;
|
||
}
|
||
else
|
||
{
|
||
pu->NextAlloID = _SIL_;
|
||
}
|
||
|
||
//--------------------------------------
|
||
// Convert to Whistler phon code
|
||
//--------------------------------------
|
||
attr = 0;
|
||
if( pCurCell->m_ctrlFlags & PRIMARY_STRESS )
|
||
{
|
||
attr |= ALLO_IS_STRESSED;
|
||
}
|
||
hr = m_pVoiceDataObj->AlloToUnit( (short)pCurCell->m_allo, attr, &msPhon );
|
||
if( FAILED(hr) )
|
||
{
|
||
//------------------------
|
||
// allo ID is invalid
|
||
//------------------------
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
pu->PhonID = msPhon;
|
||
pu->AlloID = (USHORT)pCurCell->m_allo;
|
||
pu->flags = 0;
|
||
pu->AlloFeatures = 0;
|
||
pu->ctrlFlags = pCurCell->m_ctrlFlags;
|
||
//--------------------------------------
|
||
// Flag WORD boundary
|
||
//--------------------------------------
|
||
if( pCurCell->m_ctrlFlags & WORD_START )
|
||
{
|
||
pu->flags |= WORD_START_FLAG;
|
||
//----------------------------------------------
|
||
// Remember source word position and length
|
||
//----------------------------------------------
|
||
pu->srcPosition = pCurCell->m_SrcPosition;
|
||
pu->srcLen = pCurCell->m_SrcLen;
|
||
}
|
||
|
||
//----------------------------------------------------
|
||
// Flag SENTENCE boundary on 1st displayable word
|
||
//----------------------------------------------------
|
||
if( bFirstPass && (pCurCell->m_SentenceLen > 0) )
|
||
{
|
||
bFirstPass = false;
|
||
pu->flags |= SENT_START_FLAG;
|
||
//----------------------------------------------
|
||
// Remember source word position and length
|
||
//----------------------------------------------
|
||
pu->sentencePosition = pCurCell->m_SentencePosition;
|
||
pu->sentenceLen = pCurCell->m_SentenceLen;
|
||
}
|
||
|
||
pu->nKnots = KNOTS_PER_PHON;
|
||
/*for( k = 0; k < pu->nKnots; k++ )
|
||
{
|
||
pu->pTime[k] = pCurCell->m_ftTime[k] * m_SampleRate;
|
||
pu->pF0[k] = pCurCell->m_ftPitch[k];
|
||
pu->pAmp[k] = pu->ampRatio;
|
||
}*/
|
||
|
||
//----------------------------
|
||
// Controls and events
|
||
//----------------------------
|
||
pu->user_Volume = pCurCell->m_user_Volume;
|
||
pu->pBMObj = (void*)pCurCell->m_pBMObj;
|
||
pCurCell->m_pBMObj = NULL;
|
||
|
||
//----------------------------------------
|
||
// Pass features for viseme event
|
||
//----------------------------------------
|
||
if( pCurCell->m_ctrlFlags & PRIMARY_STRESS )
|
||
{
|
||
pu->AlloFeatures |= SPVFEATURE_STRESSED;
|
||
}
|
||
if( pCurCell->m_ctrlFlags & EMPHATIC_STRESS )
|
||
{
|
||
pu->AlloFeatures |= SPVFEATURE_EMPHASIS;
|
||
}
|
||
|
||
pu->duration = PITCH_BUF_RES;
|
||
|
||
pu->silenceSource = pCurCell->m_SilenceSource;
|
||
pu++;
|
||
}
|
||
pCurCell = pNextCell;
|
||
pNextCell = pAllos->GetNextCell();
|
||
}
|
||
return hr;
|
||
} /* CFrontend::AlloToUnit */
|
||
#endif
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::PrepareSpeech *
|
||
*--------------------------*
|
||
* Description:
|
||
* Prepare frontend for new speech
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::PrepareSpeech( IEnumSpSentence* pEnumSent, ISpTTSEngineSite *pOutputSite )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::PrepareSpeech" );
|
||
|
||
m_pEnumSent = pEnumSent;
|
||
m_SpeechState = SPEECH_CONTINUE;
|
||
m_CurUnitIndex = m_unitCount = 0;
|
||
m_HasSpeech = false;
|
||
m_pOutputSite = pOutputSite;
|
||
m_fInQuoteProsody = m_fInParenProsody = false;
|
||
m_CurPitchOffs = 0;
|
||
m_CurPitchRange = 1.0;
|
||
} /* CFrontend::PrepareSpeech */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* IsTokenPunct *
|
||
*--------------*
|
||
* Description:
|
||
* Return TRUE if char is , . ! or ?
|
||
*
|
||
********************************************************************** MC ***/
|
||
bool fIsPunctuation( TTSSentItem Item )
|
||
{
|
||
SPDBG_FUNC( "IsTokenPunct" );
|
||
|
||
return ( Item.pItemInfo->Type == eCOMMA ||
|
||
Item.pItemInfo->Type == eSEMICOLON ||
|
||
Item.pItemInfo->Type == eCOLON ||
|
||
Item.pItemInfo->Type == ePERIOD ||
|
||
Item.pItemInfo->Type == eQUESTION ||
|
||
Item.pItemInfo->Type == eEXCLAMATION ||
|
||
Item.pItemInfo->Type == eHYPHEN );
|
||
} /* fIsPunctuation */
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::ToBISymbols *
|
||
*------------------------*
|
||
* Description:
|
||
* Label each word with ToBI prosody notation+++
|
||
*
|
||
********************************************************************** MC ***/
|
||
HRESULT CFrontend::ToBISymbols()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::ToBISymbols" );
|
||
TOBI_PHRASE *pTPhrase;
|
||
long i, cPhrases;
|
||
PROSODY_POS prevPOS, curPOS;
|
||
bool possible_YNQ = false;
|
||
long cTok;
|
||
CFEToken *pTok, *pPrevTok, *pAuxTok;
|
||
bool hasEmph = false;
|
||
SPLISTPOS listPos;
|
||
|
||
|
||
//----------------------------------
|
||
// Get memory for phrase array
|
||
//----------------------------------
|
||
pAuxTok = NULL; // To quiet the compiler
|
||
cTok = m_TokList.GetCount();
|
||
if( cTok )
|
||
{
|
||
pTPhrase = new TOBI_PHRASE[cTok]; // worse case: each token is a phrase
|
||
if( pTPhrase )
|
||
{
|
||
//---------------------------------------------
|
||
// Find sub-phrases from POS
|
||
// For now, detect function/content boundaries
|
||
//---------------------------------------------
|
||
hasEmph = false;
|
||
cPhrases = 0;
|
||
i = 0;
|
||
listPos = m_TokList.GetHeadPosition();
|
||
pTok = m_TokList.GetNext( listPos );
|
||
prevPOS = pTok->m_posClass;
|
||
while( pTok->phon_Str[0] == _SIL_ )
|
||
{
|
||
if( i >= (cTok-1) )
|
||
{
|
||
break;
|
||
}
|
||
i++;
|
||
if( listPos != NULL )
|
||
{
|
||
pTok = m_TokList.GetNext( listPos );
|
||
}
|
||
}
|
||
if( pTok->m_posClass == POS_AUX )
|
||
{
|
||
//---------------------------------
|
||
// Could be a yes/no question
|
||
//---------------------------------
|
||
possible_YNQ = true;
|
||
pAuxTok = pTok;
|
||
}
|
||
pTPhrase[cPhrases].start = i;
|
||
for( ; i < cTok; i++ )
|
||
{
|
||
curPOS = pTok->m_posClass;
|
||
if( (curPOS != prevPOS) && (pTok->phon_Str[0] != _SIL_) )
|
||
{
|
||
pTPhrase[cPhrases].posClass = prevPOS;
|
||
pTPhrase[cPhrases].end = i-1;
|
||
cPhrases++;
|
||
pTPhrase[cPhrases].start = i;
|
||
prevPOS = curPOS;
|
||
}
|
||
if( pTok->user_Emph > 0 )
|
||
{
|
||
hasEmph = true;
|
||
}
|
||
if( listPos != NULL )
|
||
{
|
||
pTok = m_TokList.GetNext( listPos );
|
||
}
|
||
}
|
||
//-------------------------------
|
||
// Complete last phrase
|
||
//-------------------------------
|
||
pTPhrase[cPhrases].posClass = prevPOS;
|
||
pTPhrase[cPhrases].end = i-1;
|
||
cPhrases++;
|
||
|
||
for( i = 0; i < cPhrases; i++ )
|
||
{
|
||
//-------------------------------------------------------
|
||
// Sequence of function words, place a low tone
|
||
// on the LAST word in a func sequence,
|
||
// if there are more than 1 words in the sequence.
|
||
//-------------------------------------------------------
|
||
if( ((pTPhrase[i].posClass == POS_FUNC) || (pTPhrase[i].posClass == POS_AUX)) &&
|
||
(pTPhrase[i].end - pTPhrase[i].start) )
|
||
{
|
||
pTok = (CFEToken*)m_TokList.GetAt( m_TokList.FindIndex( pTPhrase[i].end ));
|
||
if( pTok->m_Accent == K_NOACC )
|
||
{
|
||
pTok->m_Accent = K_LSTAR;
|
||
pTok->m_Accent_Prom = 2;
|
||
pTok->m_AccentSource = ACC_FunctionSeq;
|
||
}
|
||
}
|
||
|
||
//-------------------------------------------------------
|
||
// Sequence of content words, place a high or
|
||
// rising tone, of random prominence,
|
||
// on the FIRST word in the content sequence
|
||
//-------------------------------------------------------
|
||
else if ( ((pTPhrase[i].posClass == POS_CONTENT) || (pTPhrase[i].posClass == POS_UNK)) )
|
||
{
|
||
pTok = (CFEToken*)m_TokList.GetAt( m_TokList.FindIndex( pTPhrase[i].start ));
|
||
if( pTok->m_Accent == K_NOACC )
|
||
{
|
||
pTok->m_Accent = K_HSTAR;
|
||
pTok->m_Accent_Prom = rand() % 5;
|
||
pTok->m_AccentSource = ACC_ContentSeq;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
delete pTPhrase;
|
||
|
||
//-----------------------------------------
|
||
// Now, insert the BOUNDARY tags
|
||
//-----------------------------------------
|
||
listPos = m_TokList.GetHeadPosition();
|
||
pPrevTok = m_TokList.GetNext( listPos );
|
||
for( i = 1; i < cTok; i++ )
|
||
{
|
||
pTok = m_TokList.GetNext( listPos );
|
||
//--------------------------------
|
||
// Place a terminal boundary
|
||
//--------------------------------
|
||
if( pTok->m_TuneBoundaryType != NULL_BOUNDARY )
|
||
{
|
||
switch( pTok->m_TuneBoundaryType )
|
||
{
|
||
case YN_QUEST_BOUNDARY:
|
||
{
|
||
pPrevTok->m_Accent = K_LSTAR;
|
||
pPrevTok->m_Accent_Prom = 10;
|
||
pPrevTok->m_Boundary = K_HMINUSHPERC;
|
||
pPrevTok->m_Boundary_Prom = 10;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_AccentSource == ACC_NoSource )
|
||
{
|
||
pPrevTok->m_AccentSource = ACC_YNQuest;
|
||
}
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_BoundarySource == BND_NoSource )
|
||
{
|
||
pPrevTok->m_BoundarySource = BND_YNQuest;
|
||
}
|
||
//-------------------------------------------------------
|
||
// Accent an aux verb in initial position (possible ynq)
|
||
//-------------------------------------------------------
|
||
if( possible_YNQ )
|
||
{
|
||
pAuxTok->m_Accent = K_HSTAR;
|
||
pAuxTok->m_Accent_Prom = 5;
|
||
pAuxTok->m_AccentSource = ACC_InitialVAux;
|
||
}
|
||
}
|
||
break;
|
||
case WH_QUEST_BOUNDARY:
|
||
case DECLAR_BOUNDARY:
|
||
case EXCLAM_BOUNDARY:
|
||
{
|
||
if (pPrevTok->m_posClass == POS_CONTENT)
|
||
{
|
||
pPrevTok->m_Accent = K_HSTAR;
|
||
pPrevTok->m_Accent_Prom = 4;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_AccentSource == ACC_NoSource )
|
||
{
|
||
pPrevTok->m_AccentSource = ACC_Period;
|
||
}
|
||
}
|
||
pPrevTok->m_Boundary = K_LMINUSLPERC;
|
||
pPrevTok->m_Boundary_Prom = 10;
|
||
//--- Diagnostic
|
||
if( pPrevTok->m_BoundarySource == BND_NoSource )
|
||
{
|
||
pPrevTok->m_BoundarySource = BND_Period;
|
||
}
|
||
}
|
||
break;
|
||
case PHRASE_BOUNDARY:
|
||
{
|
||
if (pPrevTok->m_posClass == POS_CONTENT)
|
||
{
|
||
pPrevTok->m_Accent = K_LHSTAR;
|
||
pPrevTok->m_Accent_Prom = 10;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_AccentSource == ACC_NoSource )
|
||
{
|
||
pPrevTok->m_AccentSource = ACC_Comma;
|
||
}
|
||
}
|
||
pPrevTok->m_Boundary = K_LMINUSHPERC;
|
||
pPrevTok->m_Boundary_Prom = 5;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_BoundarySource == BND_NoSource )
|
||
{
|
||
pPrevTok->m_BoundarySource = BND_Comma;
|
||
}
|
||
}
|
||
break;
|
||
case NUMBER_BOUNDARY:
|
||
{
|
||
pPrevTok->m_Boundary = K_LMINUSHPERC;
|
||
pPrevTok->m_Boundary_Prom = 5;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_BoundarySource == BND_NoSource )
|
||
{
|
||
pPrevTok->m_BoundarySource = BND_NumberTemplate;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
// Use comma for all other boundaries
|
||
if (pPrevTok->m_posClass == POS_CONTENT)
|
||
{
|
||
pPrevTok->m_Accent = K_LHSTAR;
|
||
pPrevTok->m_Accent_Prom = 10;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_AccentSource == ACC_NoSource )
|
||
{
|
||
pPrevTok->m_AccentSource = pTok->m_AccentSource;
|
||
}
|
||
}
|
||
pPrevTok->m_Boundary = K_LMINUSHPERC;
|
||
pPrevTok->m_Boundary_Prom = 5;
|
||
//-- Diagnostic
|
||
if( pPrevTok->m_BoundarySource == BND_NoSource )
|
||
{
|
||
pPrevTok->m_BoundarySource = pTok->m_BoundarySource;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
pPrevTok = pTok;
|
||
}
|
||
|
||
//--------------------------------------------
|
||
// Loop through each word and increase
|
||
// pitch prominence if EMPHASIZED and
|
||
// decrease prominence for all others
|
||
//--------------------------------------------
|
||
if( hasEmph )
|
||
{
|
||
SPLISTPOS listPos;
|
||
|
||
pPrevTok = NULL;
|
||
listPos = m_TokList.GetHeadPosition();
|
||
while( listPos )
|
||
{
|
||
pTok = m_TokList.GetNext( listPos );
|
||
//------------------------------
|
||
// Is this word emphasized?
|
||
//------------------------------
|
||
if( pTok->user_Emph > 0 )
|
||
{
|
||
//------------------------------
|
||
// Add my clever H*+L*<2A> tag
|
||
//------------------------------
|
||
pTok->m_Accent = K_HSTARLSTAR;
|
||
pTok->m_Accent_Prom = 10;
|
||
pTok->m_Boundary = K_NOBND; // Delete any boundary tag here...
|
||
if( pPrevTok )
|
||
{
|
||
pPrevTok->m_Boundary = K_NOBND; // ...or before
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------------------
|
||
// Is non-emphasized word accented?
|
||
//-----------------------------------
|
||
if( (pTok->m_Accent != K_NOACC) && (pTok->m_Accent_Prom > 5) )
|
||
{
|
||
//------------------------------
|
||
// Then clip its prominence at 5
|
||
//------------------------------
|
||
pTok->m_Accent_Prom = 5;
|
||
}
|
||
//------------------------------
|
||
// Is it a boundary?
|
||
//------------------------------
|
||
/*if( (pTok->m_Boundary != K_NOBND) && (pTok->m_Boundary_Prom > 5) )
|
||
{
|
||
//------------------------------
|
||
// Then clip its prominence at 5
|
||
//------------------------------
|
||
pTok->m_Boundary_Prom = 5;
|
||
}*/
|
||
}
|
||
pPrevTok = pTok;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return S_OK;
|
||
} /* ToBISymbols */
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::TokensToAllo *
|
||
*------------------------*
|
||
* Description:
|
||
* Transform TOKENS into ALLOS
|
||
*
|
||
********************************************************************** MC ***/
|
||
HRESULT CFrontend::TokensToAllo( CFETokenList *pTokList, CAlloList *pAllo )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::TokToAllo" );
|
||
CAlloCell *pLastCell;
|
||
long i;
|
||
long cTok;
|
||
CFEToken *pCurToken, *pNextToken, *pPrevTok;
|
||
SPLISTPOS listPos;
|
||
|
||
|
||
pLastCell = pAllo->GetTailCell(); // Get end (silence)
|
||
if( pLastCell )
|
||
{
|
||
pPrevTok = NULL;
|
||
listPos = pTokList->GetHeadPosition();
|
||
pCurToken = pTokList->GetNext( listPos );
|
||
cTok = pTokList->GetCount();
|
||
for( i = 0; i < cTok; i++ )
|
||
{
|
||
//----------------------------
|
||
// Get NEXT word
|
||
//----------------------------
|
||
if( i < (cTok -1) )
|
||
{
|
||
pNextToken = pTokList->GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNextToken = NULL;
|
||
}
|
||
if( pAllo->WordToAllo( pPrevTok, pCurToken, pNextToken, pLastCell ) )
|
||
{
|
||
m_HasSpeech = true;
|
||
}
|
||
//----------------------------
|
||
// Bump the pipeline
|
||
//----------------------------
|
||
pPrevTok = pCurToken;
|
||
pCurToken = pNextToken;
|
||
}
|
||
}
|
||
|
||
return S_OK;
|
||
|
||
} /* CFrontend::TokensToAllo */
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::GetItemControls *
|
||
*----------------------------*
|
||
* Description:
|
||
* Set user control values from Sent Enum item.
|
||
********************************************************************** MC ***/
|
||
void CFrontend::GetItemControls( const SPVSTATE* pXmlState, CFEToken* pToken )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::GetItemControls" );
|
||
|
||
pToken->user_Volume = pXmlState->Volume;
|
||
pToken->user_Rate = pXmlState->RateAdj;
|
||
pToken->user_Pitch = pXmlState->PitchAdj.MiddleAdj;
|
||
pToken->user_Emph = pXmlState->EmphAdj;
|
||
pToken->m_DurScale = CntrlToRatio( pToken->user_Rate );
|
||
if( (pToken->m_DurScale * m_RateRatio_API * m_RateRatio_PROSODY)
|
||
< DISCRETE_BKPT )
|
||
{
|
||
//-- If the total rate is low enough, insert breaks between words
|
||
pToken->m_TermSil = 0.050f /
|
||
(pToken->m_DurScale * m_RateRatio_API * m_RateRatio_PROSODY);
|
||
pToken->m_DurScale = DISCRETE_BKPT;
|
||
}
|
||
else
|
||
{
|
||
pToken->m_TermSil = 0;
|
||
}
|
||
|
||
} /* CFrontend::GetItemControls */
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::GetPOSClass *
|
||
*------------------------*
|
||
* Description:
|
||
* Transform SAPI POS code to func/content/aux class.
|
||
********************************************************************** MC ***/
|
||
PROSODY_POS CFrontend::GetPOSClass( ENGPARTOFSPEECH sapiPOS )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::GetPOSClass" );
|
||
PROSODY_POS posClass;
|
||
|
||
posClass = POS_UNK;
|
||
switch( sapiPOS )
|
||
{
|
||
case MS_Noun:
|
||
case MS_Verb:
|
||
case MS_Adj:
|
||
case MS_Adv:
|
||
case MS_Interjection:
|
||
{
|
||
posClass = POS_CONTENT;
|
||
break;
|
||
}
|
||
case MS_VAux:
|
||
{
|
||
posClass = POS_AUX;
|
||
break;
|
||
}
|
||
case MS_Modifier:
|
||
case MS_Function:
|
||
case MS_Interr:
|
||
case MS_Pron:
|
||
case MS_ObjPron:
|
||
case MS_SubjPron:
|
||
case MS_RelPron:
|
||
case MS_Conj:
|
||
case MS_CConj:
|
||
case MS_Det:
|
||
case MS_Contr:
|
||
case MS_Prep:
|
||
{
|
||
posClass = POS_FUNC;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return posClass;
|
||
} /* CFrontend::GetPOSClass */
|
||
|
||
|
||
|
||
#define QUOTE_HESITATION 100 // Number of msec
|
||
#define PAREN_HESITATION 100 // Number of msec
|
||
#define PAREN_HESITATION_TAIL 100 // Number of msec
|
||
#define EMPH_HESITATION 1 // Number of msec
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::StateQuoteProsody *
|
||
*------------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
bool CFrontend::StateQuoteProsody( CFEToken *pWordTok, TTSSentItem *pSentItem, bool fInsertSil )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::StateQuoteProsody" );
|
||
bool result = false;
|
||
|
||
if( !m_fInParenProsody )
|
||
{
|
||
if( m_fInQuoteProsody )
|
||
{
|
||
//------------------------------
|
||
// Stop quote prosody
|
||
//------------------------------
|
||
m_fInQuoteProsody = false;
|
||
m_CurPitchOffs = 0.0f;
|
||
m_CurPitchRange = 1.0f;
|
||
if( fInsertSil )
|
||
{
|
||
(void)InsertSilenceAtTail( pWordTok, pSentItem, QUOTE_HESITATION );
|
||
pWordTok->m_SilenceSource = SIL_QuoteEnd;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//------------------------------
|
||
// Begin quote prosody
|
||
//------------------------------
|
||
m_fInQuoteProsody = true;
|
||
m_CurPitchOffs = 0.1f;
|
||
m_CurPitchRange = 1.25f;
|
||
if( fInsertSil )
|
||
{
|
||
(void)InsertSilenceAtTail( pWordTok, pSentItem, QUOTE_HESITATION );
|
||
pWordTok->m_SilenceSource = SIL_QuoteStart;
|
||
}
|
||
}
|
||
result = true;
|
||
}
|
||
return result;
|
||
} /* CFrontend::StateQuoteProsody */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::StartParenProsody *
|
||
*------------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
bool CFrontend::StartParenProsody( CFEToken *pWordTok, TTSSentItem *pSentItem, bool fInsertSil )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::StartParenProsody" );
|
||
bool result = false;
|
||
|
||
if( (!m_fInParenProsody) && (!m_fInQuoteProsody) )
|
||
{
|
||
m_CurPitchOffs = -0.2f;
|
||
m_CurPitchRange = 0.75f;
|
||
m_fInParenProsody = true;
|
||
m_RateRatio_PROSODY = 1.25f;
|
||
if( fInsertSil )
|
||
{
|
||
(void)InsertSilenceAtTail( pWordTok, pSentItem, PAREN_HESITATION );
|
||
pWordTok->m_SilenceSource = SIL_ParenStart;
|
||
}
|
||
result = true;
|
||
}
|
||
return result;
|
||
} /* CFrontend::StartParenProsody */
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::EndParenProsody *
|
||
*----------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
bool CFrontend::EndParenProsody( CFEToken *pWordTok, TTSSentItem *pSentItem, bool fInsertSil )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::EndParenProsody" );
|
||
bool result = false;
|
||
|
||
if( m_fInParenProsody )
|
||
{
|
||
m_fInParenProsody = false;
|
||
m_CurPitchOffs = 0.0f;
|
||
m_CurPitchRange = 1.0f;
|
||
m_RateRatio_PROSODY = 1.0f;
|
||
if( fInsertSil )
|
||
{
|
||
(void)InsertSilenceAtTail( pWordTok, pSentItem, PAREN_HESITATION_TAIL );
|
||
pWordTok->m_SilenceSource = SIL_ParenStart;
|
||
}
|
||
result = true;
|
||
}
|
||
return result;
|
||
} /* CFrontend::EndParenProsody */
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::InsertSilenceAtTail *
|
||
*--------------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
SPLISTPOS CFrontend::InsertSilenceAtTail( CFEToken *pWordTok, TTSSentItem *pSentItem, long msec )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::InsertSilenceAtTail" );
|
||
|
||
if( msec > 0 )
|
||
{
|
||
pWordTok->user_Break = msec;
|
||
}
|
||
pWordTok->phon_Len = 1;
|
||
pWordTok->phon_Str[0] = _SIL_;
|
||
pWordTok->srcPosition = pSentItem->ulItemSrcOffset;
|
||
pWordTok->srcLen = pSentItem->ulItemSrcLen;
|
||
pWordTok->tokStr[0] = 0; // There's no orth for Break
|
||
pWordTok->tokLen = 0;
|
||
pWordTok->m_PitchBaseOffs = m_CurPitchOffs;
|
||
pWordTok->m_PitchRangeScale = m_CurPitchRange;
|
||
pWordTok->m_ProsodyDurScale = m_RateRatio_PROSODY;
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
return m_TokList.AddTail( pWordTok );
|
||
} /* CFrontend::InsertSilenceAtTail */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::InsertSilenceAfterPos *
|
||
*-----------------------------------*
|
||
* Description:
|
||
* Insert silence token AFTER 'position'
|
||
*
|
||
********************************************************************** MC ***/
|
||
SPLISTPOS CFrontend::InsertSilenceAfterPos( CFEToken *pWordTok, SPLISTPOS position )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::InsertSilenceAfterPos" );
|
||
|
||
pWordTok->phon_Len = 1;
|
||
pWordTok->phon_Str[0] = _SIL_;
|
||
pWordTok->srcPosition = 0;
|
||
pWordTok->srcLen = 0;
|
||
pWordTok->tokStr[0] = '+'; // punctuation
|
||
pWordTok->tokStr[1] = 0; // delimiter
|
||
pWordTok->tokLen = 1;
|
||
pWordTok->m_PitchBaseOffs = m_CurPitchOffs;
|
||
pWordTok->m_PitchRangeScale = m_CurPitchRange;
|
||
pWordTok->m_ProsodyDurScale = m_RateRatio_PROSODY;
|
||
pWordTok->m_DurScale = 0;
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
return m_TokList.InsertAfter( position, pWordTok );
|
||
} /* CFrontend::InsertSilenceAfterPos */
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::InsertSilenceBeforePos *
|
||
*------------------------------------*
|
||
* Description:
|
||
* Insert silence token BEFORE 'position'
|
||
*
|
||
********************************************************************** MC ***/
|
||
SPLISTPOS CFrontend::InsertSilenceBeforePos( CFEToken *pWordTok, SPLISTPOS position )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::InsertSilenceBeforePos" );
|
||
|
||
pWordTok->phon_Len = 1;
|
||
pWordTok->phon_Str[0] = _SIL_;
|
||
pWordTok->srcPosition = 0;
|
||
pWordTok->srcLen = 0;
|
||
pWordTok->tokStr[0] = '+'; // punctuation
|
||
pWordTok->tokStr[1] = 0; // delimiter
|
||
pWordTok->tokLen = 1;
|
||
pWordTok->m_PitchBaseOffs = m_CurPitchOffs;
|
||
pWordTok->m_PitchRangeScale = m_CurPitchRange;
|
||
pWordTok->m_ProsodyDurScale = m_RateRatio_PROSODY;
|
||
pWordTok->m_DurScale = 0;
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
return m_TokList.InsertBefore( position, pWordTok );
|
||
} /* CFrontend::InsertSilenceBeforePos */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
#define K_ACCENT_PROM ((rand() % 4) + 4)
|
||
#define K_DEACCENT_PROM 5
|
||
#define K_ACCENT K_HSTAR
|
||
#define K_DEACCENT K_NOACC
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::ProsodyTemplates *
|
||
*-----------------------------*
|
||
* Description:
|
||
* Call prosody template function for supported item types.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::ProsodyTemplates( SPLISTPOS clusterPos, TTSSentItem *pSentItem )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::ProsodyTemplates" );
|
||
long cWordCount;
|
||
CFEToken *pClusterTok;
|
||
|
||
switch( pSentItem->pItemInfo->Type )
|
||
{
|
||
//---------------------------------------
|
||
// Numbers
|
||
//---------------------------------------
|
||
case eNUM_ROMAN_NUMERAL:
|
||
case eNUM_ROMAN_NUMERAL_ORDINAL:
|
||
{
|
||
if ( ( (TTSRomanNumeralItemInfo*) pSentItem->pItemInfo )->pNumberInfo->Type != eDATE_YEAR )
|
||
{
|
||
if ( ((TTSNumberItemInfo*)((TTSRomanNumeralItemInfo*)pSentItem->pItemInfo)->pNumberInfo)->pIntegerPart )
|
||
{
|
||
DoIntegerTemplate( &clusterPos,
|
||
(TTSNumberItemInfo*)((TTSRomanNumeralItemInfo*)pSentItem->pItemInfo)->pNumberInfo,
|
||
pSentItem->ulNumWords );
|
||
}
|
||
|
||
if ( ((TTSNumberItemInfo*)((TTSRomanNumeralItemInfo*)pSentItem->pItemInfo)->pNumberInfo)->pDecimalPart )
|
||
{
|
||
DoNumByNumTemplate( &clusterPos,
|
||
((TTSNumberItemInfo*)((TTSRomanNumeralItemInfo*)pSentItem->pItemInfo)->pNumberInfo)->pDecimalPart->ulNumDigits );
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case eNUM_CARDINAL:
|
||
case eNUM_DECIMAL:
|
||
case eNUM_ORDINAL:
|
||
case eNUM_MIXEDFRACTION:
|
||
{
|
||
if ( ( (TTSNumberItemInfo*) pSentItem->pItemInfo )->pIntegerPart )
|
||
{
|
||
cWordCount = DoIntegerTemplate( &clusterPos,
|
||
(TTSNumberItemInfo*) pSentItem->pItemInfo,
|
||
pSentItem->ulNumWords );
|
||
}
|
||
|
||
if( ( (TTSNumberItemInfo*) pSentItem->pItemInfo )->pDecimalPart )
|
||
{
|
||
//-----------------------------------------
|
||
// Skip "point" string...
|
||
//-----------------------------------------
|
||
(void) m_TokList.GetNext( clusterPos );
|
||
//-----------------------------------------
|
||
// ...and do single digit prosody
|
||
//-----------------------------------------
|
||
DoNumByNumTemplate( &clusterPos,
|
||
( (TTSNumberItemInfo*) pSentItem->pItemInfo )->pDecimalPart->ulNumDigits );
|
||
}
|
||
|
||
if ( ( (TTSNumberItemInfo*) pSentItem->pItemInfo )->pFractionalPart )
|
||
{
|
||
//-----------------------------------------
|
||
// Skip "and" string...
|
||
//-----------------------------------------
|
||
pClusterTok = m_TokList.GetNext( clusterPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
//--------------------------------------
|
||
// Force POS for "and" to noun
|
||
// so phrasing rules don't kick in!
|
||
//--------------------------------------
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
pClusterTok->POScode = MS_Noun;
|
||
pClusterTok->m_posClass = POS_CONTENT;
|
||
}
|
||
//-----------------------------------------
|
||
// ...and do fraction prosody
|
||
//-----------------------------------------
|
||
cWordCount = DoFractionTemplate( &clusterPos,
|
||
(TTSNumberItemInfo*) pSentItem->pItemInfo,
|
||
pSentItem->ulNumWords );
|
||
}
|
||
}
|
||
break;
|
||
|
||
//---------------------------------------
|
||
// Fraction
|
||
//---------------------------------------
|
||
case eNUM_FRACTION:
|
||
{
|
||
cWordCount = DoFractionTemplate( &clusterPos,
|
||
(TTSNumberItemInfo*) pSentItem->pItemInfo,
|
||
pSentItem->ulNumWords );
|
||
}
|
||
break;
|
||
|
||
//---------------------------------------
|
||
// Money
|
||
//---------------------------------------
|
||
case eNUM_CURRENCY:
|
||
{
|
||
DoCurrencyTemplate( clusterPos, pSentItem );
|
||
}
|
||
break;
|
||
|
||
//---------------------------------------
|
||
// Phone Numbers
|
||
//---------------------------------------
|
||
case eNUM_PHONENUMBER:
|
||
case eNEWNUM_PHONENUMBER:
|
||
{
|
||
DoPhoneNumberTemplate( clusterPos, pSentItem );
|
||
}
|
||
break;
|
||
|
||
//---------------------------------------
|
||
// Time-of-Day
|
||
//---------------------------------------
|
||
case eTIMEOFDAY:
|
||
{
|
||
DoTODTemplate( clusterPos, pSentItem );
|
||
}
|
||
break;
|
||
|
||
case eELLIPSIS:
|
||
{
|
||
CFEToken *pWordTok;
|
||
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
clusterPos = InsertSilenceAtTail( pWordTok, pSentItem, 0 );
|
||
//clusterPos = m_TokList.GetTailPosition( );
|
||
//clusterPos = InsertSilenceAfterPos( pWordTok, clusterPos );
|
||
pWordTok->m_SilenceSource = SIL_Ellipsis;
|
||
pWordTok->m_TuneBoundaryType = ELLIPSIS_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_Ellipsis;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
} /* CFrontend::ProsodyTemplates */
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoTODTemplate *
|
||
*--------------------------*
|
||
* Description:
|
||
* Prosody template for time-of-day.
|
||
*
|
||
* TODO: Temp kludge - needs more info in TTSTimeOfDayItemInfo
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoTODTemplate( SPLISTPOS clusterPos, TTSSentItem *pSentItem )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoTODTemplate" );
|
||
TTSTimeOfDayItemInfo *pTOD;
|
||
CFEToken *pWordTok;
|
||
CFEToken *pClusterTok;
|
||
SPLISTPOS curPos, nextPos, prevPos;
|
||
|
||
|
||
curPos = nextPos = clusterPos;
|
||
pTOD = (TTSTimeOfDayItemInfo*)&pSentItem->pItemInfo->Type;
|
||
|
||
// Can't do 24 hr because there's no way to tell
|
||
// if it's 1 or 2 digits (18: vs 23:)
|
||
if( !pTOD->fTwentyFourHour )
|
||
{
|
||
//-------------------------------------
|
||
// Get HOUR token
|
||
//-------------------------------------
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
//-------------------------------------
|
||
// Accent hour
|
||
//-------------------------------------
|
||
pClusterTok->m_Accent = K_ACCENT;
|
||
pClusterTok->m_Accent_Prom = K_ACCENT_PROM;
|
||
pClusterTok->m_AccentSource = ACC_TimeOFDay_HR;
|
||
|
||
//---------------------------------
|
||
// Insert SILENCE after hour
|
||
//---------------------------------
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
nextPos = InsertSilenceAfterPos( pWordTok, clusterPos );
|
||
pWordTok->m_SilenceSource = SIL_TimeOfDay_HR;
|
||
pWordTok->m_TuneBoundaryType = NUMBER_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_TimeOFDay_HR;
|
||
pWordTok = NULL;
|
||
//----------------------------
|
||
// Skip last digit
|
||
//----------------------------
|
||
if( clusterPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
}
|
||
if( pTOD->fMinutes )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
//-------------------------------------
|
||
// Accent 1st digit for minutes
|
||
//-------------------------------------
|
||
pClusterTok->m_Accent = K_ACCENT;
|
||
pClusterTok->m_Accent_Prom = K_ACCENT_PROM;
|
||
pClusterTok->m_AccentSource = ACC_TimeOFDay_1stMin;
|
||
}
|
||
|
||
if( pTOD->fTimeAbbreviation )
|
||
{
|
||
curPos = prevPos = m_TokList.GetTailPosition( );
|
||
pClusterTok = m_TokList.GetPrev( prevPos );
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
prevPos = InsertSilenceBeforePos( pWordTok, prevPos );
|
||
pWordTok->m_SilenceSource = SIL_TimeOfDay_AB;
|
||
pWordTok->m_TuneBoundaryType = TOD_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_TimeOFDay_AB;
|
||
pWordTok = NULL;
|
||
//pClusterTok = m_TokList.GetNext( clusterPos );
|
||
//pClusterTok = m_TokList.GetNext( clusterPos );
|
||
}
|
||
//-------------------------------------
|
||
// Accent "M"
|
||
//-------------------------------------
|
||
pClusterTok = m_TokList.GetNext( curPos );
|
||
pClusterTok->m_Accent = K_ACCENT;
|
||
pClusterTok->m_Accent_Prom = K_ACCENT_PROM;
|
||
pClusterTok->m_AccentSource = ACC_TimeOFDay_M;
|
||
}
|
||
}
|
||
} /* CFrontend::DoTODTemplate */
|
||
|
||
|
||
|
||
|
||
|
||
CFEToken *CFrontend::InsertPhoneSilenceAtSpace( SPLISTPOS *pClusterPos,
|
||
BOUNDARY_SOURCE bndSrc,
|
||
SILENCE_SOURCE silSrc )
|
||
{
|
||
CFEToken *pWordTok;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
curPos = nextPos = *pClusterPos;
|
||
//---------------------------------
|
||
// Insert SILENCE after area code
|
||
//---------------------------------
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
nextPos = InsertSilenceBeforePos( pWordTok, curPos );
|
||
pWordTok->m_SilenceSource = silSrc;
|
||
pWordTok->m_TuneBoundaryType = PHONE_BOUNDARY;
|
||
pWordTok->m_BoundarySource = bndSrc;
|
||
pWordTok->m_AccentSource = ACC_PhoneBnd_AREA; // @@@@ ???
|
||
pWordTok = NULL;
|
||
//----------------------------
|
||
// Skip last digit
|
||
//----------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pWordTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
}
|
||
//pWordTok = m_TokList.GetNext( clusterPos );
|
||
//-----------------------------------------
|
||
// Filter and embedded silences
|
||
//-----------------------------------------
|
||
while( (pWordTok->phon_Str[0] == _SIL_) && (nextPos != NULL) )
|
||
{
|
||
curPos = nextPos;
|
||
pWordTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
*pClusterPos = curPos;
|
||
|
||
return pWordTok;
|
||
}
|
||
|
||
|
||
|
||
|
||
void CFrontend::InsertPhoneSilenceAtEnd( BOUNDARY_SOURCE bndSrc,
|
||
SILENCE_SOURCE silSrc )
|
||
{
|
||
CFEToken *pWordTok;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
curPos = m_TokList.GetTailPosition( );
|
||
//---------------------------------
|
||
// Insert SILENCE after area code
|
||
//---------------------------------
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
nextPos = InsertSilenceAfterPos( pWordTok, curPos );
|
||
pWordTok->m_SilenceSource = silSrc;
|
||
pWordTok->m_TuneBoundaryType = PHONE_BOUNDARY;
|
||
pWordTok->m_BoundarySource = bndSrc;
|
||
pWordTok->m_AccentSource = ACC_PhoneBnd_AREA; // @@@@ ???
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoPhoneNumberTemplate *
|
||
*----------------------------------*
|
||
* Description:
|
||
* Prosody template for phone numbers.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoPhoneNumberTemplate( SPLISTPOS clusterPos, TTSSentItem *pSentItem )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoPhoneNumberTemplate" );
|
||
TTSPhoneNumberItemInfo *pFone;
|
||
CFEToken *pClusterTok;
|
||
long cWordCount;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
curPos = nextPos = clusterPos;
|
||
pFone = (TTSPhoneNumberItemInfo*)&pSentItem->pItemInfo->Type;
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
//
|
||
// COUNTRY CODE
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
if( pFone->pCountryCode )
|
||
{
|
||
//-------------------------------------
|
||
// Skip "country" and...
|
||
//-------------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
|
||
//-------------------------------------
|
||
// ...skip "code"
|
||
//-------------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
|
||
cWordCount = DoIntegerTemplate( &nextPos,
|
||
pFone->pCountryCode,
|
||
pSentItem->ulNumWords );
|
||
pClusterTok = InsertPhoneSilenceAtSpace( &nextPos, BND_Phone_COUNTRY, SIL_Phone_COUNTRY );
|
||
}
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
//
|
||
// "One"
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
if( pFone->fOne )
|
||
{
|
||
//-------------------------------------
|
||
// Skip "One"
|
||
//-------------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
//-------------------------------------
|
||
// and add silence
|
||
//-------------------------------------
|
||
pClusterTok = InsertPhoneSilenceAtSpace( &nextPos, BND_Phone_ONE, SIL_Phone_ONE );
|
||
|
||
}
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
//
|
||
// AREA CODE
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
if( pFone->pAreaCode )
|
||
{
|
||
|
||
if( (pFone->fIs800) && nextPos )
|
||
{
|
||
//--------------------------
|
||
// Skip digit
|
||
//--------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
//--------------------------
|
||
// Skip "hundred"
|
||
//--------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
if( nextPos )
|
||
{
|
||
pClusterTok = InsertPhoneSilenceAtSpace( &nextPos, BND_Phone_AREA, SIL_Phone_AREA );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-------------------------------------
|
||
// Skip "area" and...
|
||
//-------------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
//-------------------------------------
|
||
// ...skip "code"
|
||
//-------------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
|
||
DoNumByNumTemplate( &nextPos, pFone->pAreaCode->ulNumDigits );
|
||
if( nextPos )
|
||
{
|
||
pClusterTok = InsertPhoneSilenceAtSpace( &nextPos, BND_Phone_AREA, SIL_Phone_AREA );
|
||
}
|
||
}
|
||
}
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
//
|
||
// Digits
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
unsigned long i;
|
||
|
||
for( i = 0; i < pFone->ulNumGroups; i++ )
|
||
{
|
||
DoNumByNumTemplate( &nextPos, pFone->ppGroups[i]->ulNumDigits );
|
||
if( nextPos )
|
||
{
|
||
pClusterTok = InsertPhoneSilenceAtSpace( &nextPos, BND_Phone_DIGITS, SIL_Phone_DIGITS );
|
||
}
|
||
}
|
||
InsertPhoneSilenceAtEnd( BND_Phone_DIGITS, SIL_Phone_DIGITS );
|
||
} /* CFrontend::DoPhoneNumberTemplate */
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoCurrencyTemplate *
|
||
*-------------------------------*
|
||
* Description:
|
||
* Prosody template for currency.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoCurrencyTemplate( SPLISTPOS clusterPos, TTSSentItem *pSentItem )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoCurrencyTemplate" );
|
||
TTSCurrencyItemInfo *pMoney;
|
||
CFEToken *pWordTok;
|
||
CFEToken *pClusterTok = NULL;
|
||
long cWordCount;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
pMoney = (TTSCurrencyItemInfo*)&pSentItem->pItemInfo->Type;
|
||
|
||
curPos = nextPos = clusterPos;
|
||
if( pMoney->pPrimaryNumberPart->Type != eNUM_CARDINAL )
|
||
{
|
||
return;
|
||
}
|
||
cWordCount = DoIntegerTemplate( &nextPos,
|
||
pMoney->pPrimaryNumberPart,
|
||
pSentItem->ulNumWords );
|
||
curPos = nextPos;
|
||
if( cWordCount > 1 )
|
||
{
|
||
if( pMoney->fQuantifier )
|
||
{
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
}
|
||
}
|
||
if( cWordCount > 1 )
|
||
{
|
||
//---------------------------------
|
||
// Insert SILENCE after "dollars"
|
||
//---------------------------------
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
nextPos = InsertSilenceAfterPos( pWordTok, curPos );
|
||
pWordTok->m_SilenceSource = SIL_Currency_DOLLAR;
|
||
pWordTok->m_TuneBoundaryType = NUMBER_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_Currency_DOLLAR;
|
||
pWordTok = NULL;
|
||
//----------------------------
|
||
// Skip "dollar(s)"
|
||
//----------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
}
|
||
if( pMoney->pSecondaryNumberPart != NULL )
|
||
{
|
||
//----------------------------
|
||
// Skip SILENCE
|
||
//----------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
//----------------------------
|
||
// Skip AND
|
||
//----------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
//--------------------------------------
|
||
// Force POS for "and" to noun
|
||
// so phrasing rules don't kick in!
|
||
//--------------------------------------
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
pClusterTok->POScode = MS_Noun;
|
||
pClusterTok->m_posClass = POS_CONTENT;
|
||
}
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
cWordCount = DoIntegerTemplate( &curPos,
|
||
pMoney->pSecondaryNumberPart,
|
||
cWordCount );
|
||
}
|
||
}
|
||
} /* CFrontend::DoCurrencyTemplate */
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoNumByNumTemplate *
|
||
*---------------------------------*
|
||
* Description:
|
||
* Prosody template for RIGHT hand side of the decimal point.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoNumByNumTemplate( SPLISTPOS *pClusterPos, long cWordCount )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoNumByNumTemplate" );
|
||
CFEToken *pClusterTok;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
curPos = nextPos = *pClusterPos;
|
||
while( cWordCount > 1 )
|
||
{
|
||
pClusterTok = NULL;
|
||
//-------------------------------------------------------------
|
||
// Right side of decimal point - add H* to every other word
|
||
//-------------------------------------------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
|
||
if( pClusterTok )
|
||
{
|
||
pClusterTok->m_Accent = K_ACCENT;
|
||
pClusterTok->m_Accent_Prom = K_ACCENT_PROM;
|
||
pClusterTok->m_AccentSource = ACC_NumByNum;
|
||
}
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
}
|
||
if( cWordCount > 0 )
|
||
{
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
}
|
||
*pClusterPos = nextPos;
|
||
} /* CFrontend::DoNumByNumTemplate */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoFractionTemplate *
|
||
*------------------------------*
|
||
* Description:
|
||
* Prosody template for RIGHT side of the decimal point.
|
||
*
|
||
********************************************************************** MC ***/
|
||
long CFrontend::DoFractionTemplate( SPLISTPOS *pClusterPos, TTSNumberItemInfo *pNInfo, long cWordCount )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoFractionTemplate" );
|
||
CFEToken *pClusterTok;
|
||
TTSFractionItemInfo *pFInfo;
|
||
CFEToken *pWordTok;
|
||
|
||
pFInfo = pNInfo->pFractionalPart;
|
||
|
||
//--- Do Numerator...
|
||
if ( pFInfo->pNumerator->pIntegerPart )
|
||
{
|
||
cWordCount = DoIntegerTemplate( pClusterPos, pFInfo->pNumerator, cWordCount );
|
||
}
|
||
if( pFInfo->pNumerator->pDecimalPart )
|
||
{
|
||
//-----------------------------------------
|
||
// Skip "point" string...
|
||
//-----------------------------------------
|
||
(void) m_TokList.GetNext( *pClusterPos );
|
||
//-----------------------------------------
|
||
// ...and do single digit prosody
|
||
//-----------------------------------------
|
||
DoNumByNumTemplate( pClusterPos, pFInfo->pNumerator->pDecimalPart->ulNumDigits );
|
||
}
|
||
|
||
//--- Special case - a non-standard fraction (e.g. 1/4)
|
||
if( !pFInfo->fIsStandard )
|
||
{
|
||
if( !*pClusterPos )
|
||
{
|
||
*pClusterPos = m_TokList.GetTailPosition( );
|
||
}
|
||
else
|
||
{
|
||
pClusterTok = m_TokList.GetPrev( *pClusterPos );
|
||
}
|
||
}
|
||
|
||
pWordTok = new CFEToken;
|
||
if( pWordTok )
|
||
{
|
||
*pClusterPos = InsertSilenceBeforePos( pWordTok, *pClusterPos );
|
||
pWordTok->m_SilenceSource = SIL_Fractions_NUM;
|
||
pWordTok->m_TuneBoundaryType = NUMBER_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_Frac_Num;
|
||
pWordTok = NULL;
|
||
//----------------------------
|
||
// Skip numerator
|
||
//----------------------------
|
||
if( *pClusterPos != NULL )
|
||
{
|
||
pClusterTok = m_TokList.GetNext( *pClusterPos );
|
||
}
|
||
}
|
||
|
||
//--- Do Denominator...
|
||
if ( pFInfo->pDenominator->pIntegerPart )
|
||
{
|
||
//-----------------------------------------
|
||
// Skip "over" string...
|
||
//-----------------------------------------
|
||
pClusterTok = m_TokList.GetNext( *pClusterPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
//--------------------------------------
|
||
// Force POS for "and" to noun
|
||
// so phrasing rules don't kick in!
|
||
//--------------------------------------
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
pClusterTok->POScode = MS_Noun;
|
||
pClusterTok->m_posClass = POS_CONTENT;
|
||
}
|
||
cWordCount = DoIntegerTemplate( pClusterPos, pFInfo->pDenominator, cWordCount );
|
||
}
|
||
if( pFInfo->pDenominator->pDecimalPart )
|
||
{
|
||
//-----------------------------------------
|
||
// Skip "point" string...
|
||
//-----------------------------------------
|
||
(void) m_TokList.GetNext( *pClusterPos );
|
||
//-----------------------------------------
|
||
// ...and do single digit prosody
|
||
//-----------------------------------------
|
||
DoNumByNumTemplate( pClusterPos, pFInfo->pDenominator->pDecimalPart->ulNumDigits );
|
||
}
|
||
|
||
return cWordCount;
|
||
} /* CFrontend::DoFractionTemplate */
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoIntegerTemplate *
|
||
*------------------------------*
|
||
* Description:
|
||
* Prosody template for LEFT hand side of the decimal point.
|
||
*
|
||
********************************************************************** MC ***/
|
||
long CFrontend::DoIntegerTemplate( SPLISTPOS *pClusterPos, TTSNumberItemInfo *pNInfo, long cWordCount )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoIntegerTemplate" );
|
||
long i;
|
||
CFEToken *pClusterTok;
|
||
CFEToken *pWordTok = NULL;
|
||
SPLISTPOS curPos, nextPos;
|
||
|
||
//------------------------------------------
|
||
// Special currency hack...sorry
|
||
//------------------------------------------
|
||
if( pNInfo->pIntegerPart->fDigitByDigit )
|
||
{
|
||
DoNumByNumTemplate( pClusterPos, pNInfo->pIntegerPart->ulNumDigits );
|
||
return cWordCount - pNInfo->pIntegerPart->ulNumDigits;
|
||
}
|
||
|
||
nextPos = curPos = *pClusterPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
if( pNInfo->fNegative )
|
||
{
|
||
//---------------------------------
|
||
// Skip "NEGATIVE"
|
||
//---------------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
cWordCount--;
|
||
}
|
||
for( i = (pNInfo->pIntegerPart->lNumGroups -1); i >= 0; i-- )
|
||
{
|
||
//------------------------------------
|
||
// Accent 1st digit in group
|
||
//------------------------------------
|
||
pClusterTok->m_Accent = K_ACCENT;
|
||
pClusterTok->m_Accent_Prom = K_ACCENT_PROM;
|
||
pClusterTok->m_AccentSource = ACC_IntegerGroup;
|
||
|
||
|
||
if( pNInfo->pIntegerPart->Groups[i].fHundreds )
|
||
{
|
||
//---------------------------------
|
||
// Skip "X HUNDRED"
|
||
//---------------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
}
|
||
cWordCount--;
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
}
|
||
cWordCount--;
|
||
}
|
||
if( pNInfo->pIntegerPart->Groups[i].fTens )
|
||
{
|
||
//---------------------------------
|
||
// Skip "X-TY"
|
||
//---------------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
}
|
||
cWordCount--;
|
||
}
|
||
if( pNInfo->pIntegerPart->Groups[i].fOnes )
|
||
{
|
||
//---------------------------------
|
||
// Skip "X"
|
||
//---------------------------------
|
||
if( nextPos != NULL )
|
||
{
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
}
|
||
cWordCount--;
|
||
}
|
||
if( pNInfo->pIntegerPart->Groups[i].fQuantifier )
|
||
{
|
||
//---------------------------------
|
||
// Insert SILENCE after quant
|
||
//---------------------------------
|
||
if( pWordTok == NULL )
|
||
{
|
||
pWordTok = new CFEToken;
|
||
}
|
||
if( pWordTok )
|
||
{
|
||
nextPos = InsertSilenceAfterPos( pWordTok, curPos );
|
||
pWordTok->m_SilenceSource = SIL_Integer_Quant;
|
||
pWordTok->m_TuneBoundaryType = NUMBER_BOUNDARY;
|
||
pWordTok->m_BoundarySource = BND_IntegerQuant;
|
||
pWordTok = NULL;
|
||
if( pClusterTok->m_Accent == K_NOACC )
|
||
{
|
||
pClusterTok->m_Accent = K_DEACCENT;
|
||
pClusterTok->m_Accent_Prom = K_DEACCENT_PROM;
|
||
}
|
||
if( nextPos != NULL )
|
||
{
|
||
//------------------------------
|
||
// Skip inserted silence
|
||
//------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
if( nextPos != NULL )
|
||
{
|
||
//-----------------------------------
|
||
// Skip quantifier string
|
||
//-----------------------------------
|
||
curPos = nextPos;
|
||
pClusterTok = m_TokList.GetNext( nextPos );
|
||
}
|
||
cWordCount--;
|
||
}
|
||
}
|
||
}
|
||
|
||
*pClusterPos = curPos;
|
||
return cWordCount;
|
||
} /* CFrontend::DoIntegerTemplate */
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::GetSentenceTokens *
|
||
*------------------------------*
|
||
* Description:
|
||
* Collect Senence Enum tokens.
|
||
* Copy tokens into 'm_TokList' and token count into 'm_cNumOfWords'
|
||
* S_FALSE return means no more input sentences.+++
|
||
*
|
||
********************************************************************** MC ***/
|
||
HRESULT CFrontend::GetSentenceTokens( DIRECTION eDirection )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::GetSentenceTokens" );
|
||
HRESULT eHR = S_OK;
|
||
bool fLastItem = false;
|
||
IEnumSENTITEM *pItemizer;
|
||
TTSSentItem sentItem;
|
||
long tokenIndex;
|
||
CFEToken *pWordTok;
|
||
bool lastWasTerm = false;
|
||
bool lastWasSil = true;
|
||
TUNE_TYPE defaultTune = PHRASE_BOUNDARY;
|
||
long cNumOfItems, cCurItem, cCurWord;
|
||
SPLISTPOS clusterPos, tempPos;
|
||
|
||
m_cNumOfWords = 0;
|
||
pWordTok = NULL;
|
||
clusterPos = NULL;
|
||
|
||
if ( eDirection == eNEXT )
|
||
{
|
||
eHR = m_pEnumSent->Next( &pItemizer );
|
||
}
|
||
else
|
||
{
|
||
eHR = m_pEnumSent->Previous( &pItemizer );
|
||
}
|
||
|
||
|
||
if( eHR == S_OK )
|
||
{
|
||
//--------------------------------------------
|
||
// There's still another sentence to speak
|
||
//--------------------------------------------
|
||
tokenIndex = 0;
|
||
|
||
CItemList& ItemList = ((CSentItemEnum*)pItemizer)->_GetList();
|
||
cNumOfItems = (ItemList.GetCount()) -1;
|
||
cCurItem = 0;
|
||
|
||
//------------------------------------
|
||
// Collect all sentence tokens
|
||
//------------------------------------
|
||
while( (eHR = pItemizer->Next( &sentItem )) == S_OK )
|
||
{
|
||
clusterPos = NULL;
|
||
cCurWord = sentItem.ulNumWords;
|
||
for ( ULONG i = 0; i < sentItem.ulNumWords; i++ )
|
||
{
|
||
//------------------------------
|
||
// Always have a working token
|
||
//------------------------------
|
||
if( pWordTok == NULL )
|
||
{
|
||
pWordTok = new CFEToken;
|
||
}
|
||
if( pWordTok )
|
||
{
|
||
|
||
if( sentItem.pItemInfo->Type & eWORDLIST_IS_VALID )
|
||
{
|
||
//------------------------------------------
|
||
// Get tag values (vol, rate, pitch, etc.)
|
||
//------------------------------------------
|
||
GetItemControls( sentItem.Words[i].pXmlState, pWordTok );
|
||
|
||
//------------------------------------------
|
||
//
|
||
//------------------------------------------
|
||
|
||
//-------------------------------------
|
||
// Switch on token type
|
||
//-------------------------------------
|
||
switch ( sentItem.Words[i].pXmlState->eAction )
|
||
{
|
||
case SPVA_Speak:
|
||
case SPVA_SpellOut:
|
||
{
|
||
//----------------------------------
|
||
// Speak this token
|
||
//----------------------------------
|
||
pWordTok->tokLen = sentItem.Words[i].ulWordLen;
|
||
if( pWordTok->tokLen > (TOKEN_LEN_MAX -1) )
|
||
{
|
||
//-----------------------------------
|
||
// Clip to max string length
|
||
//-----------------------------------
|
||
pWordTok->tokLen = TOKEN_LEN_MAX -1;
|
||
}
|
||
//--------------------------
|
||
// Copy token string
|
||
// Append C-string delimiter
|
||
//--------------------------
|
||
memcpy( &pWordTok->tokStr[0], &sentItem.Words[i].pWordText[0],
|
||
pWordTok->tokLen * sizeof(WCHAR) );
|
||
pWordTok->tokStr[pWordTok->tokLen] = 0; //string delimiter
|
||
|
||
pWordTok->phon_Len = IPA_to_Allo( sentItem.Words[i].pWordPron,
|
||
pWordTok->phon_Str );
|
||
pWordTok->POScode = sentItem.Words[i].eWordPartOfSpeech;
|
||
pWordTok->m_posClass = GetPOSClass( pWordTok->POScode );
|
||
pWordTok->srcPosition = sentItem.ulItemSrcOffset;
|
||
pWordTok->srcLen = sentItem.ulItemSrcLen;
|
||
pWordTok->m_PitchBaseOffs = m_CurPitchOffs;
|
||
pWordTok->m_PitchRangeScale = m_CurPitchRange;
|
||
pWordTok->m_ProsodyDurScale = m_RateRatio_PROSODY;
|
||
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
tempPos = m_TokList.AddTail( pWordTok );
|
||
if( clusterPos == NULL )
|
||
{
|
||
//--------------------------------------
|
||
// Remember where currentitem started
|
||
//--------------------------------------
|
||
clusterPos = tempPos;
|
||
}
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
lastWasTerm = false;
|
||
lastWasSil = false;
|
||
|
||
break;
|
||
}
|
||
|
||
case SPVA_Silence:
|
||
{
|
||
(void)InsertSilenceAtTail( pWordTok, &sentItem, sentItem.Words[i].pXmlState->SilenceMSecs );
|
||
pWordTok->m_SilenceSource = SIL_XML;
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
lastWasTerm = false;
|
||
break;
|
||
}
|
||
|
||
case SPVA_Pronounce:
|
||
{
|
||
pWordTok->tokStr[0] = 0; // There's no orth for Pron types
|
||
pWordTok->tokLen = 0;
|
||
pWordTok->phon_Len = IPA_to_Allo( sentItem.Words[i].pXmlState->pPhoneIds, pWordTok->phon_Str );
|
||
pWordTok->POScode = sentItem.Words[i].eWordPartOfSpeech;
|
||
pWordTok->m_posClass = GetPOSClass( pWordTok->POScode );
|
||
pWordTok->srcPosition = sentItem.ulItemSrcOffset;
|
||
pWordTok->srcLen = sentItem.ulItemSrcLen;
|
||
pWordTok->m_PitchBaseOffs = m_CurPitchOffs;
|
||
pWordTok->m_PitchRangeScale = m_CurPitchRange;
|
||
pWordTok->m_ProsodyDurScale = m_RateRatio_PROSODY;
|
||
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
tempPos = m_TokList.AddTail( pWordTok );
|
||
if( clusterPos == NULL )
|
||
{
|
||
//--------------------------------------
|
||
// Remember where currentitem started
|
||
//--------------------------------------
|
||
clusterPos = tempPos;
|
||
}
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
lastWasTerm = false;
|
||
lastWasSil = false;
|
||
break;
|
||
}
|
||
|
||
case SPVA_Bookmark:
|
||
{
|
||
BOOKMARK_ITEM *pMarker;
|
||
//-------------------------------------------------
|
||
// Create bookmark list if it's not already there
|
||
//-------------------------------------------------
|
||
if( pWordTok->pBMObj == NULL )
|
||
{
|
||
pWordTok->pBMObj = new CBookmarkList;
|
||
}
|
||
if( pWordTok->pBMObj )
|
||
{
|
||
//--------------------------------------------------------
|
||
// Allocate memory for bookmark string
|
||
// (add 1 to length for string delimiter)
|
||
//--------------------------------------------------------
|
||
pWordTok->tokLen = sentItem.Words[i].ulWordLen;
|
||
pMarker = new BOOKMARK_ITEM;
|
||
if (pMarker)
|
||
{
|
||
//----------------------------------------
|
||
// We'll need the text ptr and length
|
||
// when this bookmark event gets posted
|
||
//----------------------------------------
|
||
pMarker->pBMItem = (LPARAM)sentItem.pItemSrcText;
|
||
//--- Punch NULL character into end of bookmark string for Event...
|
||
WCHAR* pTemp = (WCHAR*) sentItem.pItemSrcText + sentItem.ulItemSrcLen;
|
||
*pTemp = 0;
|
||
|
||
//-----------------------------------
|
||
// Add this bookmark to list
|
||
//-----------------------------------
|
||
pWordTok->pBMObj->m_BMList.AddTail( pMarker );
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
default:
|
||
{
|
||
SPDBG_DMSG1( "Unknown SPVSTATE eAction: %d\n", sentItem.Words[i].pXmlState->eAction );
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------------
|
||
// Maybe token is punctuation
|
||
//-----------------------------
|
||
if ( fIsPunctuation(sentItem) )
|
||
{
|
||
TUNE_TYPE bType = NULL_BOUNDARY;
|
||
|
||
switch ( sentItem.pItemInfo->Type )
|
||
{
|
||
case eCOMMA:
|
||
case eSEMICOLON:
|
||
case eCOLON:
|
||
case eHYPHEN:
|
||
if( !lastWasSil )
|
||
{
|
||
bType = PHRASE_BOUNDARY;
|
||
}
|
||
break;
|
||
case ePERIOD:
|
||
if( fLastItem )
|
||
{
|
||
bType = DECLAR_BOUNDARY;
|
||
}
|
||
else
|
||
{
|
||
defaultTune = DECLAR_BOUNDARY;
|
||
}
|
||
break;
|
||
case eQUESTION:
|
||
if( fLastItem )
|
||
{
|
||
bType = YN_QUEST_BOUNDARY;
|
||
}
|
||
else
|
||
{
|
||
defaultTune = YN_QUEST_BOUNDARY;
|
||
}
|
||
break;
|
||
case eEXCLAMATION:
|
||
if( fLastItem )
|
||
{
|
||
bType = EXCLAM_BOUNDARY;
|
||
}
|
||
else
|
||
{
|
||
defaultTune = EXCLAM_BOUNDARY;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if( (bType != NULL_BOUNDARY) && (tokenIndex > 0) )
|
||
{
|
||
pWordTok->m_TuneBoundaryType = bType;
|
||
|
||
pWordTok->phon_Len = 1;
|
||
pWordTok->phon_Str[0] = _SIL_;
|
||
pWordTok->srcPosition = sentItem.ulItemSrcOffset;
|
||
pWordTok->srcLen = sentItem.ulItemSrcLen;
|
||
pWordTok->tokStr[0] = sentItem.pItemSrcText[0]; // punctuation
|
||
pWordTok->tokStr[1] = 0; // delimiter
|
||
pWordTok->tokLen = 1;
|
||
pWordTok->m_SilenceSource = SIL_Term;
|
||
pWordTok->m_TermSil = 0;
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
tempPos = m_TokList.AddTail( pWordTok );
|
||
if( clusterPos == NULL )
|
||
{
|
||
//--------------------------------------
|
||
// Remember where currentitem started
|
||
//--------------------------------------
|
||
clusterPos = tempPos;
|
||
}
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
lastWasTerm = true;
|
||
lastWasSil = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch ( sentItem.pItemInfo->Type )
|
||
{
|
||
//case eSINGLE_QUOTE:
|
||
case eDOUBLE_QUOTE:
|
||
if( StateQuoteProsody( pWordTok, &sentItem, (!fLastItem) & (!lastWasSil) ) )
|
||
{
|
||
if( (!fLastItem) & (!lastWasSil) )
|
||
{
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
}
|
||
lastWasTerm = false;
|
||
lastWasSil = true;
|
||
}
|
||
break;
|
||
|
||
case eOPEN_PARENTHESIS:
|
||
case eOPEN_BRACKET:
|
||
case eOPEN_BRACE:
|
||
if( StartParenProsody( pWordTok, &sentItem, !fLastItem ) )
|
||
{
|
||
if( !fLastItem )
|
||
{
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
}
|
||
lastWasTerm = false;
|
||
lastWasSil = true;
|
||
}
|
||
break;
|
||
|
||
case eCLOSE_PARENTHESIS:
|
||
case eCLOSE_BRACKET:
|
||
case eCLOSE_BRACE:
|
||
if( EndParenProsody( pWordTok, &sentItem, !fLastItem ) )
|
||
{
|
||
if( !fLastItem )
|
||
{
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
}
|
||
lastWasTerm = false;
|
||
lastWasSil = true;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
eHR = E_OUTOFMEMORY;
|
||
break;
|
||
}
|
||
if( --cCurWord == 0 )
|
||
{
|
||
cCurItem++;
|
||
}
|
||
if( cCurItem == cNumOfItems )
|
||
{
|
||
fLastItem = true;
|
||
}
|
||
}
|
||
|
||
//-------------------------------------
|
||
// Tag special word clusters
|
||
//-------------------------------------
|
||
ProsodyTemplates( clusterPos, &sentItem );
|
||
|
||
}
|
||
|
||
pItemizer->Release();
|
||
|
||
//------------------------------------------------------
|
||
// Make sure sentence ends on termination
|
||
//------------------------------------------------------
|
||
if( !lastWasTerm )
|
||
{
|
||
//------------------------
|
||
// Add a comma
|
||
//------------------------
|
||
if( pWordTok == NULL )
|
||
{
|
||
pWordTok = new CFEToken;
|
||
}
|
||
if( pWordTok )
|
||
{
|
||
pWordTok->m_TuneBoundaryType = defaultTune;
|
||
pWordTok->m_BoundarySource = BND_ForcedTerm;
|
||
pWordTok->m_SilenceSource = SIL_Term;
|
||
pWordTok->phon_Len = 1;
|
||
pWordTok->phon_Str[0] = _SIL_;
|
||
pWordTok->srcPosition = sentItem.ulItemSrcOffset;
|
||
pWordTok->srcLen = sentItem.ulItemSrcLen;
|
||
pWordTok->tokStr[0] = '.'; // punctuation
|
||
pWordTok->tokStr[1] = 0; // delimiter
|
||
pWordTok->tokLen = 1;
|
||
// pWordTok->m_BoundarySource = bndSource;
|
||
//----------------------------------
|
||
// Advance to next token
|
||
//----------------------------------
|
||
tempPos = m_TokList.AddTail( pWordTok );
|
||
if( clusterPos == NULL )
|
||
{
|
||
//--------------------------------------
|
||
// Remember where current item started
|
||
//--------------------------------------
|
||
clusterPos = tempPos;
|
||
}
|
||
pWordTok = NULL; // Get a new ptr next time
|
||
tokenIndex++;
|
||
}
|
||
else
|
||
{
|
||
//----------------------------------
|
||
// Bail-out or we'll crash
|
||
//----------------------------------
|
||
eHR = E_OUTOFMEMORY;
|
||
}
|
||
}
|
||
m_cNumOfWords = tokenIndex;
|
||
if( eHR == S_FALSE )
|
||
{
|
||
//----------------------------------
|
||
// Return only errors
|
||
//----------------------------------
|
||
eHR = S_OK;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
eHR = eHR; // !!!!
|
||
}
|
||
|
||
//-------------------------------
|
||
// Cleanup memory allocation
|
||
//-------------------------------
|
||
if( pWordTok != NULL )
|
||
{
|
||
delete pWordTok;
|
||
}
|
||
|
||
//---------------------------------------------------
|
||
// Get sentence position and length for SAPI events
|
||
//---------------------------------------------------
|
||
CalcSentenceLength();
|
||
|
||
return eHR;
|
||
} /* CFrontend::GetSentenceTokens */
|
||
|
||
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::CalcSentenceLength *
|
||
*-------------------------------*
|
||
* Description:
|
||
* Loop thru token list and sum the source char count.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::CalcSentenceLength()
|
||
{
|
||
long firstIndex, lastIndex, lastLen;
|
||
bool firstState;
|
||
SPLISTPOS listPos;
|
||
CFEToken *pWordTok, *pFirstTok = NULL;
|
||
|
||
//---------------------------------------------
|
||
// Find the 1st and last words in sentence
|
||
//---------------------------------------------
|
||
firstIndex = lastIndex = lastLen = 0;
|
||
firstState = true;
|
||
listPos = m_TokList.GetHeadPosition();
|
||
while( listPos )
|
||
{
|
||
pWordTok = m_TokList.GetNext( listPos );
|
||
//-------------------------------------------
|
||
// Look at at displayable words only
|
||
//-------------------------------------------
|
||
if( pWordTok->srcLen > 0 )
|
||
{
|
||
if( firstState )
|
||
{
|
||
firstState = false;
|
||
firstIndex = pWordTok->srcPosition;
|
||
pFirstTok = pWordTok;
|
||
}
|
||
else
|
||
{
|
||
lastIndex = pWordTok->srcPosition;
|
||
lastLen = pWordTok->srcLen;
|
||
}
|
||
}
|
||
}
|
||
//--------------------------------------------------
|
||
// Calculate sentence length for head list item
|
||
//--------------------------------------------------
|
||
if( pFirstTok )
|
||
{
|
||
pFirstTok->sentencePosition = firstIndex; // Sentence starts here...
|
||
pFirstTok->sentenceLen = (lastIndex - firstIndex) + lastLen; // ...and this is the length
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DisposeUnits *
|
||
*-------------------------*
|
||
* Description:
|
||
* Delete memory allocated to 'm_pUnits'.
|
||
* Clean-up memory for Bookmarks
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
void CFrontend::DisposeUnits( )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DisposeUnits" );
|
||
ULONG unitIndex;
|
||
|
||
if( m_pUnits )
|
||
{
|
||
//-----------------------------------------
|
||
// Clean-up Bookmark memory allocation
|
||
//-----------------------------------------
|
||
|
||
for( unitIndex = m_CurUnitIndex; unitIndex < m_unitCount; unitIndex++)
|
||
{
|
||
if( m_pUnits[unitIndex].pBMObj != NULL )
|
||
{
|
||
//---------------------------------------
|
||
// Dispose bookmark list
|
||
//---------------------------------------
|
||
delete m_pUnits[unitIndex].pBMObj;
|
||
m_pUnits[unitIndex].pBMObj = NULL;
|
||
}
|
||
}
|
||
delete m_pUnits;
|
||
m_pUnits = NULL;
|
||
}
|
||
} /* CFrontend::DisposeUnits */
|
||
#endif
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::ParseNextSentence *
|
||
*------------------------------*
|
||
* Description:
|
||
* Fill 'm_pUnits' array with next sentence.
|
||
* If there's no more input text,
|
||
* return with 'm_SpeechState' set to SPEECH_DONE +++
|
||
*
|
||
********************************************************************** MC ***/
|
||
HRESULT CFrontend::ParseSentence( DIRECTION eDirection )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::ParseNextSentence" );
|
||
HRESULT hr = S_OK;
|
||
|
||
//-----------------------------------------------------
|
||
// If there's a previous unit array, free its memory
|
||
//-----------------------------------------------------
|
||
#ifdef USE_VOICEDATAOBJ
|
||
DisposeUnits();
|
||
#endif
|
||
m_CurUnitIndex = 0;
|
||
m_unitCount = 0;
|
||
DeleteTokenList();
|
||
#ifdef USE_VOICEDATAOBJ
|
||
m_pUnits = NULL;
|
||
#endif
|
||
//-----------------------------------------------------
|
||
// If there's a previous allo array, free its memory
|
||
//-----------------------------------------------------
|
||
if( m_pAllos )
|
||
{
|
||
delete m_pAllos;
|
||
m_pAllos = NULL;
|
||
}
|
||
|
||
//-----------------------------------------------------
|
||
// Fill token array with next sentence
|
||
// Skip empty sentences.
|
||
// NOTE: includes non-speaking items
|
||
//-----------------------------------------------------
|
||
do
|
||
{
|
||
hr = GetSentenceTokens( eDirection );
|
||
} while( (hr == S_OK) && (m_cNumOfWords == 0) );
|
||
|
||
if( hr == S_OK )
|
||
{
|
||
//--------------------------------------------
|
||
// Prepare word emphasis
|
||
//--------------------------------------------
|
||
DoWordAccent();
|
||
|
||
//--------------------------------------------
|
||
// Word level prosodic lables
|
||
//--------------------------------------------
|
||
DoPhrasing();
|
||
ToBISymbols();
|
||
|
||
//--------------------------------------------
|
||
// Convert tokens to allo list
|
||
//--------------------------------------------
|
||
m_pAllos = new CAlloList;
|
||
if (m_pAllos == NULL)
|
||
{
|
||
//-----------------------
|
||
// Out of memory
|
||
//-----------------------
|
||
hr = E_FAIL;
|
||
}
|
||
if( SUCCEEDED(hr) )
|
||
{
|
||
//--------------------------------
|
||
// Convert word to allo strteam
|
||
//-------------------------------
|
||
TokensToAllo( &m_TokList, m_pAllos );
|
||
|
||
//----------------------------
|
||
// Tag sentence syllables
|
||
//----------------------------
|
||
m_SyllObj.TagSyllables( m_pAllos );
|
||
|
||
//--------------------------------------------
|
||
// Dispose token array, no longer needed
|
||
//--------------------------------------------
|
||
DeleteTokenList();
|
||
|
||
//--------------------------------------------
|
||
// Create the unit array
|
||
// NOTE:
|
||
//--------------------------------------------
|
||
#ifdef USE_VOICEDATAOBJ
|
||
hr = UnitLookahead ();
|
||
if( hr == S_OK )
|
||
{
|
||
//--------------------------------------------
|
||
// Compute allo durations
|
||
//--------------------------------------------
|
||
UnitToAlloDur( m_pAllos, m_pUnits );
|
||
m_DurObj.AlloDuration( m_pAllos, m_RateRatio_API );
|
||
//--------------------------------------------
|
||
// Modulate allo pitch
|
||
//--------------------------------------------
|
||
m_PitchObj.AlloPitch( m_pAllos, m_BasePitch, m_PitchRange );
|
||
}
|
||
#else
|
||
m_DurObj.AlloDuration( m_pAllos, m_RateRatio_API );
|
||
m_PitchObj.AlloPitch( m_pAllos, m_BasePitch, m_PitchRange );
|
||
#endif
|
||
|
||
}
|
||
#ifdef USE_VOICEDATAOBJ
|
||
if( hr == S_OK )
|
||
{
|
||
AlloToUnitPitch( m_pAllos, m_pUnits );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
if( FAILED(hr) )
|
||
{
|
||
//------------------------------------------
|
||
// Either the input text is dry or we failed.
|
||
// Try to fail gracefully
|
||
// 1 - Clean up memory
|
||
// 2 - End the speech
|
||
//------------------------------------------
|
||
if( m_pAllos )
|
||
{
|
||
delete m_pAllos;
|
||
m_pAllos = 0;
|
||
}
|
||
DeleteTokenList();
|
||
#ifdef USE_VOICEDATAOBJ
|
||
DisposeUnits();
|
||
#endif
|
||
m_SpeechState = SPEECH_DONE;
|
||
}
|
||
else if( hr == S_FALSE )
|
||
{
|
||
//---------------------------------
|
||
// No more input text
|
||
//---------------------------------
|
||
hr = S_OK;
|
||
m_SpeechState = SPEECH_DONE;
|
||
}
|
||
|
||
|
||
return hr;
|
||
} /* CFrontend::ParseNextSentence */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::UnitLookahead *
|
||
*--------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
HRESULT CFrontend::UnitLookahead ()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::UnitLookahead" );
|
||
HRESULT hr = S_OK;
|
||
UNIT_CVT *pPhon2Unit = NULL;
|
||
ULONG i;
|
||
|
||
m_unitCount = m_pAllos->GetCount();
|
||
|
||
m_pUnits = new UNITINFO[m_unitCount];
|
||
if( m_pUnits )
|
||
{
|
||
pPhon2Unit = new UNIT_CVT[m_unitCount];
|
||
if( pPhon2Unit )
|
||
{
|
||
//--------------------------------------------
|
||
// Convert allo list to unit array
|
||
//--------------------------------------------
|
||
memset( m_pUnits, 0, m_unitCount * sizeof(UNITINFO) );
|
||
hr = AlloToUnit( m_pAllos, m_pUnits );
|
||
|
||
if( SUCCEEDED(hr) )
|
||
{
|
||
//--------------------------------------------
|
||
// Initialize UNIT_CVT
|
||
//--------------------------------------------
|
||
for( i = 0; i < m_unitCount; i++ )
|
||
{
|
||
pPhon2Unit[i].PhonID = m_pUnits[i].PhonID;
|
||
pPhon2Unit[i].flags = m_pUnits[i].flags;
|
||
}
|
||
//--------------------------------------------
|
||
// Compute triphone IDs
|
||
//--------------------------------------------
|
||
hr = m_pVoiceDataObj->GetUnitIDs( pPhon2Unit, m_unitCount );
|
||
|
||
if( SUCCEEDED(hr) )
|
||
{
|
||
//--------------------------------------------
|
||
// Copy UNIT_CVT to UNITINFO
|
||
//--------------------------------------------
|
||
for( i = 0; i < m_unitCount; i++ )
|
||
{
|
||
m_pUnits[i].UnitID = pPhon2Unit[i].UnitID;
|
||
m_pUnits[i].SenoneID = pPhon2Unit[i].SenoneID;
|
||
m_pUnits[i].duration = pPhon2Unit[i].Dur;
|
||
m_pUnits[i].amp = pPhon2Unit[i].Amp;
|
||
m_pUnits[i].ampRatio = pPhon2Unit[i].AmpRatio;
|
||
strcpy( m_pUnits[i].szUnitName, pPhon2Unit[i].szUnitName );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------
|
||
// Can't get unit ID's
|
||
//-----------------------
|
||
delete m_pUnits;
|
||
m_pUnits = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------
|
||
// Can't convert allos
|
||
//-----------------------
|
||
delete m_pUnits;
|
||
m_pUnits = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------
|
||
// Out of memory
|
||
//-----------------------
|
||
delete m_pUnits;
|
||
m_pUnits = NULL;
|
||
hr = E_FAIL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//-----------------------
|
||
// Out of memory
|
||
//-----------------------
|
||
hr = E_FAIL;
|
||
}
|
||
|
||
//------------------------------
|
||
// Cleanup before exit
|
||
//------------------------------
|
||
if( pPhon2Unit )
|
||
{
|
||
delete pPhon2Unit;
|
||
}
|
||
|
||
|
||
return hr;
|
||
} /* CFrontend::UnitLookahead */
|
||
#endif
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::UnitToAlloDur *
|
||
*--------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::UnitToAlloDur( CAlloList *pAllos, UNITINFO *pu )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::UnitToAlloDur" );
|
||
CAlloCell *pCurCell;
|
||
|
||
pCurCell = pAllos->GetHeadCell();
|
||
while( pCurCell )
|
||
{
|
||
pCurCell->m_UnitDur = pu->duration;
|
||
pu++;
|
||
pCurCell = pAllos->GetNextCell();
|
||
}
|
||
} /* CFrontend::UnitToAlloDur */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::AlloToUnitPitch *
|
||
*----------------------------*
|
||
* Description:
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
void CFrontend::AlloToUnitPitch( CAlloList *pAllos, UNITINFO *pu )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::AlloToUnitPitch" );
|
||
ULONG k;
|
||
CAlloCell *pCurCell;
|
||
|
||
pCurCell = pAllos->GetHeadCell();
|
||
while( pCurCell )
|
||
{
|
||
pu->duration = pCurCell->m_ftDuration;
|
||
for( k = 0; k < pu->nKnots; k++ )
|
||
{
|
||
pu->pTime[k] = pCurCell->m_ftTime[k] * m_SampleRate;
|
||
pu->pF0[k] = pCurCell->m_ftPitch[k];
|
||
pu->pAmp[k] = pu->ampRatio;
|
||
}
|
||
pu++;
|
||
pCurCell = pAllos->GetNextCell();
|
||
}
|
||
} /* CFrontend::AlloToUnitPitch */
|
||
#endif
|
||
|
||
/*****************************************************************************
|
||
* CAlloList::DeleteTokenList *
|
||
*----------------------------*
|
||
* Description:
|
||
* Remove every item in link list.
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DeleteTokenList()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DeleteTokenList" );
|
||
CFEToken *pTok;
|
||
|
||
while( !m_TokList.IsEmpty() )
|
||
{
|
||
pTok = (CFEToken*)m_TokList.RemoveHead();
|
||
delete pTok;
|
||
}
|
||
|
||
} /* CFrontend::DeleteTokenList */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* AdjustQuestTune *
|
||
*-----------------*
|
||
* Description:
|
||
* Adjust termination for either YN or WH sentence tune.
|
||
*
|
||
********************************************************************** MC ***/
|
||
static void AdjustQuestTune( CFEToken *pTok, bool fIsYesNo )
|
||
{
|
||
SPDBG_FUNC( "AdjustQuestTune" );
|
||
if ( pTok->m_TuneBoundaryType > NULL_BOUNDARY )
|
||
{
|
||
if( (pTok->m_TuneBoundaryType == YN_QUEST_BOUNDARY) ||
|
||
(pTok->m_TuneBoundaryType == WH_QUEST_BOUNDARY) )
|
||
{
|
||
//------------------------------------
|
||
// Is this a yes/no question phrase
|
||
//------------------------------------
|
||
if( fIsYesNo )
|
||
{
|
||
//------------------------------------------
|
||
// Put out a final yes/no question marker
|
||
//------------------------------------------
|
||
pTok->m_TuneBoundaryType = YN_QUEST_BOUNDARY;
|
||
pTok->m_BoundarySource = BND_YNQuest;
|
||
}
|
||
else
|
||
{
|
||
|
||
//------------------------------------------------------------------------
|
||
// Use declarative phrase marker (for WH questions)
|
||
//------------------------------------------------------------------------
|
||
pTok->m_TuneBoundaryType = WH_QUEST_BOUNDARY;
|
||
pTok->m_BoundarySource = BND_WHQuest;
|
||
}
|
||
}
|
||
}
|
||
} /* AdjustQuestTune */
|
||
|
||
|
||
typedef enum
|
||
{
|
||
p_Interj,
|
||
P_Adv,
|
||
P_Verb,
|
||
P_Adj,
|
||
P_Noun,
|
||
PRIORITY_SIZE,
|
||
} CONTENT_PRIORITY;
|
||
|
||
#define NO_POSITION -1
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::ExclamEmph *
|
||
*-----------------------*
|
||
* Description:
|
||
* Find a likely word to emph if sentence has exclamation
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::ExclamEmph()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::ExclamEmph" );
|
||
CFEToken *pCur_Tok;
|
||
SPLISTPOS listPos, targetPos, curPos, contentPos[PRIORITY_SIZE];
|
||
long cContent, cWords;
|
||
long i;
|
||
|
||
for(i = 0; i < PRIORITY_SIZE; i++ )
|
||
{
|
||
contentPos[i] = (SPLISTPOS)NO_POSITION;
|
||
}
|
||
|
||
listPos = m_TokList.GetTailPosition();
|
||
pCur_Tok = m_TokList.GetNext( listPos );
|
||
|
||
//---------------------------------------------------
|
||
// First, check last token fors an exclamation
|
||
//---------------------------------------------------
|
||
if( pCur_Tok->m_TuneBoundaryType == EXCLAM_BOUNDARY )
|
||
{
|
||
//-----------------------------------------------------
|
||
// Then, see if there's only one content word
|
||
// in the sentence
|
||
//-----------------------------------------------------
|
||
cContent = cWords = 0;
|
||
listPos = m_TokList.GetHeadPosition();
|
||
while( listPos )
|
||
{
|
||
curPos = listPos;
|
||
pCur_Tok = m_TokList.GetNext( listPos );
|
||
if( pCur_Tok->m_posClass == POS_CONTENT )
|
||
{
|
||
cContent++;
|
||
cWords++;
|
||
if( cContent == 1)
|
||
{
|
||
targetPos = curPos;
|
||
}
|
||
//--------------------------------------------------------
|
||
// Fill the famous Azara Content Prominence Hierarchy (ACPH)
|
||
//--------------------------------------------------------
|
||
if( (pCur_Tok->POScode == MS_Noun) && (contentPos[P_Noun] == (SPLISTPOS)NO_POSITION) )
|
||
{
|
||
contentPos[P_Noun] = curPos;
|
||
}
|
||
else if( (pCur_Tok->POScode == MS_Verb) && (contentPos[P_Verb] == (SPLISTPOS)NO_POSITION) )
|
||
{
|
||
contentPos[P_Verb] = curPos;
|
||
}
|
||
else if( (pCur_Tok->POScode == MS_Adj) && (contentPos[P_Adj] == (SPLISTPOS)NO_POSITION) )
|
||
{
|
||
contentPos[P_Adj] = curPos;
|
||
}
|
||
else if( (pCur_Tok->POScode == MS_Adv) && (contentPos[P_Adv] == (SPLISTPOS)NO_POSITION) )
|
||
{
|
||
contentPos[P_Adv] = curPos;
|
||
}
|
||
else if( (pCur_Tok->POScode == MS_Interjection) && (contentPos[p_Interj] == (SPLISTPOS)NO_POSITION) )
|
||
{
|
||
contentPos[p_Interj] = curPos;
|
||
}
|
||
}
|
||
else if( pCur_Tok->m_posClass == POS_FUNC )
|
||
{
|
||
cWords++;
|
||
if( cWords == 1)
|
||
{
|
||
targetPos = curPos;
|
||
}
|
||
}
|
||
}
|
||
|
||
//--------------------------------------------
|
||
// If there's only one word or content word
|
||
// then EMPHASIZE it
|
||
//--------------------------------------------
|
||
if( (cContent == 1) || (cWords == 1) )
|
||
{
|
||
pCur_Tok = m_TokList.GetNext( targetPos );
|
||
pCur_Tok->user_Emph = 1;
|
||
}
|
||
else if( cContent > 1 )
|
||
{
|
||
for(i = 0; i < PRIORITY_SIZE; i++ )
|
||
{
|
||
if( contentPos[i] != (SPLISTPOS)NO_POSITION )
|
||
{
|
||
targetPos = contentPos[i];
|
||
break;
|
||
}
|
||
}
|
||
pCur_Tok = m_TokList.GetNext( targetPos );
|
||
pCur_Tok->user_Emph = 1;
|
||
}
|
||
}
|
||
} //ExclamEmph
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoWordAccent *
|
||
*-------------------------*
|
||
* Description:
|
||
* Prepare word for emphasis
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoWordAccent()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoWordAccent" );
|
||
long cNumOfWords;
|
||
long iCurWord;
|
||
CFEToken *pCur_Tok, *pNext_Tok, *pPrev_Tok, *pTempTok;
|
||
SPLISTPOS listPos;
|
||
TUNE_TYPE cur_Bnd, prev_Bnd;
|
||
|
||
//-----------------------------
|
||
// Initilize locals
|
||
//-----------------------------
|
||
cNumOfWords = m_TokList.GetCount();
|
||
if( cNumOfWords > 0 )
|
||
{
|
||
ExclamEmph();
|
||
prev_Bnd = PHRASE_BOUNDARY; // Assume start of sentence
|
||
//-------------------------------------
|
||
// Fill the token pipeline
|
||
//-------------------------------------
|
||
listPos = m_TokList.GetHeadPosition();
|
||
|
||
//-- Previous
|
||
pPrev_Tok = NULL;
|
||
|
||
//-- Current
|
||
pCur_Tok = m_TokList.GetNext( listPos );
|
||
|
||
//-- Next
|
||
if( listPos )
|
||
{
|
||
pNext_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext_Tok = NULL;
|
||
}
|
||
|
||
//-----------------------------------
|
||
// Step through entire word array
|
||
// (skip last)
|
||
//-----------------------------------
|
||
for( iCurWord = 0; iCurWord < (cNumOfWords -1); iCurWord++ )
|
||
{
|
||
cur_Bnd = pCur_Tok->m_TuneBoundaryType;
|
||
if( pCur_Tok->user_Emph > 0 )
|
||
{
|
||
//-----------------------------------
|
||
// Current word is emphasized
|
||
//-----------------------------------
|
||
if( prev_Bnd == NULL_BOUNDARY )
|
||
{
|
||
pTempTok = new CFEToken;
|
||
if( pTempTok )
|
||
{
|
||
pTempTok->user_Break = EMPH_HESITATION;
|
||
pTempTok->m_TuneBoundaryType = NULL_BOUNDARY;
|
||
pTempTok->phon_Len = 1;
|
||
pTempTok->phon_Str[0] = _SIL_;
|
||
pTempTok->srcPosition = pCur_Tok->srcPosition;
|
||
pTempTok->srcLen = pCur_Tok->srcLen;
|
||
pTempTok->tokStr[0] = 0; // There's no orth for Break
|
||
pTempTok->tokLen = 0;
|
||
pTempTok->m_TermSil = 0;
|
||
pTempTok->m_SilenceSource = SIL_Emph;
|
||
pTempTok->m_DurScale = 0;
|
||
if( pPrev_Tok )
|
||
{
|
||
//pTempTok->m_DurScale = pPrev_Tok->m_DurScale;
|
||
pTempTok->m_ProsodyDurScale = pPrev_Tok->m_ProsodyDurScale;
|
||
pTempTok->user_Volume = pPrev_Tok->user_Volume;
|
||
}
|
||
else
|
||
{
|
||
//pTempTok->m_DurScale = 1.0f;
|
||
pTempTok->m_ProsodyDurScale = 1.0f;
|
||
}
|
||
|
||
m_TokList.InsertBefore( m_TokList.FindIndex( iCurWord ), pTempTok );
|
||
pCur_Tok = pTempTok;
|
||
m_cNumOfWords++;
|
||
cNumOfWords++;
|
||
iCurWord++;
|
||
}
|
||
}
|
||
}
|
||
//------------------------------
|
||
// Shift the token pipeline
|
||
//------------------------------
|
||
prev_Bnd = cur_Bnd;
|
||
pPrev_Tok = pCur_Tok;
|
||
pCur_Tok = pNext_Tok;
|
||
if( listPos )
|
||
{
|
||
pNext_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext_Tok = NULL;
|
||
}
|
||
|
||
}
|
||
}
|
||
} /* CFrontend::DoWordAccent */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::DoPhrasing *
|
||
*-----------------------*
|
||
* Description:
|
||
* Insert sub-phrase boundaries into word token array
|
||
*
|
||
********************************************************************** MC ***/
|
||
void CFrontend::DoPhrasing()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::DoPhrasing" );
|
||
long iCurWord;
|
||
CFEToken *pCur_Tok, *pNext_Tok, *pNext2_Tok, *pNext3_Tok, *pTempTok, *pPrev_Tok;
|
||
ENGPARTOFSPEECH cur_POS, next_POS, next2_POS, next3_POS, prev_POS;
|
||
bool fNext_IsPunct, fNext2_IsPunct, fNext3_IsPunct;
|
||
bool fIsYesNo, fMaybeWH, fHasDet, fInitial_Adv, fIsShortSent, fIsAlphaWH;
|
||
TUNE_TYPE cur_Bnd, prev_Punct;
|
||
long punctDistance;
|
||
long cNumOfWords;
|
||
SPLISTPOS listPos;
|
||
BOUNDARY_SOURCE bndNum;
|
||
ACCENT_SOURCE accNum;
|
||
|
||
//-----------------------------
|
||
// Initialize locals
|
||
//-----------------------------
|
||
cNumOfWords = m_TokList.GetCount();
|
||
if( cNumOfWords > 0 )
|
||
{
|
||
cur_Bnd = NULL_BOUNDARY;
|
||
prev_POS = MS_Unknown;
|
||
prev_Punct = PHRASE_BOUNDARY; // Assume start of sentence
|
||
punctDistance = 0; // To quiet the compiler...
|
||
fIsYesNo = fMaybeWH = fHasDet = fIsAlphaWH = false; // To quiet the compiler...
|
||
fMaybeWH = false;
|
||
fInitial_Adv = false;
|
||
if (cNumOfWords <= 9)
|
||
{
|
||
fIsShortSent = true;
|
||
}
|
||
else
|
||
{
|
||
fIsShortSent = false;
|
||
}
|
||
|
||
//-------------------------------------
|
||
// Fill the token pipeline
|
||
//-------------------------------------
|
||
listPos = m_TokList.GetHeadPosition();
|
||
//-- Previous
|
||
pPrev_Tok = NULL;
|
||
//-- Current
|
||
pCur_Tok = m_TokList.GetNext( listPos );
|
||
//-- Next
|
||
if( listPos )
|
||
{
|
||
pNext_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext_Tok = NULL;
|
||
}
|
||
//-- Next 2
|
||
if( listPos )
|
||
{
|
||
pNext2_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext2_Tok = NULL;
|
||
}
|
||
//-- Next 3
|
||
if( listPos )
|
||
{
|
||
pNext3_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext3_Tok = NULL;
|
||
}
|
||
|
||
//-----------------------------------
|
||
// Step through entire word array
|
||
// (skip last)
|
||
//-----------------------------------
|
||
for( iCurWord = 0; iCurWord < (cNumOfWords -1); iCurWord++ )
|
||
{
|
||
bndNum = BND_NoSource;
|
||
accNum = ACC_NoSource;
|
||
|
||
if( (prev_Punct > NULL_BOUNDARY) && (prev_Punct < SUB_BOUNDARY_1) )
|
||
{
|
||
punctDistance = 1;
|
||
fIsYesNo = true;
|
||
fMaybeWH = false;
|
||
fHasDet = false;
|
||
fIsAlphaWH = false;
|
||
}
|
||
else
|
||
{
|
||
punctDistance++;
|
||
}
|
||
//------------------------------------
|
||
// Process new word
|
||
//------------------------------------
|
||
cur_POS = pCur_Tok->POScode;
|
||
cur_Bnd = NULL_BOUNDARY;
|
||
//------------------------------------
|
||
// Don't depend on POS to detect
|
||
// "WH" question
|
||
//------------------------------------
|
||
if( ((pCur_Tok->tokStr[0] == 'W') || (pCur_Tok->tokStr[0] == 'w')) &&
|
||
((pCur_Tok->tokStr[1] == 'H') || (pCur_Tok->tokStr[1] == 'h')) )
|
||
{
|
||
fIsAlphaWH = true;
|
||
}
|
||
else
|
||
{
|
||
fIsAlphaWH = false;
|
||
}
|
||
|
||
//------------------------------------
|
||
// Look ahead to NEXT word
|
||
//------------------------------------
|
||
next_POS = pNext_Tok->POScode;
|
||
if( pNext_Tok->m_TuneBoundaryType != NULL_BOUNDARY )
|
||
{
|
||
fNext_IsPunct = true;
|
||
}
|
||
else
|
||
{
|
||
fNext_IsPunct = false;
|
||
}
|
||
|
||
//------------------------------------
|
||
// Look ahead 2 positions
|
||
//------------------------------------
|
||
if( pNext2_Tok )
|
||
{
|
||
next2_POS = pNext2_Tok->POScode;
|
||
if( pNext2_Tok->m_TuneBoundaryType != NULL_BOUNDARY )
|
||
{
|
||
fNext2_IsPunct = true;
|
||
}
|
||
else
|
||
{
|
||
fNext2_IsPunct = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
next2_POS = MS_Unknown;
|
||
fNext2_IsPunct = false;
|
||
}
|
||
|
||
//------------------------------------
|
||
// Look ahead 3 positions
|
||
//------------------------------------
|
||
if( pNext3_Tok )
|
||
{
|
||
next3_POS = pNext3_Tok->POScode;
|
||
if( pNext3_Tok->m_TuneBoundaryType != NULL_BOUNDARY )
|
||
{
|
||
fNext3_IsPunct = true;
|
||
}
|
||
else
|
||
{
|
||
fNext3_IsPunct = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
next3_POS = MS_Unknown;
|
||
fNext3_IsPunct = false;
|
||
}
|
||
|
||
//------------------------------------------------------------------------
|
||
// Is phrase a yes/no question?
|
||
//------------------------------------------------------------------------
|
||
if( punctDistance == 1 )
|
||
{
|
||
if( (cur_POS == MS_Interr) || (fIsAlphaWH) )
|
||
{
|
||
//---------------------------------
|
||
// It's a "WH" question
|
||
//---------------------------------
|
||
fIsYesNo = false;
|
||
}
|
||
else if( (cur_POS == MS_Prep) || (cur_POS == MS_Conj) || (cur_POS == MS_CConj) )
|
||
{
|
||
fMaybeWH = true;
|
||
}
|
||
}
|
||
else if( (punctDistance == 2) && (fMaybeWH) &&
|
||
((cur_POS == MS_Interr) || (cur_POS == MS_RelPron) || (fIsAlphaWH)) )
|
||
{
|
||
fIsYesNo = false;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_1: Insert boundary after sentence-initial adverb
|
||
//
|
||
// Reluctantly __the cat sat on the mat.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
if( fInitial_Adv )
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_1;
|
||
fInitial_Adv = false;
|
||
bndNum = BND_PhraseRule1;
|
||
accNum = ACC_PhraseRule1;
|
||
}
|
||
else
|
||
{
|
||
|
||
if( (punctDistance == 1) &&
|
||
(cur_POS == MS_Adv) && (next_POS == MS_Det) )
|
||
// include
|
||
//LEX_SUBJPRON // he
|
||
//LEX_DPRON // this
|
||
//LEX_IPRON // everybody
|
||
//NOT LEX_PPRON // myself
|
||
{
|
||
fInitial_Adv = true;
|
||
}
|
||
else
|
||
{
|
||
fInitial_Adv = false;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_2:Insert boundary before coordinating conjunctions
|
||
// The cat sat on the mat __and cleaned his fur.
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
if( (cur_POS == MS_CConj) &&
|
||
(fHasDet == false) &&
|
||
(punctDistance > 3) &&
|
||
(next2_POS != MS_Conj) )
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_2;
|
||
bndNum = BND_PhraseRule2;
|
||
accNum = ACC_PhraseRule2;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_2:Insert boundary before adverb
|
||
// The cat sat on the mat __reluctantly.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( (cur_POS == MS_Adv) &&
|
||
(punctDistance > 4) &&
|
||
(next_POS != MS_Adj) )
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_2;
|
||
bndNum = BND_PhraseRule3;
|
||
accNum = ACC_PhraseRule3;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_2:Insert boundary after object pronoun
|
||
// The cat sat with me__ on the mat.
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( (prev_POS == MS_ObjPron) && (punctDistance > 2))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_2;
|
||
bndNum = BND_PhraseRule4;
|
||
accNum = ACC_PhraseRule4;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_2:Insert boundary before subject pronoun or contraction
|
||
// The cat sat on the mat _I see.
|
||
// The cat sat on the mat _I'm sure.
|
||
//
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( ((cur_POS == MS_SubjPron) || (cur_POS == MS_Contr) ) &&
|
||
(punctDistance > 3) && (prev_POS != MS_RelPron) && (prev_POS != MS_Conj))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_2;
|
||
bndNum = BND_PhraseRule5;
|
||
accNum = ACC_PhraseRule5;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_2:Insert boundary before interr
|
||
// The cat sat on the mat _how odd.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( (cur_POS == MS_Interr) && (punctDistance > 4) )
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_2;
|
||
bndNum = BND_PhraseRule6;
|
||
accNum = ACC_PhraseRule6;
|
||
}
|
||
|
||
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_3:Insert boundary after subject noun phrase followed by aux verb
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_3:Insert boundary before vaux after noun phrase
|
||
// The gray cat __should sit on the mat.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( (punctDistance > 2) &&
|
||
( ((prev_POS == MS_Noun) || (prev_POS == MS_Verb)) && (prev_POS != MS_VAux) ) &&
|
||
(cur_POS == MS_VAux)
|
||
)
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_3;
|
||
bndNum = BND_PhraseRule7;
|
||
accNum = ACC_PhraseRule7;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_3:Insert boundary after MS_Interr
|
||
// The gray cat __should sit on the mat.
|
||
// SEE ABOVE???
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
/*else if( (prev_POS == MS_Noun) && ((next_POS != MS_RelPron) &&
|
||
(next_POS != MS_VAux) && (next_POS != MS_RVAux) &&
|
||
(next2_POS != MS_VAux) && (next2_POS != MS_RVAux)) &&
|
||
(punctDistance > 4) &&
|
||
((cur_POS == MS_VAux) || (cur_POS == MS_RVAux)))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_3;
|
||
bndNum = BND_PhraseRule8;
|
||
accNum = ACC_PhraseRule8;
|
||
}*/
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_3:Insert boundary after MS_Interr
|
||
// The cat sat on the mat _how odd.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( (prev_POS == MS_Noun) && (next_POS != MS_RelPron) &&
|
||
(next_POS != MS_Conj) &&
|
||
(next_POS != MS_CConj) && (punctDistance > 3) && (cur_POS == MS_Verb))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_3;
|
||
bndNum = BND_PhraseRule9;
|
||
accNum = ACC_PhraseRule9;
|
||
}
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_3:Insert boundary after MS_Interr
|
||
// The cat sat on the mat _how odd.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
/*else if( (prev_POS == MS_Noun) && (cur_POS != MS_RelPron) &&
|
||
(cur_POS != MS_RVAux) && (cur_POS != MS_CConj) &&
|
||
(cur_POS != MS_Conj) && (punctDistance > 2) &&
|
||
((punctDistance > 2) || (fIsShortSent)) && (cur_POS == MS_Verb))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_3;
|
||
bndNum = BND_PhraseRule10;
|
||
accNum = ACC_PhraseRule10;
|
||
}
|
||
|
||
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_4:Insert boundary before conjunction
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( ((cur_POS == MS_Conj) && (punctDistance > 3) &&
|
||
(fNext_IsPunct == false) &&
|
||
(prev_POS != MS_Conj) && (prev_POS != MS_CConj) &&
|
||
(fNext2_IsPunct == false)) ||
|
||
|
||
( (prev_POS == MS_VPart) && (cur_POS != MS_Prep) &&
|
||
(cur_POS != MS_Det) &&
|
||
(punctDistance > 2) &&
|
||
((cur_POS == MS_Noun) || (cur_POS == MS_Noun) || (cur_POS == MS_Adj))) ||
|
||
|
||
( (cur_POS == MS_Interr) && (punctDistance > 2) &&
|
||
(cur_POS == MS_SubjPron)) )
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_4;
|
||
bndNum = BND_PhraseRule11;
|
||
accNum = ACC_PhraseRule11;
|
||
}
|
||
|
||
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_5:Insert boundary before relative pronoun
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( ( (cur_POS == MS_RelPron) && (punctDistance >= 3) &&
|
||
(prev_POS != MS_Prep) && (next3_POS != MS_VAux) &&
|
||
(next3_POS != MS_RVAux) &&
|
||
( (prev_POS == MS_Noun) || (prev_POS == MS_Verb) ) ) ||
|
||
|
||
( (cur_POS == MS_Quant) && (punctDistance > 5) &&
|
||
(prev_POS != MS_Adj) && (prev_POS != MS_Det) &&
|
||
(prev_POS != MS_VAux) && (prev_POS != MS_RVAux) &&
|
||
(prev_POS != MS_Det) && (next2_POS != MS_CConj) &&
|
||
(fNext_IsPunct == false)))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_5;
|
||
bndNum = BND_PhraseRule12;
|
||
accNum = ACC_PhraseRule12;
|
||
}*/
|
||
|
||
|
||
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
// SUB_BOUNDARY_6:Silverman87-style, content/function tone group boundaries.
|
||
// Does trivial sentence-final function word look-ahead check.
|
||
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
|
||
else if( ( (prev_POS == MS_Noun) || (prev_POS == MS_Verb) || (prev_POS == MS_Adj) || (prev_POS == MS_Adv))
|
||
&& ((cur_POS != MS_Noun) && (cur_POS != MS_Verb) && (cur_POS != MS_Adj) && (cur_POS != MS_Adv))
|
||
&& (fNext_IsPunct == false))
|
||
{
|
||
cur_Bnd = SUB_BOUNDARY_6;
|
||
bndNum = BND_PhraseRule13;
|
||
accNum = ACC_PhraseRule13;
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------
|
||
// If phrasing was found, save it
|
||
//------------------------------------------------------------------------
|
||
if( (cur_Bnd != NULL_BOUNDARY) && (iCurWord > 0) &&
|
||
//!(fNext_IsPunct) &&
|
||
!(prev_Punct) &&
|
||
(pCur_Tok->m_TuneBoundaryType == NULL_BOUNDARY) )
|
||
{
|
||
//pCur_Tok->m_TuneBoundaryType = cur_Bnd;
|
||
pTempTok = new CFEToken;
|
||
if( pTempTok )
|
||
{
|
||
pTempTok->m_TuneBoundaryType = cur_Bnd;
|
||
pTempTok->phon_Len = 1;
|
||
pTempTok->phon_Str[0] = _SIL_;
|
||
pTempTok->srcPosition = pCur_Tok->srcPosition;
|
||
pTempTok->srcLen = pCur_Tok->srcLen;
|
||
pTempTok->tokStr[0] = '+'; // punctuation
|
||
pTempTok->tokStr[1] = 0; // delimiter
|
||
pTempTok->tokLen = 1;
|
||
pTempTok->m_TermSil = 0;
|
||
pTempTok->m_DurScale = 0;
|
||
if( pPrev_Tok )
|
||
{
|
||
pPrev_Tok->m_AccentSource = accNum;
|
||
pPrev_Tok->m_BoundarySource = bndNum;
|
||
pPrev_Tok->m_Accent = K_LHSTAR;
|
||
}
|
||
pTempTok->m_SilenceSource = SIL_SubBound;
|
||
if( pPrev_Tok )
|
||
{
|
||
//pTempTok->m_DurScale = pPrev_Tok->m_DurScale;
|
||
pTempTok->m_ProsodyDurScale = pPrev_Tok->m_ProsodyDurScale;
|
||
pTempTok->user_Volume = pPrev_Tok->user_Volume;
|
||
}
|
||
else
|
||
{
|
||
//pTempTok->m_DurScale = 1.0f;
|
||
pTempTok->m_ProsodyDurScale = 1.0f;
|
||
}
|
||
|
||
m_TokList.InsertBefore( m_TokList.FindIndex( iCurWord ), pTempTok );
|
||
pCur_Tok = pTempTok;
|
||
m_cNumOfWords++;
|
||
cNumOfWords++;
|
||
iCurWord++;
|
||
}
|
||
}
|
||
//-------------------------------
|
||
// Process sentence punctuation
|
||
//-------------------------------
|
||
AdjustQuestTune( pCur_Tok, fIsYesNo );
|
||
|
||
//-------------------------------
|
||
// Prepare for next word
|
||
//-------------------------------
|
||
prev_Punct = pCur_Tok->m_TuneBoundaryType;
|
||
prev_POS = cur_POS;
|
||
pPrev_Tok = pCur_Tok;
|
||
|
||
//------------------------------
|
||
// Shift the token pipeline
|
||
//------------------------------
|
||
pCur_Tok = pNext_Tok;
|
||
pNext_Tok = pNext2_Tok;
|
||
pNext2_Tok = pNext3_Tok;
|
||
if( listPos )
|
||
{
|
||
pNext3_Tok = m_TokList.GetNext( listPos );
|
||
}
|
||
else
|
||
{
|
||
pNext3_Tok = NULL;
|
||
}
|
||
|
||
//------------------------------------------------------------------------
|
||
// Keep track of when determiners encountered to help in deciding
|
||
// when to allow a strong 'and' boundary (SUB_BOUNDARY_2)
|
||
//------------------------------------------------------------------------
|
||
if( punctDistance > 2)
|
||
{
|
||
fHasDet = false;
|
||
}
|
||
if( cur_POS == MS_Det )
|
||
{
|
||
fHasDet = true;
|
||
}
|
||
}
|
||
//-------------------------------------
|
||
// Process final sentence punctuation
|
||
//-------------------------------------
|
||
pCur_Tok = (CFEToken*)m_TokList.GetTail();
|
||
AdjustQuestTune( pCur_Tok, fIsYesNo );
|
||
}
|
||
|
||
|
||
} /* CFrontend::DoPhrasing */
|
||
|
||
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::RecalcProsody *
|
||
*--------------------------*
|
||
* Description:
|
||
* In response to a real-time rate change, recalculate duration and pitch
|
||
*
|
||
********************************************************************** MC ***/
|
||
#ifdef USE_VOICEDATAOBJ
|
||
void CFrontend::RecalcProsody()
|
||
{
|
||
SPDBG_FUNC( "CFrontend::RecalcProsody" );
|
||
UNITINFO* pu;
|
||
CAlloCell* pCurCell;
|
||
ULONG k;
|
||
|
||
//--------------------------------------------
|
||
// Compute new allo durations
|
||
//--------------------------------------------
|
||
/*pCurCell = m_pAllos->GetHeadCell();
|
||
while( pCurCell )
|
||
{
|
||
//pCurCell->m_DurScale = 1.0;
|
||
pCurCell = m_pAllos->GetNextCell();
|
||
}*/
|
||
m_DurObj.AlloDuration( m_pAllos, m_RateRatio_API );
|
||
|
||
//--------------------------------------------
|
||
// Modulate allo pitch
|
||
//--------------------------------------------
|
||
m_PitchObj.AlloPitch( m_pAllos, m_BasePitch, m_PitchRange );
|
||
|
||
pu = m_pUnits;
|
||
pCurCell = m_pAllos->GetHeadCell();
|
||
while( pCurCell )
|
||
{
|
||
pu->duration = pCurCell->m_ftDuration;
|
||
for( k = 0; k < pu->nKnots; k++ )
|
||
|
||
{
|
||
pu->pTime[k] = pCurCell->m_ftTime[k] * m_SampleRate;
|
||
pu->pF0[k] = pCurCell->m_ftPitch[k];
|
||
pu->pAmp[k] = pu->ampRatio;
|
||
}
|
||
pu++;
|
||
pCurCell = m_pAllos->GetNextCell();
|
||
}
|
||
} /* CFrontend::RecalcProsody */
|
||
#endif
|
||
|
||
/*****************************************************************************
|
||
* CFrontend::NextData *
|
||
*---------------------*
|
||
* Description:
|
||
* This gets called from the backend when UNIT stream is dry.
|
||
* Parse TOKENS to ALLOS to UNITS
|
||
*
|
||
********************************************************************** MC ***/
|
||
HRESULT CFrontend::NextData( void **pData, SPEECH_STATE *pSpeechState )
|
||
{
|
||
SPDBG_FUNC( "CFrontend::NextData" );
|
||
bool haveNewRate = false;
|
||
HRESULT hr = S_OK;
|
||
|
||
//-----------------------------------
|
||
// First, check and see if SAPI has an action
|
||
//-----------------------------------
|
||
// Check for rate change
|
||
long baseRateRatio;
|
||
if( m_pOutputSite->GetActions() & SPVES_RATE )
|
||
{
|
||
hr = m_pOutputSite->GetRate( &baseRateRatio );
|
||
if ( SUCCEEDED( hr ) )
|
||
{
|
||
if( baseRateRatio > SPMAX_VOLUME )
|
||
{
|
||
//--- Clip rate to engine maximum
|
||
baseRateRatio = MAX_USER_RATE;
|
||
}
|
||
else if ( baseRateRatio < MIN_USER_RATE )
|
||
{
|
||
//--- Clip rate to engine minimum
|
||
baseRateRatio = MIN_USER_RATE;
|
||
}
|
||
m_RateRatio_API = CntrlToRatio( baseRateRatio );
|
||
haveNewRate = true;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------
|
||
// Async stop?
|
||
//---------------------------------------------
|
||
if( SUCCEEDED( hr ) && ( m_pOutputSite->GetActions() & SPVES_ABORT ) )
|
||
{
|
||
m_SpeechState = SPEECH_DONE;
|
||
}
|
||
|
||
//---------------------------------------------
|
||
// Async skip?
|
||
//---------------------------------------------
|
||
if( SUCCEEDED( hr ) && ( m_pOutputSite->GetActions() & SPVES_SKIP ) )
|
||
{
|
||
SPVSKIPTYPE SkipType;
|
||
long SkipCount = 0;
|
||
|
||
hr = m_pOutputSite->GetSkipInfo( &SkipType, &SkipCount );
|
||
|
||
if ( SUCCEEDED( hr ) && SkipType == SPVST_SENTENCE )
|
||
{
|
||
IEnumSENTITEM *pGarbage;
|
||
//--- Skip Forwards
|
||
if ( SkipCount > 0 )
|
||
{
|
||
long OriginalSkipCount = SkipCount;
|
||
while ( SkipCount > 1 &&
|
||
( hr = m_pEnumSent->Next( &pGarbage ) ) == S_OK )
|
||
{
|
||
SkipCount--;
|
||
pGarbage->Release();
|
||
}
|
||
if ( hr == S_OK )
|
||
{
|
||
hr = ParseSentence( eNEXT );
|
||
if ( SUCCEEDED( hr ) )
|
||
{
|
||
SkipCount--;
|
||
}
|
||
}
|
||
else if ( hr == S_FALSE )
|
||
{
|
||
m_SpeechState = SPEECH_DONE;
|
||
}
|
||
SkipCount = OriginalSkipCount - SkipCount;
|
||
}
|
||
//--- Skip Backwards
|
||
else if ( SkipCount < 0 )
|
||
{
|
||
long OriginalSkipCount = SkipCount;
|
||
while ( SkipCount < -1 &&
|
||
( hr = m_pEnumSent->Previous( &pGarbage ) ) == S_OK )
|
||
{
|
||
SkipCount++;
|
||
pGarbage->Release();
|
||
}
|
||
if ( hr == S_OK )
|
||
{
|
||
hr = ParseSentence( ePREVIOUS );
|
||
// This case is different from the forward skip, needs to test that
|
||
// Parse sentence found something to parse!
|
||
if ( SUCCEEDED( hr ) && m_SpeechState != SPEECH_DONE)
|
||
{
|
||
SkipCount++;
|
||
}
|
||
}
|
||
else if ( hr == S_FALSE )
|
||
{
|
||
m_SpeechState = SPEECH_DONE;
|
||
}
|
||
SkipCount = OriginalSkipCount - SkipCount;
|
||
}
|
||
//--- Skip to beginning of this sentence
|
||
else
|
||
{
|
||
m_CurUnitIndex = 0;
|
||
}
|
||
hr = m_pOutputSite->CompleteSkip( SkipCount );
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------
|
||
// Make sure we're still speaking
|
||
//---------------------------------------------
|
||
if( SUCCEEDED( hr ) && m_SpeechState != SPEECH_DONE )
|
||
{
|
||
/*****
|
||
if( m_CurUnitIndex >= m_unitCount)
|
||
{
|
||
//-----------------------------------
|
||
// Get next sentence from Normalizer
|
||
//-----------------------------------
|
||
hr = ParseSentence( eNEXT );
|
||
//m_SpeechState = SPEECH_DONE;
|
||
}
|
||
else if( haveNewRate )
|
||
{
|
||
//-----------------------------------
|
||
// Recalculate prosody to new rate
|
||
//-----------------------------------
|
||
RecalcProsody();
|
||
}
|
||
|
||
if( SUCCEEDED(hr) )
|
||
{
|
||
if( m_SpeechState != SPEECH_DONE )
|
||
{
|
||
//-----------------------------------
|
||
// Get next phon
|
||
//-----------------------------------
|
||
m_pUnits[m_CurUnitIndex].hasSpeech = m_HasSpeech;
|
||
*pData =( void*)&m_pUnits[m_CurUnitIndex];
|
||
m_CurUnitIndex++;
|
||
}
|
||
}
|
||
*****/
|
||
|
||
hr = ParseSentence( eNEXT );
|
||
if ( SUCCEEDED( hr ) && m_SpeechState == SPEECH_CONTINUE )
|
||
{
|
||
SentenceData *pSentData = new SentenceData;
|
||
pSentData->pPhones = new Phone[ m_pAllos->GetCount() ];
|
||
ZeroMemory( pSentData->pPhones, m_pAllos->GetCount() * sizeof( Phone ) );
|
||
pSentData->ulNumPhones = m_pAllos->GetCount();
|
||
|
||
m_PitchObj.GetContour( &pSentData->pf0, &pSentData->ulNumf0 );
|
||
|
||
float RunTime = 0.0;
|
||
float InitialSil = 0.0;
|
||
bool fInitialSil = true;
|
||
char ph[512];
|
||
typedef const char *(*MapPhoneSetFunc) (ALLO_CODE);
|
||
MapPhoneSetFunc MapPhoneSet;
|
||
|
||
if (m_fNewPhoneSet)
|
||
{
|
||
MapPhoneSet = NewMapPhoneSet;
|
||
}
|
||
else
|
||
{
|
||
MapPhoneSet = OldMapPhoneSet;
|
||
}
|
||
for ( int i = 0; i < m_pAllos->GetCount(); i++ )
|
||
{
|
||
CAlloCell *pCurCell = m_pAllos->GetCell( i );
|
||
strcpy ( ph, MapPhoneSet( pCurCell->m_allo ) );
|
||
//--- adding stress info for vowels
|
||
// if ( ( pCurCell->m_ctrlFlags & PRIMARY_STRESS ) && IsVowel ( ph ) )
|
||
// {
|
||
// strcat( ph, "s");
|
||
// }
|
||
|
||
strcpy( pSentData->pPhones[i].phone, ph );
|
||
//--- Skip initial SIL
|
||
if ( fInitialSil &&
|
||
stricmp( pSentData->pPhones[i].phone, "sil" ) == 0 )
|
||
{
|
||
InitialSil += pCurCell->m_ftDuration;
|
||
pSentData->pPhones[i].f0 = 0;
|
||
pSentData->pPhones[i].end = InitialSil;
|
||
continue;
|
||
}
|
||
//--- Skip final SIL
|
||
else if ( i == m_pAllos->GetCount() - 1 &&
|
||
stricmp( pSentData->pPhones[i].phone, "sil" ) == 0 )
|
||
{
|
||
pSentData->pPhones[i].end = RunTime + InitialSil;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
fInitialSil = false;
|
||
pSentData->pPhones[i].f0 =
|
||
GetPhoneF0( pSentData->pf0, RunTime, pCurCell->m_ftDuration );
|
||
RunTime += pCurCell->m_ftDuration;
|
||
pSentData->pPhones[i].end = RunTime + InitialSil;
|
||
}
|
||
}
|
||
*pData = (void*) pSentData;
|
||
}
|
||
}
|
||
//-------------------------------------------
|
||
// Let client know if text input is dry
|
||
//-------------------------------------------
|
||
*pSpeechState = m_SpeechState;
|
||
|
||
return hr;
|
||
} /* CFrontend::NextData */
|
||
|
||
/*****************************************************************************
|
||
* IsVowel *
|
||
*----------*
|
||
*
|
||
*********************************************************************** WD ***/
|
||
bool IsVowel ( char* ph )
|
||
{
|
||
if ( ph )
|
||
{
|
||
if ( ph[0] == 'a' || ph[0] == 'e' || ph[0] == 'i' || ph[0] == 'o' ||
|
||
ph[0] == 'u' )
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|