windows-nt/Source/XPSP1/NT/enduser/speech/tts/tools/filedist/viterbi.cpp
2020-09-26 16:20:57 +08:00

237 lines
5.7 KiB
C++

#include <stdlib.h>
#include "viterbi.h"
#include <float.h>
CPtrArray::CPtrArray()
{
m_iSize=0;
m_rgpv=NULL;
m_iTop=0;
m_iGrow=10;
}
CPtrArray::~CPtrArray()
{
if (m_rgpv)
free (m_rgpv);
}
void CPtrArray::SetSize(int iSize, int iGrowSize)
{
if (iSize > m_iSize)
{
m_rgpv = (void **)realloc (m_rgpv, iSize*sizeof(void *));
m_iSize = iSize;
}
if (0 < iGrowSize)
m_iGrow = iGrowSize;
else
m_iGrow = 10;
}
int CPtrArray::Add(void *pElem)
{
if (m_iTop >= m_iSize)
{
m_iSize += m_iGrow;
m_rgpv = (void **)realloc (m_rgpv, m_iSize*sizeof(void *));
}
m_rgpv[m_iTop] = pElem;
return (m_iTop++);
}
/*
void *CPtrArray::Get(int iElem)
{
if ((iElem >= m_iTop) || (iElem < 0))
return NULL;
return m_rgpv[iElem];
}
*/
/*
__inline int CPtrArray::GetSize()
{
return m_iSize;
}
*/
CViterbi::CViterbi ()
{
m_fPruneLevel = 0.f;
m_pConcatCostFunction = NULL;
m_pUnitCostFunction = NULL;
m_rgpBestElems = NULL;
m_rgpElemArray = NULL;
m_iLen = 0;
}
CViterbi::~CViterbi ()
{
int i;
for (i=0; i < m_iLen; i++)
delete m_rgpElemArray[i];
if (m_rgpElemArray)
free (m_rgpElemArray);
if (m_rgpBestElems)
free (m_rgpBestElems);
}
int CViterbi::Init (int iLen, int iInitialDepth, int iGrowSize)
{
int i;
m_iLen = iLen;
if (NULL == (m_rgpElemArray = (CPtrArray **)malloc (sizeof (CPtrArray*)*m_iLen)))
return -1;
for (i=0; i < m_iLen; i++)
{
m_rgpElemArray[i] = new CPtrArray;
if (NULL == m_rgpElemArray[i])
{
m_iLen = i;
return -1;
}
m_rgpElemArray[i]->SetSize (iInitialDepth, iGrowSize);
}
return 0;
}
int CViterbi::Add (int iPos, void *pElem)
{
if ((iPos > m_iLen) || (iPos < 0))
return -1;
m_rgpElemArray[iPos]->Add(pElem);
return 0;
}
int CViterbi::FindBestPath(ConcatCostFn pConcatCostFunction, UnitCostFn pUnitCostFunction, float *pfCost)
{
if (pConcatCostFunction)
m_pConcatCostFunction = pConcatCostFunction;
if (pUnitCostFunction)
m_pUnitCostFunction = pUnitCostFunction;
float **rgrgfCosts=NULL, *rgfBuf=NULL;
int **rgrgiBestLeft=NULL, *rgiBuf=NULL;
int iMaxLen, iLLen, iRLen, iTotalLen, iPos, iLElem, iRElem, iBestElem, iTempLen;
float fCost, fUnitCost;
int iRet=-1;
iMaxLen = m_rgpElemArray[0]->GetUsed();
iRLen = iMaxLen;
if (0 == iMaxLen)
iMaxLen=1;
iTotalLen = iMaxLen;
for (iPos=1; iPos < m_iLen; iPos++)
{
iTempLen = m_rgpElemArray[iPos]->GetUsed();
if (0 == iTempLen)
iTempLen=1;
if (iTempLen > iMaxLen)
iMaxLen = iTempLen;
iTotalLen += iTempLen;
}
rgfBuf = (float *)calloc (iTotalLen, sizeof (float));
rgiBuf = (int *)calloc (iTotalLen, sizeof(int));
iTotalLen=0;
rgrgfCosts = (float **)malloc (m_iLen * sizeof (float*));
rgrgiBestLeft = (int **)malloc (sizeof (int)*m_iLen);
if ((NULL == rgrgfCosts) || (NULL == rgfBuf) || (NULL == rgrgiBestLeft) || (NULL == rgiBuf))
goto Err;
rgrgfCosts[0] = rgfBuf+iTotalLen;
rgrgiBestLeft[0] = rgiBuf+iTotalLen;
if (0 == iRLen)
iTotalLen++;
else
iTotalLen += iRLen;
for (iLElem=0; iLElem < iRLen; iLElem++)
if (NULL != (*m_rgpElemArray[0])[iLElem])
rgrgfCosts[0][iLElem] = m_pUnitCostFunction((*m_rgpElemArray[0])[iLElem],0);
for (iPos=1; iPos < m_iLen; iPos++)
{
iLLen = iRLen;
iRLen = m_rgpElemArray[iPos]->GetUsed();
rgrgfCosts[iPos] = rgfBuf+iTotalLen;
rgrgiBestLeft[iPos] = rgiBuf+iTotalLen;
if (0 == iRLen)
iTotalLen++;
else
iTotalLen += iRLen;
for (iRElem=0; iRElem < iRLen; iRElem++)
{
rgrgfCosts[iPos][iRElem] = FLT_MAX; // much bigger than any potential cost.
fUnitCost = m_pUnitCostFunction((*m_rgpElemArray[iPos])[iRElem],iPos);
for (iLElem=0; iLElem < iLLen; iLElem++)
{
if (NULL != (*m_rgpElemArray[iPos-1])[iLElem])
{
fCost = m_pConcatCostFunction((*m_rgpElemArray[iPos-1])[iLElem],
(*m_rgpElemArray[iPos])[iRElem], fUnitCost) +
rgrgfCosts[iPos-1][iLElem];// + fUnitCost;
if (fCost <= rgrgfCosts[iPos][iRElem])
{
rgrgfCosts[iPos][iRElem] = fCost;
rgrgiBestLeft[iPos][iRElem] = iLElem;
}
}
// else it was pruned earlier
}
if ((0.f != m_fPruneLevel) && (rgrgfCosts[iPos][iRElem] > m_fPruneLevel))
(*m_rgpElemArray[iPos])[iRElem] = NULL;
}
}
*pfCost = 0.f;
fCost = rgrgfCosts[m_iLen-1][0];
iBestElem = 0;
for (iRElem=1; iRElem < iRLen; iRElem++)
if (rgrgfCosts[m_iLen-1][iRElem] < fCost)
{
iBestElem = iRElem;
fCost = rgrgfCosts[m_iLen-1][iRElem];
}
m_rgpBestElems = (void **)calloc (m_iLen, sizeof (void *));
if (NULL == m_rgpBestElems)
goto Err;
if (iBestElem >= m_rgpElemArray[m_iLen-1]->GetUsed())
m_rgpBestElems[m_iLen-1] = NULL;
else
{
m_rgpBestElems[m_iLen-1] = (*m_rgpElemArray[m_iLen-1])[iBestElem];
*pfCost = fCost;
}
for (iPos=m_iLen-2; iPos >= 0; iPos--)
{
if (0 == m_rgpElemArray[iPos+1]->GetUsed())
{
iRLen = m_rgpElemArray[iPos]->GetUsed();
fCost = rgrgfCosts[iPos][0];
for (iRElem=1; iRElem < iRLen; iRElem++)
if (rgrgfCosts[iPos][iRElem] < fCost)
{
iBestElem = iRElem;
fCost = rgrgfCosts[iPos][iRElem];
}
}
else
iBestElem = rgrgiBestLeft[iPos+1][iBestElem];
if (iBestElem >= m_rgpElemArray[iPos]->GetUsed())
m_rgpBestElems[iPos] = NULL;
else
{
m_rgpBestElems[iPos] = (*m_rgpElemArray[iPos])[iBestElem];
if (0 == *pfCost)
*pfCost = fCost;
}
}
iRet = 0;
Err:
if (rgrgfCosts)
free (rgrgfCosts);
if (rgfBuf)
free (rgfBuf);
if (rgrgiBestLeft)
free (rgrgiBestLeft);
if (rgiBuf)
free (rgiBuf);
return iRet;
}