/****************************************************************************** * tips.cpp * *----------* * *------------------------------------------------------------------------------ * Copyright (c) 1996-1997 Entropic Research Laboratory, Inc. * Copyright (C) 1998 Entropic, Inc * Copyright (C) 2000 Microsoft Corporation Date: 03/02/00-12/4/00 * All Rights Reserved * ********************************************************************* mplumpe was PACOG ***/ #include "tips.h" #include "SynthUnit.h" #include "sigproc.h" #include #include #include #include #include #include #include #include "ftol.h" const double CTips::m_iDefaultPeriod = .01; //10 msec. const double CTips::m_dMinF0 = 15.0; // Absolute minimum F0 alowed const int CTips::m_iHalfHanLen_c = 1024; /***************************************************************************** * CTips::CTips * *--------------* * Description: * ******************************************************************* PACOG ***/ CTips::CTips (int iOptions) { m_fLptips = (bool) (iOptions & LpTips); m_fRtips = (iOptions & RTips) != 0; m_iSampFormat = 0; m_iSampFreq = 0; m_dGain = 1.0; m_pfF0 = 0; m_iNumF0 = 0; m_dRunTime = 0.0; m_dF0SampFreq = 0.0; m_dF0TimeNext = 0.0; m_dF0TimeStep = 0.0; m_dF0Value = 0.0; m_dAcumF0 = 0.0; m_iF0Idx = 0; m_dLastEpochTime = 0.0; m_dNewEpochTime = 0.0; m_aBuffer[0].m_pdSamples = 0; m_aBuffer[1].m_pdSamples = 0; m_iLpcOrder = 0; m_pdFiltMem = 0; m_pdInterpCoef = 0; m_pdLastCoef = 0; m_pUnit = 0; m_psSynthSamples = 0; m_iNumSynthSamples = 0; m_adHalfHanning = 0; } /***************************************************************************** * CTips::~CTips * *---------------* * Description: * ******************************************************************* mplumpe ***/ CTips::~CTips () { if (m_pdFiltMem) { delete[] m_pdFiltMem; } if (m_pdInterpCoef) { delete[] m_pdInterpCoef; } if (m_pdLastCoef) { delete[] m_pdLastCoef; } if (m_aBuffer[0].m_pdSamples) { delete[] m_aBuffer[0].m_pdSamples; } if (m_aBuffer[1].m_pdSamples) { delete[] m_aBuffer[1].m_pdSamples; } if (m_psSynthSamples) { delete[] m_psSynthSamples; } if (m_adHalfHanning) { delete [] m_adHalfHanning; } } /***************************************************************************** * CTips::Init * *-------------* * Description: * ******************************************************************* mplumpe ***/ int CTips::Init (int iSampFormat, int iSampFreq) { int i; assert (iSampFreq>0); m_iSampFreq = iSampFreq; m_iSampFormat = iSampFormat; int iPeriodLen = (int) (iSampFreq * m_iDefaultPeriod); // Delete old buffers, if they exist if (m_aBuffer[0].m_pdSamples) { delete[] m_aBuffer[0].m_pdSamples; } if (m_aBuffer[1].m_pdSamples) { delete[] m_aBuffer[1].m_pdSamples; } // Allocate new ones, and initialize them to Zero. // NOTE: Only need to allocate buffer[1], really, since they'll be rotated before // synthesis. if ((m_aBuffer[0].m_pdSamples = new double[2 * iPeriodLen]) == 0 ) { return 0; } //memset(m_aBuffer[0].m_pdSamples, 0, sizeof(double) * 2 * iPeriodLen); if ((m_aBuffer[1].m_pdSamples = new double [2 * iPeriodLen]) == 0) { return 0; } memset(m_aBuffer[1].m_pdSamples, 0, sizeof(double) * 2 * iPeriodLen); m_aBuffer[0].m_iNumSamples = 2 * iPeriodLen; m_aBuffer[0].m_iCenter = iPeriodLen; m_aBuffer[0].m_dDelay = 0.0; m_aBuffer[1].m_iNumSamples = 2 * iPeriodLen; m_aBuffer[1].m_iCenter = iPeriodLen; m_aBuffer[1].m_dDelay = 0.0; // // make Hanning buffer // if (m_adHalfHanning) { delete m_adHalfHanning; } if ((m_adHalfHanning = new double [m_iHalfHanLen_c]) == 0) { return 0; } for (i=0; i < m_iHalfHanLen_c; i++) { m_adHalfHanning[i] = 0.5-0.5*cos(M_PI*i/m_iHalfHanLen_c); } if (m_fLptips) { return LpcInit(); } return 1; } /***************************************************************************** * CTips::SetGain * *----------------* * Description: * ******************************************************************* PACOG ***/ void CTips::SetGain (double dGain) { assert (dGain>=0.0); m_dGain = dGain; } /***************************************************************************** * CTips::GetGain * *----------------* * Description: * ******************************************************************* PACOG ***/ double CTips::GetGain () { return m_dGain; } /***************************************************************************** * CTips::NewSentence * *--------------------* * Description: * ******************************************************************* PACOG ***/ void CTips::NewSentence (float* pfF0, int iNumF0, int iF0SampFreq) { assert (pfF0); assert (iNumF0>0); assert (iF0SampFreq>0); m_pfF0 = pfF0; m_iNumF0 = iNumF0; m_dF0SampFreq = iF0SampFreq; m_dF0TimeStep = 1.0/iF0SampFreq; m_dRunTime = 0.0; m_dF0TimeNext = 0.0; m_dAcumF0 = 0.0; m_iF0Idx = 0; m_dLastEpochTime = 0.0; m_dNewEpochTime = 0.0; } /***************************************************************************** * CTips::NewUnit * *----------------* * Description: * Gets a new unit to synthesize, and does some analysis on it. ******************************************************************* PACOG ***/ int CTips::NewUnit (CSynth* pUnit) { if (pUnit) { m_pUnit = pUnit; if (m_fLptips) { if (!m_pUnit->LpcAnalysis(m_iSampFreq, m_iLpcOrder)) { return 0; } } if ( Prosody (pUnit) == -1) { return 0; } return 1; } return 0; } /***************************************************************************** * CTips::Prosody * *----------------* * Description: * We get synthesis epochs track for a segment. F0 curve integration is * therefore carried out here. The sampling frequency chosen is high enough * as to reduce jitter to an umperceivable level, but that depends on the * synthesis module being capable of synthesizing at that interval. * ******************************************************************* PACOG ***/ int CTips::Prosody ( CSynth* pUnit ) { double dF0IntegralTime = 0.0; assert (m_pfF0 && m_iNumF0>0); if (m_dNewEpochTime != m_dLastEpochTime) { if ((pUnit->m_pdSynEpochs = new double[2]) == 0) { return -1; } pUnit->m_pdSynEpochs[0] = m_dLastEpochTime; pUnit->m_pdSynEpochs[1] = m_dNewEpochTime; pUnit->m_iNumSynEpochs = 2; } else { if ((pUnit->m_pdSynEpochs = new double[1]) == 0) { return -1; } pUnit->m_pdSynEpochs[0] = m_dNewEpochTime; pUnit->m_iNumSynEpochs = 1; } while ( m_dRunTime < pUnit->m_dRunTimeLimit || // Find an extra epoch, for the overlapping period // if the last epoch doesn't already cross the segment limit pUnit->m_pdSynEpochs[pUnit->m_iNumSynEpochs-1] < pUnit->m_dRunTimeLimit) { if (m_dRunTime >= m_dF0TimeNext) { m_dF0Value = m_pfF0[m_iF0Idx]; if (m_iF0Idx < m_iNumF0-1) { m_iF0Idx++; } if (m_dF0Value<=0.0) { m_dF0Value = 100.0; // Best choice is f0=100Hz } else if (m_dF0Value <= m_dMinF0) { m_dF0Value = m_dMinF0; } m_dF0TimeNext += m_dF0TimeStep; } dF0IntegralTime = (1.0 - m_dAcumF0) / m_dF0Value; if (dF0IntegralTime >= m_dF0TimeStep) { m_dRunTime += m_dF0TimeStep; m_dAcumF0 += m_dF0Value * m_dF0TimeStep; } else { m_dRunTime += dF0IntegralTime; m_dAcumF0 = 0; //Got epoch m_dLastEpochTime = m_dNewEpochTime; m_dNewEpochTime = m_dRunTime; //Reallocate the synthesis epochs array double* pdSynEpochs = new double[pUnit->m_iNumSynEpochs + 1]; if (!pdSynEpochs) { return -1; } memcpy(pdSynEpochs, pUnit->m_pdSynEpochs, pUnit->m_iNumSynEpochs * sizeof(double)); delete[] pUnit->m_pdSynEpochs; pUnit->m_pdSynEpochs = pdSynEpochs; // And add a new epoch pUnit->m_pdSynEpochs[pUnit->m_iNumSynEpochs] = m_dNewEpochTime; pUnit->m_iNumSynEpochs++; } } if (pUnit->m_iNumSynEpochs <3) { delete[] pUnit->m_pdSynEpochs; pUnit->m_pdSynEpochs = 0; return 0; } // Synthesis epochs are in absolute synthesis time double epStartTime = ((long)(pUnit->m_pdSynEpochs[0] * m_iSampFreq)) / (double)m_iSampFreq; for (int i=0; im_iNumSynEpochs; i++) { pUnit->m_pdSynEpochs[i] -= epStartTime; } return pUnit->FindPrecedent (); } /***************************************************************************** * CTips::Pending * *----------------* * Description: * ******************************************************************* PACOG ***/ int CTips::Pending () { return m_pUnit != 0; } /***************************************************************************** * CTips::NextPeriod * *-------------------* * Description: * ******************************************************************* PACOG ***/ int CTips::NextPeriod (short** ppnSamples, int *piNumSamples) { int iPeriodLen; assert (ppnSamples && piNumSamples> 0); if (m_pUnit) { iPeriodLen = m_pUnit->NextBuffer (this); if ( iPeriodLen > 0 ) { Synthesize (iPeriodLen); *ppnSamples = m_psSynthSamples; *piNumSamples = iPeriodLen; return 1; } else { delete m_pUnit; m_pUnit = 0; } } return 0; } /***************************************************************************** * CTips::FillBuffer * *-------------------* * Description: * ******************************************************************* PACOG ***/ int CTips::SetBuffer ( double* pdSamples, int iNumSamples, int iCenter, double dDelay, double* pdLpcCoef) { // Advance buffers delete[] m_aBuffer[0].m_pdSamples; m_aBuffer[0] = m_aBuffer[1]; m_aBuffer[1].m_pdSamples = pdSamples; m_aBuffer[1].m_iNumSamples = iNumSamples; m_aBuffer[1].m_iCenter = iCenter; m_aBuffer[1].m_dDelay = dDelay; m_pdNewCoef = pdLpcCoef; return 1; } /***************************************************************************** * CTips::Synthesize * *-------------------* * Description: * ******************************************************************* PACOG ***/ int CTips::Synthesize (int iPeriodLen) { double* pdPeriodSamples = 0; double* windowedLeft = 0; int leftSize; double* windowedRight = 0; int rightSize; double *p1, *p2; int i; assert (iPeriodLen); if (m_fRtips) { NonIntegerDelay (m_aBuffer[1].m_pdSamples, m_aBuffer[1].m_iNumSamples, m_aBuffer[1].m_dDelay); } if (!GetWindowedSignal(0, iPeriodLen, &windowedLeft, &leftSize)) { goto error; } if (!GetWindowedSignal(1, iPeriodLen, &windowedRight, &rightSize) ) { goto error; } assert (windowedLeft && leftSize); assert (windowedRight && rightSize); if (!windowedLeft || !leftSize || !windowedRight || !rightSize ) { goto error; } if ((pdPeriodSamples = new double[iPeriodLen]) == 0) { goto error; } p1=windowedLeft; p2=windowedRight; for (i=0; i SHRT_MAX ) { return SHRT_MAX; } if (x < SHRT_MIN ) { return SHRT_MIN; } return (short)FTOL(x); } /***************************************************************************** * CTips::LpcInit * *----------------* * Description: * ******************************************************************* PACOG ***/ bool CTips::LpcInit () { m_iLpcOrder = LpcOrder (m_iSampFreq); if ((m_pdFiltMem = new double [m_iLpcOrder]) == 0) { goto error; } memset( m_pdFiltMem, 0, m_iLpcOrder * sizeof (*m_pdFiltMem)); if ((m_pdInterpCoef = new double [m_iLpcOrder]) == 0) { goto error; } memset( m_pdInterpCoef, 0, m_iLpcOrder * sizeof (*m_pdInterpCoef)); if ((m_pdLastCoef = new double [m_iLpcOrder]) == 0) { goto error; } memset( m_pdLastCoef, 0, m_iLpcOrder * sizeof (*m_pdLastCoef)); return true; error: LpcFreeAll(); return false; } /***************************************************************************** * CTips::LpcSynth * *--------------------* * Description: * ******************************************************************* PACOG ***/ void CTips::LpcSynth (double* pdPeriod, int iPeriodLen) { double alfa; int i; int j; for (i=0; i