You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
556 lines
14 KiB
556 lines
14 KiB
//
|
|
// lmlattice.cpp
|
|
//
|
|
// implelementation of ITfLMLattice object, IEnumTfLatticeElements object
|
|
//
|
|
|
|
#include "private.h"
|
|
#include "sapilayr.h"
|
|
#include "lmlattic.h"
|
|
|
|
//
|
|
// CLMLattice
|
|
//
|
|
//
|
|
|
|
// ctor / dtor
|
|
CLMLattice::CLMLattice(CSapiIMX *p_tip, IUnknown *pResWrap)
|
|
{
|
|
m_cpResWrap = pResWrap;
|
|
m_pTip = p_tip;
|
|
if (m_pTip)
|
|
{
|
|
m_pTip->AddRef();
|
|
}
|
|
m_cRef = 1;
|
|
}
|
|
|
|
CLMLattice::~CLMLattice()
|
|
{
|
|
if (m_pTip)
|
|
{
|
|
m_pTip->Release();
|
|
}
|
|
}
|
|
|
|
// IUnknown
|
|
HRESULT CLMLattice::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hr;
|
|
Assert(ppvObj);
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown)
|
|
|| IsEqualIID(riid, IID_ITfLMLattice))
|
|
{
|
|
*ppvObj = this;
|
|
hr = S_OK;
|
|
this->m_cRef++;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ULONG CLMLattice::AddRef(void)
|
|
{
|
|
this->m_cRef++;
|
|
return this->m_cRef;
|
|
}
|
|
|
|
ULONG CLMLattice::Release(void)
|
|
{
|
|
this->m_cRef--;
|
|
if (this->m_cRef > 0)
|
|
{
|
|
return this->m_cRef;
|
|
}
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// ITfLMLattice
|
|
HRESULT CLMLattice::QueryType(REFGUID refguidType, BOOL *pfSupported)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pfSupported)
|
|
{
|
|
*pfSupported = IsEqualGUID(refguidType, GUID_LMLATTICE_VER1_0);
|
|
if (*pfSupported)
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CLMLattice::EnumLatticeElements( DWORD dwFrameStart, REFGUID refguidType, IEnumTfLatticeElements **ppEnum)
|
|
{
|
|
if (!ppEnum)
|
|
return E_INVALIDARG;
|
|
|
|
*ppEnum = NULL;
|
|
|
|
if (!IsEqualGUID(refguidType, GUID_LMLATTICE_VER1_0))
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
// get alternates and cache the returned cotaskmem
|
|
ULONG ulcMaxAlt = m_pTip->_GetMaxAlternates();
|
|
ISpPhraseAlt **ppAlt = NULL;
|
|
|
|
CComPtr<IServiceProvider> cpServicePrv;
|
|
CComPtr<ISpRecoResult> cpRecoResult;
|
|
CRecoResultWrap *pWrap = NULL;
|
|
ULONG ulStartInWrp, ulNumInWrp;
|
|
|
|
// QI the service provider first then get to the sapi interface
|
|
//
|
|
hr = m_cpResWrap->QueryInterface(IID_IServiceProvider, (void **)&cpServicePrv);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_cpResWrap->QueryInterface(IID_PRIV_RESULTWRAP, (void **)&pWrap);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = cpServicePrv->QueryService(GUID_NULL, IID_ISpRecoResult, (void **)&cpRecoResult);
|
|
}
|
|
|
|
|
|
ulStartInWrp = pWrap->GetStart();
|
|
ulNumInWrp = pWrap->GetNumElements();
|
|
|
|
if ( SUCCEEDED(hr))
|
|
{
|
|
// Get the Alternates for current RecoResult.
|
|
ppAlt = (ISpPhraseAlt **)cicMemAlloc(ulcMaxAlt * sizeof(ISpPhraseAlt *));
|
|
if (ppAlt)
|
|
{
|
|
hr = cpRecoResult->GetAlternates(
|
|
ulStartInWrp,
|
|
ulNumInWrp,
|
|
ulcMaxAlt,
|
|
ppAlt, /* [out] ISpPhraseAlt **ppPhrases, */
|
|
&ulcMaxAlt /* [out] ULONG *pcPhrasesReturned */
|
|
);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
// OK now create an instance of enumerator
|
|
CEnumLatticeElements *pEnumLE = NULL;
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
pEnumLE = new CEnumLatticeElements(dwFrameStart);
|
|
|
|
if (!pEnumLE)
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
for ( ULONG i=0; i<ulcMaxAlt; i++)
|
|
{
|
|
SPPHRASE *pPhrase = NULL;
|
|
ULONG ulStart, ulNum;
|
|
ULONG ulStartInPar, ulNumInParent;
|
|
|
|
ppAlt[i]->GetPhrase(&pPhrase);
|
|
ppAlt[i]->GetAltInfo(NULL, &ulStartInPar, &ulNumInParent, &ulNum);
|
|
|
|
if ( (ulStartInPar >= ulStartInWrp) && (ulStartInPar+ulNumInParent <= ulStartInWrp+ulNumInWrp) )
|
|
{
|
|
// This is a valid alternate
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
ulStart = ulStartInPar;
|
|
hr = pEnumLE->_InitFromPhrase(pPhrase, ulStart, ulNum);
|
|
}
|
|
}
|
|
|
|
if (pPhrase)
|
|
{
|
|
CoTaskMemFree(pPhrase);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
hr = pEnumLE->QueryInterface(IID_IEnumTfLatticeElements, (void **)ppEnum);
|
|
}
|
|
|
|
SafeRelease(pEnumLE);
|
|
|
|
if ( ppAlt )
|
|
{
|
|
// Release references to alternate phrases.
|
|
for (int i = 0; i < (int)ulcMaxAlt; i++)
|
|
{
|
|
if (NULL != (ppAlt)[i])
|
|
{
|
|
((ppAlt)[i])->Release();
|
|
}
|
|
}
|
|
|
|
cicMemFree(ppAlt);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// CEnumLatticeElements
|
|
//
|
|
//
|
|
|
|
// ctor / dtor
|
|
CEnumLatticeElements::CEnumLatticeElements(DWORD dwFrameStart)
|
|
{
|
|
m_dwFrameStart = dwFrameStart;
|
|
m_ulCur = (ULONG)-1;
|
|
m_ulTotal = 0;
|
|
|
|
m_cRef = 1;
|
|
}
|
|
|
|
CEnumLatticeElements::~CEnumLatticeElements()
|
|
{
|
|
// clean up the lattice elements here
|
|
int ulCount;
|
|
TF_LMLATTELEMENT * pLE;
|
|
|
|
ulCount = (int) Count( );
|
|
|
|
TraceMsg(TF_GENERAL, "CEnumLatticeElements::~CEnumLatticeElements: ulCount=%d", ulCount);
|
|
|
|
if (ulCount)
|
|
{
|
|
for (int i = 0; i < ulCount; i++)
|
|
{
|
|
pLE = GetPtr(i);
|
|
if ( pLE && pLE->bstrText)
|
|
{
|
|
::SysFreeString(pLE->bstrText);
|
|
pLE->bstrText=0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// IUnknown
|
|
HRESULT CEnumLatticeElements::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
HRESULT hr;
|
|
Assert(ppvObj);
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown)
|
|
|| IsEqualIID(riid, IID_IEnumTfLatticeElements))
|
|
{
|
|
*ppvObj = this;
|
|
hr = S_OK;
|
|
this->m_cRef++;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
ULONG CEnumLatticeElements::AddRef(void)
|
|
{
|
|
this->m_cRef++;
|
|
return this->m_cRef;
|
|
}
|
|
|
|
ULONG CEnumLatticeElements::Release(void)
|
|
{
|
|
this->m_cRef--;
|
|
if (this->m_cRef > 0)
|
|
{
|
|
return this->m_cRef;
|
|
}
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
// ITfEnumLatticeElements
|
|
HRESULT CEnumLatticeElements::Clone(IEnumTfLatticeElements **ppEnum)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
if (ppEnum)
|
|
{
|
|
CEnumLatticeElements *pele = new CEnumLatticeElements(m_dwFrameStart);
|
|
|
|
if ( !pele )
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (pele->Append(Count()))
|
|
{
|
|
for (int i = 0; i < Count(); i++)
|
|
{
|
|
*(pele->GetPtr(i)) = *GetPtr(i);
|
|
Assert((pele->GetPtr(i))->bstrText);
|
|
(pele->GetPtr(i))->bstrText = SysAllocString(GetPtr(i)->bstrText);
|
|
|
|
}
|
|
|
|
pele->m_dwFrameStart = m_dwFrameStart;
|
|
hr = pele->QueryInterface(IID_IEnumTfLatticeElements, (void **)ppEnum);
|
|
}
|
|
else
|
|
{
|
|
delete pele;
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
HRESULT CEnumLatticeElements::Next(ULONG ulCount, TF_LMLATTELEMENT *rgsElements, ULONG *pcFetched)
|
|
{
|
|
if (ulCount == 0
|
|
|| rgsElements == NULL
|
|
|| pcFetched == NULL
|
|
)
|
|
return E_INVALIDARG;
|
|
|
|
// find the start position
|
|
if (m_dwFrameStart == -1)
|
|
{
|
|
m_ulCur = m_dwFrameStart = 0;
|
|
}
|
|
else
|
|
{
|
|
if (m_ulCur == (ULONG)-1)
|
|
{
|
|
_Find(m_dwFrameStart, &m_ulCur);
|
|
}
|
|
}
|
|
|
|
if (m_ulCur >= m_ulTotal)
|
|
{
|
|
// no more elements but OK
|
|
*pcFetched = 0;
|
|
}
|
|
else
|
|
{
|
|
// something to return
|
|
for (ULONG ul = m_ulCur;
|
|
ul < m_ulTotal && ul - m_ulCur < ulCount;
|
|
ul++)
|
|
{
|
|
rgsElements[ul-m_ulCur] = *GetPtr(ul);
|
|
}
|
|
*pcFetched = ul - m_ulCur;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CEnumLatticeElements::Reset()
|
|
{
|
|
m_ulCur = (ULONG)-1;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CEnumLatticeElements::Skip(ULONG ulCount)
|
|
{
|
|
// find the start position
|
|
if (m_dwFrameStart == -1)
|
|
{
|
|
m_ulCur = m_dwFrameStart = 0;
|
|
}
|
|
else
|
|
{
|
|
if (m_ulCur == (ULONG)-1)
|
|
{
|
|
_Find(m_dwFrameStart, &m_ulCur);
|
|
}
|
|
}
|
|
|
|
m_ulCur += ulCount;
|
|
|
|
if (m_ulCur > m_ulTotal)
|
|
m_ulCur = m_ulTotal;
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//
|
|
// internal APIs
|
|
//
|
|
|
|
HRESULT CEnumLatticeElements::_InitFromPhrase
|
|
(
|
|
SPPHRASE *pPhrase,
|
|
ULONG ulStartElem,
|
|
ULONG ulNumElem
|
|
)
|
|
{
|
|
Assert(pPhrase);
|
|
|
|
if ( pPhrase == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// allocate the initial slots
|
|
if (!Append(ulNumElem))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
long lEndElem;
|
|
long indexOrgList;
|
|
long indexNewList;
|
|
|
|
lEndElem = min(pPhrase->Rule.ulCountOfElements, ulStartElem + ulNumElem);
|
|
lEndElem --; // Real position ( offset from 0 ) for the last element
|
|
|
|
indexNewList = Count( ) - 1;
|
|
indexOrgList = indexNewList - ulNumElem;
|
|
|
|
m_ulTotal += ulNumElem;
|
|
|
|
TraceMsg(TF_GENERAL, "_InitFromPhrase: m_ulTotal=%d", m_ulTotal);
|
|
|
|
// FutureConsider: ITN has to be considered here!
|
|
for (long i=lEndElem; i>=(long)ulStartElem; i--)
|
|
{
|
|
TF_LMLATTELEMENT * pLE;
|
|
|
|
// Compare all the elements in the Org list from End to start
|
|
// with this new element's dwFrameStart,
|
|
// If dwFrameStart of the element in Org list is larger than(or equal to)
|
|
// this element's dwFrameStart, just move the org element
|
|
// to the current available position in the new list.
|
|
|
|
// until we find an element in the org list whose dwFrameStart is less than
|
|
// this element's dwFrameStart. we need to move this element to the
|
|
// new current available item in the new list.
|
|
|
|
// Current available position in the new list is from End to Start.
|
|
|
|
while ( (indexOrgList >=0) && (indexNewList >=0) && (S_OK == hr) )
|
|
{
|
|
pLE = GetPtr(indexOrgList);
|
|
if (pLE)
|
|
{
|
|
if ( pLE->dwFrameStart >= pPhrase->pElements[i].ulAudioTimeOffset )
|
|
{
|
|
// Move this Org element to a new postion in new List.
|
|
TF_LMLATTELEMENT * pNewLE;
|
|
|
|
pNewLE = GetPtr(indexNewList);
|
|
if ( pNewLE)
|
|
{
|
|
pNewLE->dwFrameStart = pLE->dwFrameStart;
|
|
pNewLE->dwFrameLen = pLE->dwFrameLen;
|
|
pNewLE->dwFlags = pLE->dwFlags;
|
|
pNewLE->iCost = pLE->iCost;
|
|
pNewLE->bstrText = pLE->bstrText;
|
|
|
|
pLE->dwFrameStart = 0;
|
|
pLE->dwFrameLen = 0;
|
|
pLE->dwFlags = 0;
|
|
pLE->iCost = 0;
|
|
pLE->bstrText = 0;
|
|
}
|
|
|
|
// update the index position in both org and new list
|
|
indexNewList --;
|
|
indexOrgList --;
|
|
}
|
|
else
|
|
{
|
|
// current element from this phrase should be moved to the new list
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_GENERAL, "CEnumLatticeElements::_InitFromPhrase: pLE is NULL");
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
} //while
|
|
|
|
|
|
if ( (S_OK == hr) && (indexNewList >=0) )
|
|
{
|
|
pLE = GetPtr(indexNewList);
|
|
if (pLE)
|
|
{
|
|
pLE->dwFrameStart = pPhrase->pElements[i].ulAudioTimeOffset;
|
|
pLE->dwFrameLen = pPhrase->pElements[i].ulAudioSizeTime;
|
|
|
|
pLE->dwFlags = 0; // for now
|
|
pLE->iCost = pPhrase->pElements[i].ActualConfidence;
|
|
|
|
pLE->bstrText = SysAllocString(pPhrase->pElements[i].pszDisplayText);
|
|
|
|
TraceMsg(TF_GENERAL, "i=%d, dwFramStart=%d bstrText=%S", i, pLE->dwFrameStart, pLE->bstrText);
|
|
|
|
indexNewList--;
|
|
}
|
|
}
|
|
|
|
} // for
|
|
} // if
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// _Find()
|
|
//
|
|
// slightly modified version of array find
|
|
//
|
|
ULONG CEnumLatticeElements::_Find(DWORD dwFrame, ULONG *pul)
|
|
{
|
|
int iMatch = -1;
|
|
int iMid = -1;
|
|
int iMin = 0;
|
|
int iMax = _cElems;
|
|
|
|
while(iMin < iMax)
|
|
{
|
|
iMid = (iMin + iMax) / 2;
|
|
DWORD dwCur = GetPtr(iMid)->dwFrameStart;
|
|
if (dwFrame < dwCur)
|
|
{
|
|
iMax = iMid;
|
|
}
|
|
else if (dwFrame > dwCur)
|
|
{
|
|
iMin = iMid + 1;
|
|
}
|
|
else
|
|
{
|
|
iMatch = iMid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pul)
|
|
{
|
|
if ((iMatch == -1) && (iMid >= 0))
|
|
{
|
|
if (dwFrame < GetPtr(iMid)->dwFrameStart)
|
|
iMid--;
|
|
}
|
|
*pul = iMid;
|
|
}
|
|
return iMatch;
|
|
}
|