/******************************************************************************
* Duration.cpp *
*--------------*
*
*------------------------------------------------------------------------------
*  Copyright (C) 1999 Microsoft Corporation         Date: 04/28/99
*  All Rights Reserved
*
*********************************************************************** MC ****/

//--- Additional includes
#include "stdafx.h"

#ifndef SPDebug_h
#include <spdebug.h>
#endif
#ifndef Frontend_H
#include "Frontend.h"
#endif
#ifndef AlloOps_H
#include "AlloOps.h"
#endif



//-----------------------------
// Data.cpp
//-----------------------------
extern const unsigned long    g_AlloFlags[];
extern const float  g_BoundryDurTbl[];
extern const float  g_BoundryStretchTbl[];





/*****************************************************************************
* CDuration::Pause_Insertion *
*----------------------------*
*   Description:
*   Duration Rule #1 - Pause Insertion
*       
********************************************************************** MC ***/
void CDuration::Pause_Insertion( long userDuration, long silBreak )
{
    SPDBG_FUNC( "CDuration::Pause_Insertion" );

    if( userDuration )
    {
        m_DurHold = ((float)userDuration / 1000);
        m_TotalDurScale = 1.0;
    }
    else if( silBreak )
    {
        m_DurHold = ((float)silBreak / 1000);
    }
    else
    {
        if( m_CurBoundary != NULL_BOUNDARY)
        {
            m_DurHold = g_BoundryDurTbl[(long)m_CurBoundary];
			//m_DurHold *= m_TotalDurScale;

			//----------------------------
			// Clip to limits
			//----------------------------
			if( m_DurHold > MAX_SIL_DUR )
			{
				m_DurHold = MAX_SIL_DUR;
			}
			/*else if( m_DurHold < MIN_ALLO_DUR )
			{
				m_DurHold = MIN_ALLO_DUR;
			}*/
        }
    }

} /* CDuration::Pause_Insertion */





/*****************************************************************************
* CDuration::PhraseFinal_Lengthen *
*---------------------------------*
*   Description:
*   Duration Rule #2 - Phrase-final Lengthening
*       
********************************************************************** MC ***/
void CDuration::PhraseFinal_Lengthen( long /*cellCount*/ )
{
    SPDBG_FUNC( "CDuration::PhraseFinal_Lengthen" );
	float		stretchGain;

    if( m_cur_SyllableType & TERM_END_SYLL)
    {
    
    
        if( (m_cur_Stress) && (m_cur_VowelFlag) )
        {
            stretchGain = g_BoundryStretchTbl[(long)m_NextBoundary];
			m_DurHold *= stretchGain;

			//----------------------------
			// Clip to limits
			//----------------------------
			if( m_DurHold > MAX_ALLO_DUR )
			{
				m_DurHold = MAX_ALLO_DUR;
			}
			else if( m_DurHold < MIN_ALLO_DUR )
			{
				m_DurHold = MIN_ALLO_DUR;
			}
        }
    }
} /* CDuration::PhraseFinal_Lengthen */


#define		EMPH_VOWEL_GAIN	1.0f
#define		EMPH_CONS_GAIN	1.25f
#define		EMPH_VOWEL_MIN	0.060f
#define		EMPH_CONS_MIN	0.020f
#define		EMPH_MIN_DUR	0.150f

/*****************************************************************************
* CDuration::Emphatic_Lenghen *
*-----------------------------*
*   Description:
*   Duration Rule #8 - Lengthening for emphasis
*       
********************************************************************** MC ***/
long CDuration::Emphatic_Lenghen( long lastStress )
{
    SPDBG_FUNC( "CDuration::Emphatic_Lenghen" );

    long            eFlag;
	bool			isEmph;

    eFlag = lastStress;
	if( m_cur_Stress & EMPHATIC_STRESS )
	{
		isEmph = true;
	}
	else
	{
		isEmph = false;
	}

    if( (m_cur_PhonCtrl & WORD_INITIAL_CONSONANT) || 
        ( m_cur_VowelFlag && (!isEmph)) )
    {
        eFlag = false;          // start of a new word OR non-emph vowel    
    }
    
    if( isEmph )
    {
        eFlag = true;           // continue lengthening until above condition is met    
    }
    
    if( eFlag )
    {
		

		/*if( m_DurHold < EMPH_MIN_DUR )
		{
			m_durationPad += EMPH_MIN_DUR - m_DurHold;
		}*/

		float		durDiff;
        if( m_cur_VowelFlag)
        {
			durDiff = (m_DurHold * EMPH_VOWEL_GAIN) - m_DurHold;
			if( durDiff <  EMPH_VOWEL_MIN )
			{
				durDiff = EMPH_VOWEL_MIN;
			}
        }
        else
        {
			durDiff = (m_DurHold * EMPH_CONS_GAIN) - m_DurHold;
			if( durDiff <  EMPH_CONS_MIN )
			{
				durDiff = EMPH_CONS_MIN;
			}
        }
		m_durationPad += durDiff;    // lengthen phon for emph    
    }

    return eFlag;
} /* CDuration::Emphatic_Lenghen */





/*****************************************************************************
* CDuration::AlloDuration *
*-------------------------*
*   Description:
*   Calculate durations
*       
********************************************************************** MC ***/
void CDuration::AlloDuration( CAlloList *pAllos, float rateRatio )
{
    SPDBG_FUNC( "CDuration::AlloDuration" );

    
    long        eFlag;
    CAlloCell   *pPrevCell, *pCurCell, *pNextCell, *pNext2Cell;
    long        numOfCells;
    long        userDuration, silBreak;
    
    numOfCells = pAllos->GetCount();

    if( numOfCells > 0 )
    {
        eFlag   = false;
		//------------------------------
		// Fill the pipeline
		//------------------------------
		pPrevCell = pAllos->GetHeadCell();
		pCurCell = pAllos->GetNextCell();
		pNextCell = pAllos->GetNextCell();
		pNext2Cell = pAllos->GetNextCell();

		//------------------------------
		// 1st allo is always SIL
		//------------------------------
        pPrevCell->m_ftDuration = pPrevCell->m_UnitDur = PITCH_BUF_RES;           // initial SIL    
		while( pCurCell )
        {
            //------------------
            // Current  
            //------------------
            m_cur_Phon = pCurCell->m_allo;
            m_cur_PhonCtrl = pCurCell->m_ctrlFlags;
            m_cur_SyllableType = m_cur_PhonCtrl & SYLLABLE_TYPE_FIELD;
            m_cur_Stress = m_cur_PhonCtrl & STRESS_FIELD;
            m_cur_PhonFlags = ::g_AlloFlags[m_cur_Phon];
            userDuration = pCurCell->m_user_Break;
            silBreak = pCurCell->m_Sil_Break;
            if( m_cur_PhonFlags & KVOWELF)
            {
                m_cur_VowelFlag = true;
            }
            else
            {
                m_cur_VowelFlag = false;
            }
            m_CurBoundary = pCurCell->m_TuneBoundaryType;
            m_NextBoundary = pCurCell->m_NextTuneBoundaryType;
            m_TotalDurScale = rateRatio * pCurCell->m_DurScale * pCurCell->m_ProsodyDurScale;
//			m_DurHold = pCurCell->m_UnitDur;
			m_DurHold = 1.f;
			m_durationPad = 0;

			if( pCurCell->m_user_Emph > 0 )
			{
				m_cur_Stress |= EMPHATIC_STRESS;
			}
        
            //------------------
            // Prev  
            //------------------
            m_prev_Phon = pPrevCell->m_allo;
            m_prev_PhonCtrl = pPrevCell->m_ctrlFlags;
            m_prev_PhonFlags = ::g_AlloFlags[m_prev_Phon];
        
            //------------------
            // Next
            //------------------
            if( pNextCell )
            {
                m_next_Phon = pNextCell->m_allo;
                m_next_PhonCtrl = pNextCell->m_ctrlFlags;
            }
            else
            {
                m_next_Phon = _SIL_;
                m_next_PhonCtrl = 0;
            }
            m_next_PhonFlags = ::g_AlloFlags[m_next_Phon];
        
            //------------------
            // 2 phons ahead 
            //------------------
            if( pNext2Cell )
            {
                m_next2_Phon = pNext2Cell->m_allo;
                m_next2_PhonCtrl = pNext2Cell->m_ctrlFlags;
            }
            else
            {
                m_next2_Phon = _SIL_;
                m_next2_PhonCtrl = 0;
            }
            m_next2_PhonFlags = ::g_AlloFlags[m_next2_Phon];

        
            if( m_cur_Phon == _SIL_ )
            {
                //-------------------------------------------
                // #1 - Pause Insertion  
                //-------------------------------------------
                Pause_Insertion( userDuration, silBreak );
            }
            else
            {
                //-------------------------------------------
                // #2 - Phrase-final Lengthening 
                //-------------------------------------------
                PhraseFinal_Lengthen( numOfCells );
        
                //-------------------------------------------
                // #8  Lengthening for emphasis 
                //-------------------------------------------
                eFlag = Emphatic_Lenghen( eFlag );        
   
            }
        
            pCurCell->m_ftDuration = ((m_DurHold + m_durationPad) / m_TotalDurScale);

			//---------------------------------
			// Shift the pipeline once
			//---------------------------------
			pPrevCell	= pCurCell;
			pCurCell	= pNextCell;
			pNextCell	= pNext2Cell;
			pNext2Cell	= pAllos->GetNextCell();
        }
    }
} /* CDuration::AlloDuration */