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

1815 lines
57 KiB
C++

/*******************************************************************************
* VoiceDataObj.cpp *
*------------------*
* Description:
* This module is the main implementation file for the CVoiceData class.
*-------------------------------------------------------------------------------
* Created By: EDC Date: 05/06/99
* Copyright (C) 1999 Microsoft Corporation
* All Rights Reserved
*
*******************************************************************************/
//--- Additional includes
#include "stdafx.h"
#include "VoiceDataObj.h"
/*****************************************************************************
* CVoiceData::FinalConstruct *
*-------------------------------*
* Description:
* Constructor
********************************************************************* EDC ***/
CVoiceData::CVoiceData()
{
//--- Init vars
m_hVoiceDef = NULL;
m_hVoiceData = NULL;
m_pVoiceData = NULL;
m_pVoiceDef = NULL;
} /* CVoiceData::FinalConstruct */
/*****************************************************************************
* CVoiceData::FinalRelease *
*-----------------------------*
* Description:
* destructor
********************************************************************* EDC ***/
CVoiceData::~CVoiceData()
{
SPDBG_FUNC( "CVoiceData::FinalRelease" );
if( m_pVoiceDef )
{
::UnmapViewOfFile( (void*)m_pVoiceDef );
}
if( m_pVoiceData )
{
::UnmapViewOfFile( (void*)m_pVoiceData );
}
if( m_hVoiceDef ) ::CloseHandle( m_hVoiceDef );
if( m_hVoiceData ) ::CloseHandle( m_hVoiceData );
} /* CVoiceData::FinalRelease */
/*****************************************************************************
* CVoiceData::MapFile *
*------------------------*
* Description:
* Helper function used by SetObjectToken to map file. This function
* assumes that m_cpToken has been initialized.+++
********************************************************************* RAL ***/
HRESULT CVoiceData::MapFile( const WCHAR * pszTokenVal, // Value that contains file path
HANDLE * phMapping, // Pointer to file mapping handle
void ** ppvData ) // Pointer to the data
{
HRESULT hr = S_OK;
bool fWorked;
CSpDynamicString dstrFilePath;
hr = m_cpToken->GetStringValue( pszTokenVal, &dstrFilePath );
if ( SUCCEEDED( hr ) )
{
fWorked = false;
*phMapping = NULL;
*ppvData = NULL;
HANDLE hFile;
#ifndef _WIN32_WCE
hFile = g_Unicode.CreateFile(
dstrFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
#else //_WIN32_WCE
hFile = g_Unicode.CreateFileForMapping(
dstrFilePath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
#endif //_WIN32_WCE
if (hFile != INVALID_HANDLE_VALUE)
{
//-------------------------------------
// Make a unique map name from path
//-------------------------------------
long i;
for( i = 0; i < _MAX_PATH-1; i++ )
{
if( dstrFilePath[i] == 0 )
{
// End of string
break;
}
if( dstrFilePath[i] == '\\' )
{
//-------------------------------------
// Change backslash to underscore
//-------------------------------------
dstrFilePath[i] = '_';
}
}
*phMapping = g_Unicode.CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, dstrFilePath );
::CloseHandle( hFile );
}
if (*phMapping)
{
*ppvData = ::MapViewOfFile( *phMapping, FILE_MAP_READ, 0, 0, 0 );
if (*ppvData)
{
fWorked = true;
}
}
if (!fWorked)
{
hr = HRESULT_FROM_WIN32(::GetLastError());
if (hr == E_HANDLE)
{
hr &= 0xFFFFF000;
hr |= ERROR_FILE_NOT_FOUND;
}
if (*phMapping)
{
::CloseHandle(*phMapping);
*phMapping = NULL;
}
}
}
return hr;
} /* CVoiceData::MapFile */
/*****************************************************************************
* CVoiceData::SetObjectToken *
*-------------------------------*
* Description:
* This function performs the majority of the initialization of the voice.
* Once the object token has been provided, the filenames are read from the
* token key and the files are mapped.+++
********************************************************************* RAL ***/
STDMETHODIMP CVoiceData::SetObjectToken(ISpObjectToken * pToken)
{
SPDBG_FUNC( "CVoiceData::SetObjectToken" );
HRESULT hr = S_OK;
m_cpToken = pToken;
if ( SUCCEEDED( hr ) )
{
hr = MapFile( L"VoiceDef", &m_hVoiceDef, (void **)&m_pVoiceDef );
}
if ( SUCCEEDED( hr ) )
{
hr = MapFile( L"VoiceData", &m_hVoiceData, (void **)&m_pVoiceData );
}
//--- Init voice data pointers
if (SUCCEEDED(hr))
{
hr = InitVoiceData();
}
return hr;
} /* CVoiceData::SetObjectToken */
/*****************************************************************************
* CVoiceData::GetVoiceInfo *
*-----------------------------*
* Description:
* This method is used to retrieve the voice file data description.+++
********************************************************************* EDC ***/
STDMETHODIMP CVoiceData::GetVoiceInfo( MSVOICEINFO* pVoiceInfo )
{
SPDBG_FUNC( "CVoiceData::GetVoiceInfo" );
HRESULT hr = S_OK;
long i;
//--- Check args
if( ( SP_IS_BAD_WRITE_PTR( pVoiceInfo ) ) || ( m_pVoiceDef == NULL ) )
{
hr = E_INVALIDARG;
}
else
{
if (!m_cpToken)
{
hr = SPERR_UNINITIALIZED;
}
else
{
pVoiceInfo->pWindow = m_pWindow;
pVoiceInfo->FFTSize = m_FFTSize;
pVoiceInfo->LPCOrder = m_cOrder;
pVoiceInfo->ProsodyGain = m_pVoiceDef->ProsodyGain;
pVoiceInfo->eReverbType = m_pVoiceDef->ReverbType;
pVoiceInfo->Pitch = m_pVoiceDef->Pitch;
pVoiceInfo->Rate = m_pVoiceDef->Rate;
pVoiceInfo->LangID = m_pVoiceDef->LangID;
pVoiceInfo->SampleRate = m_pVoiceDef->SampleRate;
pVoiceInfo->VibratoFreq = m_pVoiceDef->VibratoFreq;
pVoiceInfo->VibratoDepth = m_pVoiceDef->VibratoDepth;
pVoiceInfo->NumOfTaps = m_pVoiceDef->NumOfTaps;
// Assumes voices are ALWAYS 16-bit mono (probably valid for now)***
pVoiceInfo->WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
pVoiceInfo->WaveFormatEx.nSamplesPerSec = pVoiceInfo->SampleRate;
pVoiceInfo->WaveFormatEx.wBitsPerSample = 16; // ***
pVoiceInfo->WaveFormatEx.nChannels = 1; // ***
pVoiceInfo->WaveFormatEx.nBlockAlign = (unsigned short)(pVoiceInfo->WaveFormatEx.nChannels * sizeof(short)); // ***
pVoiceInfo->WaveFormatEx.nAvgBytesPerSec = pVoiceInfo->WaveFormatEx.nSamplesPerSec * pVoiceInfo->WaveFormatEx.nBlockAlign;
pVoiceInfo->WaveFormatEx.cbSize = 0;
for (i = 0; i < MAXTAPS; i++)
{
pVoiceInfo->TapCoefficients[i] = m_pVoiceDef->TapCoefficients[i];
}
}
}
return hr;
} /* CVoiceData::GetVoiceInfo */
/*****************************************************************************
* CVoiceData::GetUnit *
*------------------------*
* Description:
* Retrieves and uncompresses audio data from the unit inventory. +++
*
********************************************************************* EDC ***/
STDMETHODIMP CVoiceData::GetUnitData( ULONG unitID, MSUNITDATA* pUnitData )
{
SPDBG_FUNC( "CVoiceData::GetUnit" );
HRESULT hr = S_OK;
//--- Check args
if( SP_IS_BAD_WRITE_PTR( pUnitData ) )
{
hr = E_INVALIDARG;
}
else if( unitID > m_NumOfUnits )
{
//--------------------------
// ID is out of range!
//--------------------------
hr = E_INVALIDARG;
}
else
{
if (!m_cpToken)
{
hr = SPERR_UNINITIALIZED;
}
else
{
if( m_CompressionType != COMPRESS_LPC )
{
//--------------------------------------
// Unsupported compression type
//--------------------------------------
hr = E_FAIL;
}
else
{
//-------------------------------------------------------------------
// Retrieve data from compressed inventory
//-------------------------------------------------------------------
hr = DecompressUnit( unitID, pUnitData );
}
}
}
return hr;
} /* CVoiceData::GetUnit */
/*****************************************************************************
* CVoiceData::AlloToUnit *
*---------------------------*
* Description:
* Converts FE allo code to BE unit phon code.+++
*
********************************************************************* EDC ***/
STDMETHODIMP CVoiceData::AlloToUnit( short allo, long attributes, long* pUnitID )
{
SPDBG_FUNC( "CVoiceData::AlloToUnit" );
HRESULT hr = S_OK;
long index;
union {
char c[2];
short s;
} temp;
char* pb;
//--- Check args
if( (SP_IS_BAD_READ_PTR( pUnitID )) || (allo >= m_NumOfAllos) )
{
hr = E_INVALIDARG;
}
else
{
index = (long)allo << 1; // 2 entries per phon
if( attributes & ALLO_IS_STRESSED )
{
//--- 2nd half
pb = (char*) &m_AlloToUnitTbl[index + (m_NumOfAllos << 1)];
}
else
{
pb = (char*) &m_AlloToUnitTbl[index];
}
// We read this way to avoid missaligned data accesses in 64bit.
temp.c[0] = *pb++;
temp.c[1] = *pb;
*pUnitID = (long) temp.s;
}
return hr;
} /* CVoiceData::AlloToUnit */
/*****************************************************************************
* CVoiceData::GetUnitIDs *
*---------------------------*
* Description:
* Gets the inventory triphone (in context) unit code.+++
*
********************************************************************* EDC ***/
STDMETHODIMP CVoiceData::GetUnitIDs( UNIT_CVT* pUnits, ULONG cUnits )
{
SPDBG_FUNC( "CVoiceData::GetUnitIDs" );
ULONG i;
ULONG curID, prevID, nextID;
ULONG curF, prevF, nextF;
char cPos;
ULONG senoneID;
UNALIGNED UNIT_STATS *pStats;
HRESULT hr = S_OK;
//--- Check args
if( (SP_IS_BAD_READ_PTR( pUnits)) ||
(SP_IS_BAD_WRITE_PTR( pUnits)) )
{
hr = E_INVALIDARG;
}
else
{
if (!m_cpToken)
{
hr = SPERR_UNINITIALIZED;
}
else
{
for( i = 0; i < cUnits; i++ )
{
//---------------------------
// CURRENT phon
//---------------------------
curID = pUnits[i].PhonID;
curF = pUnits[i].flags;
//---------------------------
// PREVIOUS phon
//---------------------------
if( i == 0 )
{
prevID = m_Sil_Index;
prevF = 0;
}
else
{
prevID = pUnits[i-1].PhonID;
prevF = pUnits[i-1].flags;
}
//---------------------------
// NEXT phon
//---------------------------
if( i >= cUnits -1 )
{
nextID = m_Sil_Index;
nextF = 0;
}
else
{
nextID = pUnits[i+1].PhonID;
nextF = pUnits[i+1].flags;
}
if( curID == m_Sil_Index )
{
//----------------------
// SILENCE phon
//----------------------
pUnits[i].UnitID = 0;
pUnits[i].SenoneID = 0;
pUnits[i].szUnitName[0] = 0;
pUnits[i].Dur = SIL_DURATION;
pUnits[i].Amp = 0;
pUnits[i].AmpRatio = 1.0f;
}
else
{
cPos = '\0';
if( curF & WORD_START_FLAG )
{
if( nextF & WORD_START_FLAG )
//---------------------------------------
// Both Cur and Next are word start
//---------------------------------------
cPos = 's';
else
//---------------------------------------
// Cur is word start
// Next is not
//---------------------------------------
cPos = 'b';
}
else if( nextF & WORD_START_FLAG )
{
//---------------------------------------
// Next is word start
// Cur is not
//---------------------------------------
cPos = 'e';
}
HRESULT hrt;
hrt = GetTriphoneID( m_pForest,
curID,
prevID,
nextID,
cPos,
m_pd,
&senoneID);
if( FAILED(hrt) )
{
//------------------------------------------------
// Instead of failing, I'll be robust and ignore
// the error. Force triphone to something that's
// valid.
//------------------------------------------------
senoneID = 0;
}
pUnits[i].UnitID = (m_pForest->gsOffset[curID] -
m_First_Context_Phone) + (senoneID + 1);
pUnits[i].SenoneID = senoneID;
//-----------------------------
// Get phon name strings
//-----------------------------
char *pName;
pName = PhonFromID( m_pd, pUnits[i].PhonID );
strcpy( &pUnits[i].szUnitName[0], pName );
//-----------------------------
// Get unit stats
//-----------------------------
pStats = (UNALIGNED UNIT_STATS*)(m_SenoneBlock[curID] + (char*)m_SenoneBlock);
pStats = &pStats[senoneID+1];
pStats = (UNALIGNED UNIT_STATS*)(m_SenoneBlock[curID] + (char*)m_SenoneBlock);
pStats = &pStats[senoneID-1];
pStats = (UNALIGNED UNIT_STATS*)(m_SenoneBlock[curID] + (char*)m_SenoneBlock);
pStats = &pStats[senoneID];
pUnits[i].Dur = pStats->dur / 1000.0f; // ms -> sec
pUnits[i].Amp = pStats->amp;
pUnits[i].AmpRatio = (float)sqrt(pStats->ampRatio);
//----------------------------------------------------------
// Looks like the "SENONE" table durations are
// incorrect (not even close!).
// Calc the real duration from inv epochs
// TODO: Make new table in voice data block
//----------------------------------------------------------
//hr = GetUnitDur( pUnits[i].UnitID, &pUnits[i].Dur );
if( FAILED(hr) )
{
break;
}
}
}
}
}
return hr;
} /* CVoiceData::GetUnitIDs */
/*****************************************************************************
* GetDataBlock *
*--------------*
* Description:
* Return ptr and length of specified voice data block. +++
*
********************************************************************** MC ***/
HRESULT CVoiceData::GetDataBlock( VOICEDATATYPE type, char **ppvOut, ULONG *pdwSize )
{
SPDBG_FUNC( "CVoiceData::GetDataBlock" );
long *offs;
HRESULT hr = S_OK;
long dataType;
if( !m_pVoiceData )
{
hr = E_INVALIDARG;
}
else
{
dataType = (long)type * 2; // x2 since each entry is an offset/length pair
offs = (long*)&m_pVoiceData->PhonOffset; // Table start
*ppvOut = offs[dataType] + ((char*)m_pVoiceData); // Offset -> abs address
*pdwSize = offs[dataType + 1];
}
return hr;
} /* CVoiceData::GetDataBlock */
/*****************************************************************************
* InitVoiceData *
*---------------*
* Description:
* Create pointers to voice data blocks from m_pVoiceData offsets.+++
*
********************************************************************** MC ***/
HRESULT CVoiceData::InitVoiceData()
{
SPDBG_FUNC( "CVoiceData::InitVoiceData" );
char *pRawData;
ULONG dataSize;
HRESULT hr = S_OK;
//------------------------------------------
// Check data type and version
//------------------------------------------
if( (m_pVoiceData != NULL)
&& (m_pVoiceData->Type == MS_DATA_TYPE)
&& (m_pVoiceData->Version == HEADER_VERSION) )
{
//-------------------------------
// Get ptr to PHONs
//-------------------------------
hr = GetDataBlock( MSVD_PHONE, &pRawData, &dataSize );
m_pd = (PHON_DICT*)pRawData;
//-------------------------------
// Get ptr to TREE
//-------------------------------
if( SUCCEEDED(hr) )
{
hr = GetDataBlock( MSVD_TREEIMAGE, &pRawData, &dataSize );
m_pForest = (TRIPHONE_TREE*)pRawData;
}
//-------------------------------
// Get ptr to SENONE
//-------------------------------
if( SUCCEEDED(hr) )
{
hr = GetDataBlock( MSVD_SENONE, &pRawData, &dataSize );
m_SenoneBlock = (long*)pRawData;
}
//-------------------------------
// Get ptr to ALLOID
//-------------------------------
if( SUCCEEDED(hr) )
{
hr = GetDataBlock( MSVD_ALLOID, &pRawData, &dataSize );
m_AlloToUnitTbl = (short*)pRawData;
m_NumOfAllos = dataSize / 8;
}
if( SUCCEEDED(hr) )
{
m_First_Context_Phone = m_pd->numCiPhones;
m_Sil_Index = PhonToID( m_pd, "SIL" );
}
//-----------------------------------------------------
// Init voice data INVENTORY parameters
//-----------------------------------------------------
if( SUCCEEDED(hr) )
{
hr = GetDataBlock( MSVD_INVENTORY, &pRawData, &dataSize );
if( SUCCEEDED(hr) )
{
m_pInv = (INVENTORY*)pRawData;
m_CompressionType = m_pVoiceDef->CompressionType;
//---------------------------------------------
// Convert REL to ABS
//---------------------------------------------
m_pUnit = (long*)((char*)m_pInv + m_pInv->UnitsOffset);
m_pTrig = (float*)((char*)m_pInv + m_pInv->TrigOffset);
m_pWindow = (float*)((char*)m_pInv + m_pInv->WindowOffset);
m_pGauss = (float*)((char*)m_pInv + m_pInv->pGaussOffset);
m_SampleRate = (float)m_pInv->SampleRate;
m_FFTSize = m_pInv->FFTSize;
m_cOrder = m_pInv->cOrder;
m_GaussID = 0;
m_NumOfUnits = m_pInv->cNumUnits;
}
}
}
else
{
//-------------------------
// Not a voice file!
//-------------------------
hr = E_FAIL;
}
return hr;
} /* CVoiceData::InitVoiceData */
/*****************************************************************************
* CVoiceData::DecompressUnit *
*-------------------------------*
* Description:
* Decompress acoustic unit.+++
*
* INPUT:
* UnitID - unit number (1 - 3333 typ)
*
* OUTPUT:
* Fills pSynth if success
*
********************************************************************** MC ***/
HRESULT CVoiceData::DecompressUnit( ULONG UnitID, MSUNITDATA* pSynth )
{
SPDBG_FUNC( "CVoiceData::DecompressUnit" );
long i, j, k, cNumEpochs, cBytes, cOrder = 0, VectDim;
long frameSize, cNumBins, startBin;
char *pCurStor;
unsigned char index;
float pLSP[MAX_LPCORDER], pFFT[MAX_FFTSIZE], pRes[MAX_FFTSIZE], Gain;
float *pCurLSP, *pCurLPC, *pMean, *pCurRes;
HRESULT hr = S_OK;
memset( pSynth, 0, sizeof(MSUNITDATA) );
//-----------------------------------------
// Pointer to unit data from inventory
//-----------------------------------------
pCurStor = (char*)((char*)m_pInv + m_pUnit[UnitID] ); // Rel to abs
//---------------------------------
// Get epoch count - 'cNumEpochs'
//---------------------------------
cBytes = sizeof(long);
memcpy( &cNumEpochs, pCurStor, cBytes );
pSynth->cNumEpochs = cNumEpochs;
pCurStor += cBytes;
//---------------------------------
// Get epoch lengths - 'pEpoch'
//---------------------------------
pSynth->pEpoch = new float[cNumEpochs];
if( pSynth->pEpoch == NULL )
{
hr = E_OUTOFMEMORY;
}
if( SUCCEEDED(hr) )
{
cBytes = DecompressEpoch( (signed char *) pCurStor, cNumEpochs, pSynth->pEpoch );
pCurStor += cBytes;
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
//
// Uncompress LPC coefficients...
//
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
cOrder = m_pInv->cOrder;
pSynth->cOrder = cOrder;
pSynth->pLPC = new float[cNumEpochs * (1 + cOrder)];
if( pSynth->pLPC == NULL )
{
hr = E_OUTOFMEMORY;
}
}
if( SUCCEEDED(hr) )
{
pCurLPC = pSynth->pLPC;
//---------------------------------
// ... for each epoch
//---------------------------------
for( i = 0; i < cNumEpochs; i++, pCurLPC += (1 + cOrder) )
{
//-------------------------------------
// Decode quantized LSP's...
//-------------------------------------
pCurLSP = pLSP;
for( k = 0; k < m_pInv->cNumLPCBooks; k++ )
{
VectDim = m_pInv->LPCBook[k].cCodeDim;
memcpy( &index, pCurStor, sizeof(char));
pCurStor += sizeof(char);
pMean = ((float*)((char*)m_pInv + m_pInv->LPCBook[k].pData)) + (index * VectDim);
for( j = 0; j < VectDim; j++ )
pCurLSP[j] = pMean[j];
pCurLSP += VectDim;
}
//--------------------------------------------------
// ...then convert to predictor coefficients
// (LSP's quantize better than PC's)
//--------------------------------------------------
LSPtoPC( pLSP, pCurLPC, cOrder, i );
}
//---------------------------------------
// Get pointer to residual gains
//---------------------------------------
cBytes = cNumEpochs * sizeof(float);
pSynth->pGain = (float*) pCurStor;
pCurStor += cBytes;
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
//
// Uncompress residual waveform
//
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
//--------------------------------------------
// First, figure out the buffer length...
//--------------------------------------------
pSynth->cNumSamples = 0;
for( j = 0; j < cNumEpochs; j++ )
{
pSynth->cNumSamples += (long) ABS(pSynth->pEpoch[j]);
}
//--------------------------------------------
// ...get buffer memory...
//--------------------------------------------
pSynth->pRes = new float[pSynth->cNumSamples];
if( pSynth->pRes == NULL )
{
hr = E_OUTOFMEMORY;
}
}
if( SUCCEEDED(hr) )
{
//--------------------------------------------
// ...and fill with uncompressed residual
//--------------------------------------------
pCurRes = pSynth->pRes;
for( i = 0; i < (long)pSynth->cNumEpochs; i++ )
{
//-------------------------------------
// Get epoch length
//-------------------------------------
frameSize = (long)(ABS(pSynth->pEpoch[i]));
// restore whisper
//if( (pSynth->pEpoch[i] > 0) && !(m_fModifiers & BACKEND_BITFLAG_WHISPER) )
if( pSynth->pEpoch[i] > 0 )
{
//-----------------------------------------------
// VOICED epoch
//-----------------------------------------------
if( (m_pInv->cNumDresBooks == 0) || (i == 0) || (pSynth->pEpoch[i - 1] < 0) )
{
//--------------------------------------
// Do static quantization
//--------------------------------------
for( j = 0; j < m_pInv->FFTSize; j++ )
{
pFFT[j] = 0.0f;
}
startBin = 1;
for( k = 0; k < m_pInv->cNumResBooks; k++ )
{
VectDim = m_pInv->ResBook[k].cCodeDim;
cNumBins = VectDim / 2;
memcpy( &index, pCurStor, sizeof(char) );
pCurStor += sizeof(char);
//------------------------------------------
// Uncompress spectrum using 'pResBook'
//------------------------------------------
pMean = ((float*)((char*)m_pInv + m_pInv->ResBook[k].pData)) + (index * VectDim);
PutSpectralBand( pFFT, pMean, startBin, cNumBins, m_pInv->FFTSize );
startBin += cNumBins;
}
}
else
{
//--------------------------------------
// Do delta quantization
//--------------------------------------
startBin = 1;
for( k = 0; k < m_pInv->cNumDresBooks; k++ )
{
VectDim = m_pInv->DresBook[k].cCodeDim;
cNumBins = VectDim / 2;
memcpy( &index, pCurStor, sizeof(char));
pCurStor += sizeof(char);
//------------------------------------------
// Uncompress spectrum using 'pDresBook'
//------------------------------------------
pMean = ((float*)((char*)m_pInv + m_pInv->DresBook[k].pData)) + (index * VectDim);
AddSpectralBand( pFFT, pMean, startBin, cNumBins, m_pInv->FFTSize );
startBin += cNumBins;
}
}
//--------------------------------------------------------
// Convert quantized FFT back to time residual
//--------------------------------------------------------
memcpy( pRes, pFFT, m_pInv->FFTSize * sizeof(float) ); // preserve original for delta residual
InverseFFT( pRes, m_pInv->FFTSize, m_pInv->FFTOrder, m_pTrig );
GainDeNormalize( pRes, (long)m_pInv->FFTSize, ((UNALIGNED float*)pSynth->pGain)[i] );
SetEpochLen( pCurRes, frameSize, pRes, m_pInv->FFTSize );
}
else
{
//-----------------------------------------------
// UNVOICED epoch
// NOTE: Assumes 'm_pGauss' is 1 sec
//-----------------------------------------------
Gain = 0.02f * ((UNALIGNED float*)pSynth->pGain)[i];
if( m_GaussID + frameSize >= m_pInv->SampleRate)
{
m_GaussID = 0;
}
//----------------------------------------------------------
// Generate gaussian random noise for unvoiced sounds
//----------------------------------------------------------
for( j = 0; j < frameSize; j++ )
{
pCurRes[j] = Gain * m_pGauss[j + m_GaussID];
}
m_GaussID += frameSize;
}
// restore whisper
/*if( (pSynth->pEpoch[i] > 0) && m_fModifiers & BACKEND_BITFLAG_WHISPER)
{
pSynth->pEpoch[i] = - pSynth->pEpoch[i];
}*/
pCurRes += frameSize;
}
}
if( FAILED(hr) )
{
//----------------------------------
// Cleanup allocated memory
//----------------------------------
if( pSynth->pEpoch )
{
delete pSynth->pEpoch;
pSynth->pEpoch = NULL;
}
if( pSynth->pRes )
{
delete pSynth->pRes;
pSynth->pRes = NULL;
}
if( pSynth->pLPC )
{
delete pSynth->pLPC;
pSynth->pLPC = NULL;
}
}
return hr;
} /* CVoiceData::DecompressUnit */
/*****************************************************************************
* CVoiceData::DecompressUnit *
*-------------------------------*
* Description:
* Decompress acoustic unit. +++
*
* INPUT:
* UnitID - unit number (1 - 3333 typ)
*
* OUTPUT:
* Fills pSynth if success
*
********************************************************************** MC ***/
HRESULT CVoiceData::GetUnitDur( ULONG UnitID, float* pDur )
{
SPDBG_FUNC( "CVoiceData::GetUnitDur" );
char *pCurStor;
float *pEpoch = NULL;
long cBytes, cNumEpochs, i;
float totalDur;
HRESULT hr = S_OK;
totalDur = 0;
if( UnitID > m_NumOfUnits )
{
//--------------------------
// ID is out of range!
//--------------------------
hr = E_INVALIDARG;
}
if( SUCCEEDED(hr) )
{
//-----------------------------------------
// Pointer to unit data from inventory
//-----------------------------------------
pCurStor = (char*)((char*)m_pInv + m_pUnit[UnitID] ); // Rel to abs
//---------------------------------
// Get epoch count - 'cNumEpochs'
//---------------------------------
cBytes = sizeof(long);
memcpy( &cNumEpochs, pCurStor, cBytes );
pCurStor += cBytes;
//---------------------------------
// Get epoch lengths - 'pEpoch'
//---------------------------------
pEpoch = new float[cNumEpochs];
if( pEpoch == NULL )
{
hr = E_OUTOFMEMORY;
}
if( SUCCEEDED(hr) )
{
cBytes = DecompressEpoch( (signed char *) pCurStor, cNumEpochs, pEpoch );
for( i = 0; i < cNumEpochs; i++)
{
totalDur += ABS(pEpoch[i]);
}
}
}
*pDur = totalDur / 22050;
//----------------------------------
// Cleanup allocated memory
//----------------------------------
if( pEpoch )
{
delete pEpoch;
}
return hr;
} /* CVoiceData::GetUnitDur */
/*****************************************************************************
* CVoiceData::DecompressEpoch *
*--------------------------------*
* Description:
* Decompress epoch len stream from RLE. Fills 'pEpoch' with lengths.
* Returns number of 'rgbyte' src bytes consumed.
*
********************************************************************** MC ***/
long CVoiceData::DecompressEpoch( signed char *rgbyte, long cNumEpochs, float *pEpoch )
{
SPDBG_FUNC( "CVoiceData::DecompressEpoch" );
long iDest, iSrc;
for( iSrc = 0, iDest = 0; iDest < cNumEpochs; ++iDest, ++iSrc )
{
//--------------------------------------
// Decode RLE for VOICED epochs
//--------------------------------------
if( rgbyte[iSrc] == 127 )
{
pEpoch[iDest] = 127.0f;
while( rgbyte[iSrc] == 127 )
{
pEpoch[iDest] += rgbyte[++iSrc];
}
}
//--------------------------------------
// Decode RLE for UNVOICED epochs
//--------------------------------------
else if( rgbyte[iSrc] == - 128 )
{
pEpoch[iDest] = - 128.0f;
while( rgbyte[iSrc] == - 128 )
pEpoch[iDest] += rgbyte[++iSrc];
}
//--------------------------------------
// No compression here
//--------------------------------------
else
{
pEpoch[iDest] = rgbyte[iSrc];
}
}
return iSrc;
} /* CVoiceData::DecompressEpoch */
/*****************************************************************************
* LSPCompare *
*------------*
* Description:
* QSORT callback
*
********************************************************************** MC ***/
static int __cdecl LSPCompare( const void *a, const void *b )
{
SPDBG_FUNC( "LSPCompare" );
if( *((PFLOAT) a) > *((PFLOAT) b) )
{
return 1;
}
else if( *((PFLOAT) a) == *((PFLOAT) b) )
{
return 0;
}
else
{
return -1;
}
} /* LSPCompare */
/*****************************************************************************
* CVoiceData::OrderLSP *
*-------------------------*
* Description:
* This routine reorders the LSP frequencies so that they are monotonic
*
********************************************************************** MC ***/
long CVoiceData::OrderLSP( PFLOAT pLSPFrame, INT cOrder )
{
SPDBG_FUNC( "CVoiceData::OrderLSP" );
long i, retCode = true;
for( i = 1; i < cOrder; i++ )
{
if( pLSPFrame[i - 1] > pLSPFrame[i] )
{
retCode = false;
}
}
qsort( (void *) pLSPFrame, (size_t) cOrder, (size_t) sizeof (float), LSPCompare );
return retCode;
} /* CVoiceData::OrderLSP */
/*****************************************************************************
* CVoiceData::LSPtoPC *
*------------------------*
* Description:
* Converts line spectral frequencies to LPC predictor coefficients.
*
********************************************************************** MC ***/
void CVoiceData::LSPtoPC( float *pLSP, float *pLPC, long cOrder, long /*frame*/ )
{
SPDBG_FUNC( "CVoiceData::LSPtoPC" );
long i, j, k, noh;
double freq[MAXNO], p[MAXNO / 2], q[MAXNO / 2];
double a[MAXNO / 2 + 1], a1[MAXNO / 2 + 1], a2[MAXNO / 2 + 1];
double b[MAXNO / 2 + 1], b1[MAXNO / 2 + 1], b2[MAXNO / 2 + 1];
double pi, xx, xf;
//----------------------------------
// Check for non-monotonic LSPs
//----------------------------------
for( i = 1; i < cOrder; i++ )
{
if( pLSP[i] <= pLSP[i - 1] )
{
//-----------------------------
// Reorder LSPs
//-----------------------------
OrderLSP( pLSP, cOrder );
break;
}
}
//--------------------------
// Initialization
//--------------------------
pi = KTWOPI;
noh = cOrder / 2;
for( j = 0; j < cOrder; j++ )
{
freq[j] = pLSP[j];
}
for( i = 0; i < noh + 1; i++ )
{
a[i] = 0.0f;
a1[i] = 0.0f;
a2[i] = 0.0f;
b[i] = 0.0f;
b1[i] = 0.0f;
b2[i] = 0.0f;
}
//-------------------------------------
// LSP filter parameters
//-------------------------------------
for( i = 0; i < noh; i++ )
{
p[i] = - 2.0 * cos( pi * freq[2 * i] );
q[i] = - 2.0 * cos( pi * freq[2 * i + 1] );
}
//-------------------------------------
// Impulse response of analysis filter
//-------------------------------------
xf = 0.0f;
for( k = 0; k < cOrder + 1; k++ )
{
xx = 0.0f;
if( k == 0 )
{
xx = 1.0f;
}
a[0] = xx + xf;
b[0] = xx - xf;
xf = xx;
for( i = 0; i < noh; i++ )
{
a[i + 1] = a[i] + p[i] * a1[i] + a2[i];
b[i + 1] = b[i] + q[i] * b1[i] + b2[i];
a2[i] = a1[i];
a1[i] = a[i];
b2[i] = b1[i];
b1[i] = b[i];
}
if( k != 0)
{
pLPC[k - 1] = (float) (- 0.5 * (a[noh] + b[noh]));
}
}
//-------------------------------------------------------
// Convert to predictor coefficient array configuration
//-------------------------------------------------------
for( i = cOrder - 1; i >= 0; i-- )
{
pLPC[i + 1] = - pLPC[i];
}
pLPC[0] = 1.0f;
} /* CVoiceData::LSPtoPC */
/*****************************************************************************
* CVoiceData::PutSpectralBand *
*--------------------------------*
* Description:
* This routine copies the frequency band specified by StartBin as
* is initial FFT bin, and containing cNumBins.
*
********************************************************************** MC ***/
void CVoiceData::PutSpectralBand( float *pFFT, float *pBand, long StartBin,
long cNumBins, long FFTSize )
{
SPDBG_FUNC( "CVoiceData::PutSpectralBand" );
long j, k, VectDim;
VectDim = 2 * cNumBins;
for( j = 0, k = StartBin; j < cNumBins; j++, k++ )
{
pFFT[k] = pBand[j];
}
k = FFTSize - (StartBin - 1 + cNumBins);
for( j = cNumBins; j < 2 * cNumBins; j++, k++ )
{
pFFT[k] = pBand[j];
}
} /* CVoiceData::PutSpectralBand */
/*****************************************************************************
* CVoiceData::AddSpectralBand *
*--------------------------------*
* Description:
* This routine adds the frequency band specified by StartBin as
* is initial FFT bin, and containing cNumBins, to the existing band.
*
********************************************************************** MC ***/
void CVoiceData::AddSpectralBand( float *pFFT, float *pBand, long StartBin,
long cNumBins, long FFTSize )
{
SPDBG_FUNC( "CVoiceData::AddSpectralBand" );
long j, k, VectDim;
VectDim = 2 * cNumBins;
for( j = 0, k = StartBin; j < cNumBins; j++, k++ )
{
pFFT[k] += pBand[j];
}
k = FFTSize - (StartBin - 1 + cNumBins);
for( j = cNumBins; j < 2 * cNumBins; j++, k++ )
{
pFFT[k] += pBand[j];
}
} /* CVoiceData::AddSpectralBand */
/*****************************************************************************
* CVoiceData::InverseFFT *
*---------------------------*
* Description:
* Return TRUE if consoants can be clustered.
* This subroutine computes a split-radix IFFT for real data
* It is a C version of the FORTRAN program in "Real-Valued
* Fast Fourier Transform Algorithms" by H. Sorensen et al.
* in Trans. on ASSP, June 1987, pp. 849-863. It uses half
* of the operations than its counterpart for complex data.
* *
* Length is n = 2^(fftOrder). Decimation in frequency. Result is
* in place. It uses table look-up for the trigonometric functions.
*
* Input order: *
* (Re[0], Re[1], ... Re[n/2], Im[n/2 - 1]...Im[1])
* Output order:
* (x[0], x[1], ... x[n - 1])
* The output transform exhibit hermitian symmetry (i.e. real
* part of transform is even while imaginary part is odd).
* Hence Im[0] = Im[n/2] = 0; and n memory locations suffice.
*
********************************************************************** MC ***/
void CVoiceData::InverseFFT( float *pDest, long fftSize, long fftOrder, float *sinePtr )
{
SPDBG_FUNC( "CVoiceData::InverseFFT" );
long n1, n2, n4, n8, i0, i1, i2, i3, i4, i5, i6, i7, i8;
long is, id, i, j, k, ie, ia, ia3;
float xt, t1, t2, t3, t4, t5, *cosPtr, r1, cc1, cc3, ss1, ss3;
cosPtr = sinePtr + (fftSize / 2);
//---------------------------------
// L shaped butterflies
//---------------------------------
n2 = 2 * fftSize;
ie = 1;
for( k = 1; k < fftOrder; k++ )
{
is = 0;
id = n2;
n2 = n2 / 2;
n4 = n2 / 4;
n8 = n4 / 2;
ie *= 2;
while( is < fftSize - 1 )
{
for( i = is; i < fftSize; i += id )
{
i1 = i;
i2 = i1 + n4;
i3 = i2 + n4;
i4 = i3 + n4;
t1 = pDest[i1] - pDest[i3];
pDest[i1] = pDest[i1] + pDest[i3];
pDest[i2] = 2 * pDest[i2];
pDest[i3] = t1 - 2 * pDest[i4];
pDest[i4] = t1 + 2 * pDest[i4];
if( n4 > 1 )
{
i1 = i1 + n8;
i2 = i2 + n8;
i3 = i3 + n8;
i4 = i4 + n8;
t1 = K2 * (pDest[i2] - pDest[i1]);
t2 = K2 * (pDest[i4] + pDest[i3]);
pDest[i1] = pDest[i1] + pDest[i2];
pDest[i2] = pDest[i4] - pDest[i3];
pDest[i3] = - 2 * (t1 + t2);
pDest[i4] = 2 * (t1 - t2);
}
}
is = 2 * id - n2;
id = 4 * id;
}
ia = 0;
for( j = 1; j < n8; j++ )
{
ia += ie;
ia3 = 3 * ia;
cc1 = cosPtr[ia];
ss1 = sinePtr[ia];
cc3 = cosPtr[ia3];
ss3 = sinePtr[ia3];
is = 0;
id = 2 * n2;
while( is < fftSize - 1 )
{
for( i = is; i < fftSize; i += id )
{
i1 = i + j;
i2 = i1 + n4;
i3 = i2 + n4;
i4 = i3 + n4;
i5 = i + n4 - j;
i6 = i5 + n4;
i7 = i6 + n4;
i8 = i7 + n4;
t1 = pDest[i1] - pDest[i6];
pDest[i1] = pDest[i1] + pDest[i6];
t2 = pDest[i5] - pDest[i2];
pDest[i5] = pDest[i2] + pDest[i5];
t3 = pDest[i8] + pDest[i3];
pDest[i6] = pDest[i8] - pDest[i3];
t4 = pDest[i4] + pDest[i7];
pDest[i2] = pDest[i4] - pDest[i7];
t5 = t1 - t4;
t1 = t1 + t4;
t4 = t2 - t3;
t2 = t2 + t3;
pDest[i3] = t5 * cc1 + t4 * ss1;
pDest[i7] = - t4 * cc1 + t5 * ss1;
pDest[i4] = t1 * cc3 - t2 * ss3;
pDest[i8] = t2 * cc3 + t1 * ss3;
}
is = 2 * id - n2;
id = 4 * id;
}
}
}
//---------------------------------
// length two butterflies
//---------------------------------
is = 0;
id = 4;
while( is < fftSize - 1 )
{
for( i0 = is; i0 < fftSize; i0 += id )
{
i1 = i0 + 1;
r1 = pDest[i0];
pDest[i0] = r1 + pDest[i1];
pDest[i1] = r1 - pDest[i1];
}
is = 2 * (id - 1);
id = 4 * id;
}
//---------------------------------
// digit reverse counter
//---------------------------------
j = 0;
n1 = fftSize - 1;
for( i = 0; i < n1; i++ )
{
if( i < j )
{
xt = pDest[j];
pDest[j] = pDest[i];
pDest[i] = xt;
}
k = fftSize / 2;
while( k <= j )
{
j -= k;
k /= 2;
}
j += k;
}
for( i = 0; i < fftSize; i++ )
{
pDest[i] /= fftSize;
}
} /* CVoiceData::InverseFFT */
/*****************************************************************************
* CVoiceData::SetEpochLen *
*----------------------*
* Description:
* Copy residual epoch to 'OutSize' length from 'pInRes' to 'pOutRes'
*
********************************************************************** MC ***/
void CVoiceData::SetEpochLen( float *pOutRes, long OutSize, float *pInRes,
long InSize )
{
SPDBG_FUNC( "CVoiceData::AddSpectralBand" );
long j, curFrame;
curFrame = MIN(InSize / 2, OutSize);
//-------------------------------
// Copy SRC to DEST
//-------------------------------
for( j = 0; j < curFrame; j++ )
pOutRes[j] = pInRes[j];
//-------------------------------
// Pad DEST if longer
//-------------------------------
for( j = curFrame; j < OutSize; j++ )
pOutRes[j] = 0.0f;
//-------------------------------
// Mix DEST if shorter
//-------------------------------
for( j = OutSize - curFrame; j < OutSize; j++ )
pOutRes[j] += pInRes[InSize - OutSize + j];
} /* CVoiceData::SetEpochLen */
/*****************************************************************************
* CVoiceData::GainDeNormalize *
*--------------------------------*
* Description:
* Scale residual to given gain.
*
********************************************************************** MC ***/
void CVoiceData::GainDeNormalize( float *pRes, long FFTSize, float Gain )
{
SPDBG_FUNC( "CVoiceData::GainDeNormalize" );
long j;
for( j = 0; j < FFTSize; j++ )
{
pRes[j] *= Gain;
}
} /* CVoiceData::GainDeNormalize */
/*****************************************************************************
* CVoiceData::PhonHashLookup *
*-------------------------------*
* Description:
* Lookup 'sym' in 'ht' and place its associated value in
* *val. If sym is not found place its key in *val.
* RETURN
* Return 0 indicating we found the 'sym' in the table.
* Return -1 'sym' is not in ht.
*
********************************************************************** MC ***/
long CVoiceData::PhonHashLookup(
PHON_DICT *pPD, // the hash table
char *sym, // The symbol to look up
long *val ) // Phon ID
{
SPDBG_FUNC( "CVoiceData::PhonHashLookup" );
char *cp;
unsigned long key;
long i;
HASH_TABLE *ht;
char *pStr;
HASH_ENTRY *pHE;
ht = &pPD->phonHash;
key = 0;
i = -1;
cp = sym;
pHE = (HASH_ENTRY*)((char*)pPD + ht->entryArrayOffs); // Offset to Abs address
do
{
key += *cp++ << (0xF & i--);
}
while( *cp );
while( true )
{
key %= ht->size;
if( pHE[key].obj == 0 )
{
//------------------------------
// Not in hash table!
//------------------------------
*val = (long) key;
return -1;
}
//-------------------------------
// Offset to Abs address
//-------------------------------
pStr = (char*)((char*)pPD + pHE[key].obj);
if( strcmp(pStr, sym) == 0 )
{
*val = pHE[key].val;
return 0;
}
key++;
}
} /* CVoiceData::PhonHashLookup */
/*****************************************************************************
* CVoiceData::PhonToID *
*-------------------------*
* Description:
* Return ID from phoneme string.
*
********************************************************************** MC ***/
long CVoiceData::PhonToID( PHON_DICT *pd, char *phone_str )
{
SPDBG_FUNC( "CVoiceData::PhonToID" );
long phon_id;
if( PhonHashLookup( pd, phone_str, &phon_id ) )
{
phon_id = NO_PHON;
}
return phon_id;
} /* CVoiceData::PhonToID */
/*****************************************************************************
* CVoiceData::PhonFromID *
*---------------------------*
* Description:
* Return string from phoneme ID
*
********************************************************************** MC ***/
char *CVoiceData::PhonFromID( PHON_DICT *pd, long phone_id )
{
SPDBG_FUNC( "CVoiceData::PhonFromID" );
char *strPtr;
long *pOffs;
pOffs = (long*)((char*)pd + pd->phones_list);
strPtr = (char*) ((char*)pd + pOffs[phone_id]);
return strPtr;
} /* CVoiceData::PhonFromID */
#define CNODE_ISA_LEAF(n) ((n)->yes < 0)
#define BADTREE_ERROR (-1)
#define PARAM_ERROR (-2)
#define END_OF_PROD 65535
#define WB_BEGIN 1
#define WB_END 2
#define WB_SINGLE 4
#define WB_WWT 8
#define POS_TYPE 4
#define GET_BIT(p,feat,i,b) \
{ \
(i) = ( (p)+POS_TYPE+(feat)->nstateq ) / 32; \
(b) = 1 << ( ((p)+POS_TYPE+(feat)->nstateq ) % 32); \
}
#define GET_RBIT(p,feat,i,b) \
{ \
GET_BIT(p,feat,i,b); \
(i) += (feat)->nint32perq; \
}
#define GET_CBIT(p,feat,i,b) \
{ \
GET_BIT(p,feat,i,b); \
(i) += 2 * (feat)->nint32perq; \
}
/*****************************************************************************
* AnswerQ *
*---------*
* Description:
* Tree node test.
*
********************************************************************** MC ***/
static _inline long AnswerQ( unsigned short *prod, long *uniq_prod,
long li, long bitpos, long ri, long rbitpos,
long pos, long nint32perProd)
{
UNALIGNED long *p;
for( ; *prod != END_OF_PROD; prod++ )
{
p = &uniq_prod[(*prod) * nint32perProd];
if( ((p[0] & pos) == pos) && (p[li] & bitpos) && (p[ri] & rbitpos) )
{
return true;
}
}
return false;
} /* AnswerQ */
/*****************************************************************************
* CVoiceData::GetTriphoneID *
*------------------------------*
* Description:
* Retrieve triphone ID from phoneme context.+++
* Store result into 'pResult'
*
********************************************************************** MC ***/
HRESULT CVoiceData::GetTriphoneID( TRIPHONE_TREE *forest,
long phon, // target phon
long leftPhon, // left context
long rightPhon, // right context
long pos, // word position ("b", "e" or "s"
PHON_DICT *pd,
ULONG *pResult)
{
SPDBG_FUNC( "CVoiceData::GetTriphoneID" );
C_NODE *cnode, *croot;
TREE_ELEM *tree = NULL;
long *uniq_prod;
char *ll, *rr;
long li, bitpos, ri, rbitpos, nint32perProd, c;
unsigned short *prodspace;
FEATURE *feat;
long *pOffs;
HRESULT hr = S_OK;
long triphoneID = 0;
if( (phon < 0) || (phon >= pd->numCiPhones) ||
(leftPhon < 0) || (leftPhon >= pd->numCiPhones) ||
(rightPhon < 0) || (rightPhon >= pd->numCiPhones) )
{
//--------------------------------
// Phon out of range!
//--------------------------------
hr = E_INVALIDARG;
}
if( SUCCEEDED(hr) )
{
c = phon;
tree = &forest->tree[c];
if( tree->nnodes == 0 )
{
//--------------------------------
// No CD triphones in tree!
//--------------------------------
hr = E_INVALIDARG;
}
}
if( SUCCEEDED(hr) )
{
if( pos == 'b' || pos == 'B' )
{
pos = WB_BEGIN;
}
else if( pos == 'e' || pos == 'E' )
{
pos = WB_END;
}
else if( pos == 's' || pos == 'S' )
{
pos = WB_SINGLE;
}
else if( pos == '\0' )
{
pos = WB_WWT;
}
else
{
//--------------------------------
// Unknown word position
//--------------------------------
hr = E_INVALIDARG;
}
}
if( SUCCEEDED(hr) )
{
pOffs = (long*)((char*)pd + pd->phones_list);
ll = (char*) ((char*)pd + pOffs[leftPhon]);
if( ll[0] == '+' || _strnicmp(ll, "SIL", 3) == 0 )
{
leftPhon = forest->silPhoneId;
}
rr = (char*) ((char*)pd + pOffs[rightPhon]);
if( rr[0] == '+' || _strnicmp(rr, "SIL", 3) == 0 ) // includes SIL
{
rightPhon = forest->silPhoneId;
}
else if( forest->nonSilCxt >= 0 && (pos == WB_END || pos == WB_SINGLE) )
{
rightPhon = forest->nonSilCxt;
}
feat = &forest->feat;
GET_BIT(leftPhon,feat,li,bitpos);
GET_RBIT(rightPhon,feat,ri,rbitpos);
uniq_prod = (long*)(forest->uniq_prod_Offset + (char*)forest); // Offset to ABS
croot = cnode = (C_NODE*)(tree->nodes + (char*)forest); // Offset to ABS
nint32perProd = forest->nint32perProd;
while( ! CNODE_ISA_LEAF(cnode) )
{
prodspace = (unsigned short*)((char*)forest + cnode->prod); // Offset to ABS
if( AnswerQ (prodspace, uniq_prod, li, bitpos, ri, rbitpos, pos, nint32perProd) )
{
cnode = &croot[cnode->yes];
}
else
{
cnode = &croot[cnode->no];
}
}
//-----------------------------
// Return successful result
//-----------------------------
triphoneID = (ULONG) cnode->no;
}
*pResult = triphoneID;
return hr;
} /* CVoiceData::GetTriphoneID */
/*****************************************************************************
* FIR_Filter *
*------------*
* Description:
* FIR filter. For an input x[n] it does an FIR filter with
* output y[n]. Result is in place. pHistory contains the last
* cNumTaps values.
*
* y[n] = pFilter[0] * x[n] + pFilter[1] * x[n - 1]
* + ... + pFilter[cNumTaps - 1] * x[n - cNumTaps - 1]
*
********************************************************************** MC ***/
void CVoiceData::FIR_Filter( float *pVector, long cNumSamples, float *pFilter,
float *pHistory, long cNumTaps )
{
SPDBG_FUNC( "CVoiceData::FIR_Filter" );
long i, j;
float sum;
for( i = 0; i < cNumSamples; i++ )
{
pHistory[0] = pVector[i];
sum = pHistory[0] * pFilter[0];
for( j = cNumTaps - 1; j > 0; j-- )
{
sum += pHistory[j] * pFilter[j];
pHistory[j] = pHistory[j - 1];
}
pVector[i] = sum;
}
} /* CVoiceData::FIR_Filter */
/*****************************************************************************
* IIR_Filter *
*------------*
* Description:
* IIR filter. For an input x[n] it does an IIR filter with
* output y[n]. Result is in place. pHistory contains the last
* cNumTaps values.
*
* y[n] = pFilter[0] * x[n] + pFilter[1] * y[n - 1]
* + ... + pFilter[cNumTaps - 1] * y[n - cNumTaps - 1]
*
********************************************************************** MC ***/
void CVoiceData::IIR_Filter( float *pVector, long cNumSamples, float *pFilter,
float *pHistory, long cNumTaps )
{
SPDBG_FUNC( "CVoiceData::IIR_Filter" );
long i, j;
float sum;
for( i = 0; i < cNumSamples; i++ )
{
sum = pVector[i] * pFilter[0];
for( j = cNumTaps - 1; j > 0; j-- )
{
pHistory[j] = pHistory[j - 1];
sum += pHistory[j] * pFilter[j];
}
pVector[i] = sum;
pHistory[0] = sum;
}
} /* CVoiceData::IIR_Filter */