807 lines
19 KiB
C++
807 lines
19 KiB
C++
/******************************************************************************
|
|
* 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 <vapiIo.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
#include <assert.h>
|
|
|
|
#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; i<pUnit->m_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<iPeriodLen - rightSize && i<leftSize; i++)
|
|
{
|
|
pdPeriodSamples[i] = *p1++;
|
|
}
|
|
|
|
// If windows overlap, they are added
|
|
for ( ;i<leftSize; i++)
|
|
{
|
|
pdPeriodSamples[i] = *p1++ + *p2++;
|
|
}
|
|
|
|
// Else, we fill the space with zeros
|
|
for (; i<iPeriodLen - rightSize; i++)
|
|
{
|
|
pdPeriodSamples[i] = 0.0;
|
|
}
|
|
|
|
for (;i<iPeriodLen;i++)
|
|
{
|
|
pdPeriodSamples[i] = *p2++;
|
|
}
|
|
|
|
delete[] windowedLeft;
|
|
delete[] windowedRight;
|
|
|
|
if (m_fLptips)
|
|
{
|
|
LpcSynth (pdPeriodSamples, iPeriodLen);
|
|
}
|
|
|
|
// reuse the same buffer if possible
|
|
if ( m_iNumSynthSamples < iPeriodLen )
|
|
{
|
|
if (m_psSynthSamples)
|
|
{
|
|
delete[] m_psSynthSamples;
|
|
}
|
|
if ((m_psSynthSamples = new short[iPeriodLen]) == 0)
|
|
{
|
|
goto error;
|
|
}
|
|
m_iNumSynthSamples = iPeriodLen;
|
|
}
|
|
|
|
for (i=0; i<iPeriodLen; i++)
|
|
{
|
|
m_psSynthSamples[i] = ClipData(pdPeriodSamples[i]);
|
|
}
|
|
|
|
delete[] pdPeriodSamples;
|
|
|
|
return 1;
|
|
|
|
error:
|
|
if (pdPeriodSamples)
|
|
{
|
|
delete[] pdPeriodSamples;
|
|
}
|
|
if (windowedLeft)
|
|
{
|
|
delete[] windowedLeft;
|
|
}
|
|
if (windowedRight)
|
|
{
|
|
delete[] windowedRight;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* CTips::GetWindowedSignal *
|
|
*----------------------------*
|
|
* Description:
|
|
*
|
|
******************************************************************* PACOG ***/
|
|
|
|
int CTips::GetWindowedSignal (int whichBuffer, int iPeriodLen,
|
|
double** windowed, int* nWindowed)
|
|
{
|
|
double* sampPtr;
|
|
int nSamples;
|
|
int from;
|
|
|
|
|
|
if (whichBuffer==0)
|
|
{
|
|
sampPtr = m_aBuffer[0].m_pdSamples + m_aBuffer[0].m_iCenter;
|
|
nSamples = __min(iPeriodLen, (m_aBuffer[0].m_iNumSamples - m_aBuffer[0].m_iCenter));
|
|
}
|
|
else
|
|
{
|
|
from = __max(0, m_aBuffer[1].m_iCenter - iPeriodLen);
|
|
sampPtr = m_aBuffer[1].m_pdSamples + from;
|
|
nSamples = m_aBuffer[1].m_iCenter - from;
|
|
}
|
|
|
|
|
|
if (nSamples)
|
|
{
|
|
if ((*windowed = new double[nSamples]) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
*nWindowed = nSamples;
|
|
|
|
memcpy (*windowed, sampPtr, nSamples * sizeof(**windowed));
|
|
|
|
if (whichBuffer==0)
|
|
{
|
|
HalfHanning (*windowed, nSamples, 1.0, WindowSecondHalf);
|
|
}
|
|
else
|
|
{
|
|
HalfHanning (*windowed, nSamples, 1.0, WindowFirstHalf);
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
else
|
|
{
|
|
fprintf (stderr, "NULL vector in GetWindowedSignal\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* CTips::HalfHanning *
|
|
*--------------------*
|
|
* Description:
|
|
* 12/4/00 - Since ampl wasn't being used, I'm now asserting it equal
|
|
* to 1 and ignoring it. Also, a large hanning window is
|
|
* pre-computed and interpolated here, instead of being
|
|
* calculated here.
|
|
*
|
|
******************************************************************* mplumpe ***/
|
|
|
|
void CTips::HalfHanning (double* x, int xLen, double ampl, int whichHalf)
|
|
{
|
|
double delta;
|
|
double dk;
|
|
int start;
|
|
int sign;
|
|
int i;
|
|
|
|
assert (1 == ampl);
|
|
|
|
if (x && xLen)
|
|
{
|
|
delta = m_iHalfHanLen_c / xLen;
|
|
dk=0.; // FTOL function does rounding. If casting to int, need to start at 0.5 to get rounding
|
|
|
|
/*
|
|
* When multiplying by the second half, the window function is the same,
|
|
* but we multiply from the last sample in the vector to the first
|
|
* NOTE: The first sample is multiplyed by 0 in the case of the first
|
|
* half, and by 1 (*ampl, of course) in the case of the second half.
|
|
*/
|
|
switch (whichHalf)
|
|
{
|
|
case WindowSecondHalf:
|
|
start=xLen;
|
|
sign=-1;
|
|
break;
|
|
case WindowFirstHalf:
|
|
x[0]=0.0;
|
|
start=0;
|
|
sign=1;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Hanning, should especify a half window\n");
|
|
return;
|
|
}
|
|
|
|
for (i=1; i<xLen; i++)
|
|
{
|
|
dk += delta;
|
|
x[start+sign*i] *= m_adHalfHanning[FTOL(dk)];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* CTips::ClipData *
|
|
*-----------------*
|
|
* Description:
|
|
* 12/4/00 - now using the FTOL function, since the compiler doesn't do
|
|
* the conversion efficiently.
|
|
* 1/18/01 - The FTOL function rounds, whereas casting truncates. So,
|
|
* we no longer need to ad .5 for pos numbers and subtract .5
|
|
* for negative numbers.
|
|
*
|
|
******************************************************************* mplumpe ***/
|
|
|
|
short CTips::ClipData (double x)
|
|
{
|
|
|
|
|
|
if (x > 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<iPeriodLen; i++)
|
|
{
|
|
alfa = i/(double)iPeriodLen;
|
|
|
|
for (j=0; j<m_iLpcOrder ; j++) {
|
|
m_pdInterpCoef[j] = (1.0 - alfa) * m_pdLastCoef[j] + alfa * m_pdNewCoef[j];
|
|
}
|
|
ParcorFilterSyn(pdPeriod+i, 1, m_pdInterpCoef, m_pdFiltMem, m_iLpcOrder );
|
|
}
|
|
|
|
memcpy( m_pdLastCoef, m_pdNewCoef, m_iLpcOrder * sizeof(*m_pdLastCoef));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* CTips::LpcFreeAll *
|
|
*----------------------*
|
|
* Description:
|
|
*
|
|
******************************************************************* PACOG ***/
|
|
|
|
void CTips::LpcFreeAll()
|
|
{
|
|
if (m_pdFiltMem)
|
|
{
|
|
delete[] m_pdFiltMem;
|
|
m_pdFiltMem = 0;
|
|
}
|
|
|
|
if (m_pdInterpCoef)
|
|
{
|
|
delete[] m_pdInterpCoef;
|
|
m_pdInterpCoef = 0;
|
|
}
|
|
|
|
if (m_pdLastCoef)
|
|
{
|
|
delete[] m_pdLastCoef;
|
|
m_pdInterpCoef = 0;
|
|
}
|
|
}
|
|
|