一个通用的IBM viavoice语音识别语音朗读的接口,适用于基于IBM viavoice开发


//------------------------------------------------------------------------------
// sapi.cpp  -  IBM Sapi speech engine interface
//------------------------------------------------------------------------------

#include "stdafx.h"
#include "winnls.h"

#ifndef _SPEECH_
#include "objbase.h"
#include "initguid.h"
#include <objerror.h>
#include <speech.h>
#include <ibmspch.h>
#include <mmsystem.h>
#endif

#include "SRWrapEn.h"
#include "myresource.h"
#include "global.hpp"
#include "sapi.hpp"


DWORD               ListenKey;
WantNotifications tellMe;  // Notification Sink flags
const char   *pGStopPhr; // "stop dictation" phrase for various languages

//------------------------------------------------------------------------------
// Description: SapiSpeech class implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description: constructor
//------------------------------------------------------------------------------
SapiSpeech:: SapiSpeech(CEdit *pCEdit)
{
 pGStopPhr = 0;

 m_pCEdit   = pCEdit;
 m_pSpchCentral  = 0;
 m_pSpchEngSink  = 0;
 m_pSpchDctSink  = 0;
 m_pSpchGramDict  = 0;
 m_pGramCommon  = 0;
 m_pStatusLB         = 0;
 
    m_pLtdGramCommon    = 0;   
 m_pSpchLtdSink      = 0;   

 // setup the nofification sink's notifications.
 memset(&tellMe, 0, sizeof(tellMe));
 tellMe.bDctPhraseStart  = TRUE;
 tellMe.bDctPhraseHypothesis = TRUE;
 tellMe.bDctPhraseFinish  = TRUE;

    // initialize the speech engine and grammars for Dictation
 if ( !initForDictation(SRSEQUENCE_CONTINUOUS) )
    {
  if ( !initForDictation(SRSEQUENCE_DISCRETE) )
   state = RC_SPEECH_FAILED;
  else
   state = RC_SUCCESS;
    }
 else
    {
  state = RC_SUCCESS;
    }
}

//------------------------------------------------------------------------------
// Description: destructor
//------------------------------------------------------------------------------
SapiSpeech:: ~SapiSpeech()
{
 m_pStatusLB = 0;
 
 terminate();
}

//------------------------------------------------------------------------------
// Description: terminate speech session... cleanup
//------------------------------------------------------------------------------
void SapiSpeech:: terminate()
{
 deactivate();

 if (m_pSpchCentral && m_pSpchEngSink->m_dwKey )
    m_pSpchCentral->UnRegister( m_pSpchEngSink->m_dwKey );

 if (m_pIBMAcoustics)
  m_pIBMAcoustics->Release();

 if (m_pSpchCentral)
  m_pSpchCentral->Release();

 if( m_pSpchGramDict )   m_pSpchGramDict->Release();

 if( m_pGramCommon ) m_pGramCommon->Release();
   
    if ( m_pLtdGramCommon )  m_pLtdGramCommon->Release();


    if (m_pISRListen )
    {
     if (m_dwListenKey)
       m_pISRListen->Unregister(m_dwListenKey);

  m_pISRListen->Release();
    }
 if( m_pGramActionCommon ) m_pGramActionCommon->Release();
}

//----------------------------------------------------------------------------------------------
// Description: Initializes the Speech engine via SAPI. Only the IBM dictation speech engine
//    is searched.
//----------------------------------------------------------------------------------------------
int SapiSpeech:: initForDictation(int Sequencing)
{
 HRESULT      hRes;
 SRMODEINFO     wantSRMode;
 SRMODEINFO     gotSRMode;
 PISRFIND     pFind  = 0;
 PISRENUM     pEnum  = 0;
 PIAUDIOMULTIMEDIADEVICE  pMMDev  = 0;
 int                      yes=1, no=0;
    int                      success = yes;
 

 //
 // First we create the enumerator so we can search for the IBM dictation engine
 //
 hRes = CoCreateInstance( CLSID_SREnumerator, NULL, CLSCTX_ALL, IID_ISREnum, (void**)&pEnum );
 if( FAILED(hRes) ) 
 {
  pEnum = NULL;
  Error(hRes, TEXT("Error creating SREnumerator (CoCreateInstance)."), NULL, MB_OK );
  goto initForDictation_done;
 }

 ASSERT( pEnum );

 // Get the find interface so we can search for the IBM dictation engine
 hRes = pEnum->QueryInterface(IID_ISRFind, (void**)&pFind);
 pEnum->Release(); pEnum = 0;
 if( FAILED(hRes) )
 {
  pFind = NULL;
  Error( hRes, _T("Could not create PISRFIND interface") );
  goto initForDictation_done;
 }

 //Setup the SRMODEINFO structure with the parameters we are interested in having in out speech
 // engine. Then use the enumerator to find the engine we want.
 memset( &wantSRMode, 0, sizeof(SRMODEINFO) );
 hRes = MultiByteToWideChar(CP_ACP, 0, "IBM", -1, wantSRMode.szMfgName, SRMI_NAMELEN);
 wantSRMode.dwGrammars = SRGRAM_DICTATION | SRGRAM_LIMITEDDOMAIN;

 wantSRMode.dwSequencing = Sequencing;

 hRes = pFind->Find( &wantSRMode, NULL, &gotSRMode );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Failed trying to find engine mode (Find)") );
  goto initForDictation_done;
 }

 // Did we get the IBM dictation engine???
 if (wcscmp(wantSRMode.szMfgName, gotSRMode.szMfgName) != 0)
 {
  Error(-1, TEXT("Could not find IBM dictation engine"));
        success = no;
  goto initForDictation_done;
 }

 //
 // It is preferred to not share the dictation engine. Usually, it does not make sense to do so.
 // Therefore, create a non-shared dictation engine. For a nonshared engine, we must get the
 // mmdevice
 //
 hRes = CoCreateInstance( CLSID_MMAudioSource, NULL, CLSCTX_ALL, IID_IAudioMultiMediaDevice, (void**)&pMMDev);
 if( FAILED(hRes))
 {
  Error(hRes, TEXT("CoCreateInstance for mm device failed in EngModeSelect()."));
  goto initForDictation_done;
 }

 hRes = pMMDev->DeviceNumSet( WAVE_MAPPER );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Error in IAudioMultimediaDevice::DeviceNumSet().") );
 }

 // Select now...

 // if the mode was found using the ISRFind interface then use the Find::Select()...
 hRes = pFind->Select(gotSRMode.gModeID, &m_pSpchCentral, (LPUNKNOWN)pMMDev);

 pMMDev->Release();
 pMMDev = 0;

 pFind->Release();
 pFind = 0;

 if (FAILED(hRes))
 {
  Error(hRes, TEXT("Could not select the engine"));
  m_pSpchCentral = 0;
  goto initForDictation_done;
 }

 if (0 == m_pSpchCentral)
 {
  Error(hRes, TEXT("Failed to create speech engine (m_pSpchCentral = 0)"));
        success = no;
  goto initForDictation_done;
 }


 // register the notification object to the engine
 m_pSpchEngSink = new SpchEngSink(this);
 hRes = m_pSpchCentral->Register (m_pSpchEngSink, IID_ISRNotifySink, &(m_pSpchEngSink->m_dwKey) );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Error Registering engine notification class") );
  m_pSpchEngSink = 0;
  goto initForDictation_done;
 }
                                  
    hRes = m_pSpchCentral->QueryInterface(IID_IIBM_SRListen, (void**)&m_pISRListen);
 
    if (FAILED(hRes))
 {
  Error( hRes, TEXT("Error Querying IBM Listen Extension") );
  m_pISRListen = 0;
  goto initForDictation_done;
 }

 m_pISRListen->Register(&m_dwListenKey);

 //
 // In order to work in non-US languages, the phrase to stop dictation needs to reflect the language
 // we are working in.
 //
 const char   *pGramLangSuffix;
 GUID engGuid = gotSRMode.gModeID;
 pGramLangSuffix = getGrammarLanguageSuffix(engGuid);
 pGStopPhr  = getStopPhrase(pGramLangSuffix);
 
    //
 // Create the dictation and limited-domain grammars in memory and load
    // them into the engine.
 //
    success = initGrammars( pGStopPhr );

    hRes = m_pSpchCentral->QueryInterface(IID_IIBM_SRDialogs, (void**)&m_pIBMTrainDialog);
 
    if (FAILED(hRes))
 {
  Error( hRes, TEXT("Error Querying IBM Dialogs Extension") );
  m_pIBMTrainDialog = 0;
  goto initForDictation_done;
 }
   
    hRes = m_pSpchCentral->QueryInterface(IID_IIBM_SRAcousticPronunciations, (void**)&m_pIBMAcoustics);
 
    if (FAILED(hRes))
 {
  Error( hRes, TEXT("Error Querying IBM Acoustic Pronunciations Extension") );
  m_pIBMAcoustics = 0;
  goto initForDictation_done;
 }

initForDictation_done:
 if (pMMDev) pMMDev->Release();
 if (pFind) pFind->Release();

 if (FAILED(hRes))
 {
        success = no;
    }

 if ( success == no && Sequencing == SRSEQUENCE_CONTINUOUS )
 {
  AfxMessageBox(TEXT("Now, trying for discrete engine"));
 }

    return success;
}

//----------------------------------------------------------------------------------------------
// Description: Initializes the Dictation and Limite-domain Grammars for SAPI speech.
//----------------------------------------------------------------------------------------------
int SapiSpeech:: initGrammars( const char * const stopPhrase )
{
 int       Actionlen,wordlen;
 HRESULT      hRes;
 SDATA      dictGram, ltdGram, actionGram;
 PSRCHUNK     pSRChunk = 0;
 PSRHEADER     pSRHeader = 0;
 PSRACTIONVERB            pSRActionVerb = 0;
 LPUNKNOWN     lpUnkDict  = 0;
 LPUNKNOWN     lpUnkLtd   = 0;
 LPUNKNOWN     lpUnkAction= 0;
    int                      yes=1, no=0;
    int                      success = yes;
 
   
    dictGram.pData = 0;

 //
 // Create the dictation grammar in memory and load it into the engine.
 
 //

    wordlen = strlen(stopPhrase) * 2 + 2;  // +2 for ending null

 dictGram.dwSize = sizeof(SRHEADER) + sizeof(SRCHUNK) + wordlen;
 dictGram.pData = (void*) new unsigned int[dictGram.dwSize];

 pSRHeader = (SRHEADER *)dictGram.pData;
    pSRHeader->dwType = SRHDRTYPE_DICTATION;
    pSRHeader->dwFlags = SRHDRFLAG_UNICODE;
   
   
    pSRChunk = (SRCHUNK *) ((PBYTE)dictGram.pData + sizeof(SRHEADER));
 pSRChunk->dwChunkID = SRCKD_SUBTOPIC;
 pSRChunk->dwChunkSize = wordlen;
 MultiByteToWideChar(CP_ACP, 0, "dummy", -1, (unsigned short *)&pSRChunk->avInfo[0], wordlen);


 m_pSpchDctSink = new SpchDctSink(this);
 hRes = m_pSpchCentral->GrammarLoad( SRGRMFMT_DICTATION,
          dictGram,
          (PVOID)m_pSpchDctSink,
          IID_ISRGramNotifySink,
          &lpUnkDict );
 if( FAILED(hRes))
 {
  Error(hRes, TEXT("Could not load the dictation grammar"));
  goto initGrammars_done;
 }


 /*------------------------------------------------------------------------------------*/
 /* Now that we have the Unknown to the grammer object, lets get the common interface. */
 /*------------------------------------------------------------------------------------*/
 hRes = lpUnkDict->QueryInterface( IID_ISRGramCommon, (void**)&m_pGramCommon );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get ISRGramCommon interface."));
  goto initGrammars_done;
 }
 
 hRes = lpUnkDict->QueryInterface( IID_ISRGramDictation, (void**)&m_pSpchGramDict );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get the ISRGramDictation interface."));
  goto initGrammars_done;
 }

    hRes = lpUnkDict->QueryInterface( IID_IIBM_SRGramDictation, (void**)&m_pIBMGramDict );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get the IBM SRGramDictation interface."));
  goto initGrammars_done;
 }
   

 //
 // Create the limited-domain grammar in memory and load it into the engine.
 //
    ltdGram.pData = 0;

 wordlen = strlen(stopPhrase) * 2 + 2;  // +2 for ending null

 ltdGram.dwSize = sizeof(SRHEADER) + sizeof(SRCHUNK) + wordlen;
 ltdGram.pData = (void*) new unsigned int[ltdGram.dwSize];

 pSRHeader = (SRHEADER *)ltdGram.pData;
    pSRHeader->dwType = SRHDRTYPE_LIMITEDDOMAIN;
    pSRHeader->dwFlags = SRHDRFLAG_UNICODE;

 pSRChunk = (SRCHUNK *) ((PBYTE)ltdGram.pData + sizeof(SRHEADER));
 pSRChunk->dwChunkID = SRCKLD_WORDS;
 pSRChunk->dwChunkSize = wordlen;
 MultiByteToWideChar(CP_ACP, 0, stopPhrase, -1, (unsigned short *)&pSRChunk->avInfo[0], wordlen);


 m_pSpchLtdSink = new SpchLtdSink(this);
 hRes = m_pSpchCentral->GrammarLoad( SRGRMFMT_LIMITEDDOMAIN,
          ltdGram,
          (PVOID)m_pSpchLtdSink,
          IID_ISRGramNotifySink,
          &lpUnkLtd );
 if( FAILED(hRes))
 {
  Error(hRes, TEXT("Could not load the dictation grammar"));
  goto initGrammars_done;
 }


    /*------------------------------------------------------------------------------------*/
 /* Now that we have the Unknown to the grammer object, lets get the Action interface. */
 /*------------------------------------------------------------------------------------*/
 hRes = lpUnkLtd->QueryInterface( IID_IIBM_SRUpdateWords, (void**)&m_pIBMUpdateWords );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get IBM SRUpdateWords interface."));
  goto initGrammars_done;
 }


 /*------------------------------------------------------------------------------------*/
 /* Now that we have the Unknown to the grammer object, lets get the common interface. */
 /*------------------------------------------------------------------------------------*/
 hRes = lpUnkLtd->QueryInterface( IID_ISRGramCommon, (void**)&m_pLtdGramCommon );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get ISRGramCommon interface."));
  goto initGrammars_done;
 }

 

    actionGram.pData = 0;

   
 Actionlen = strlen("sel") * 2 + 2;
 wordlen = strlen("dummy") * 2 + 2;


 actionGram.dwSize = sizeof(SRHEADER) + (sizeof(SRCHUNK) *2) + sizeof(SRACTIONVERB) + Actionlen + wordlen;
 actionGram.pData = (void*) new unsigned int[actionGram.dwSize];

 // Set Header Data
 pSRHeader = (SRHEADER *)actionGram.pData;
    pSRHeader->dwType = IBM_SRHDRTYPE_ACTION;
    pSRHeader->dwFlags = SRHDRFLAG_UNICODE;
   

    // Fill in Chunk Data
    pSRChunk = (SRCHUNK *) ((PBYTE)actionGram.pData + sizeof(SRHEADER));
 pSRChunk->dwChunkID = SRCKACTION_ACTIONVERB;
 pSRChunk->dwChunkSize = sizeof(SRACTIONVERB) + Actionlen;
   
 // Fill In Action Verb Data

    pSRActionVerb = (PSRACTIONVERB)((PBYTE)actionGram.pData + sizeof(SRHEADER)+ sizeof(SRCHUNK));
 pSRActionVerb->dwSize = sizeof(SRACTIONVERB) + Actionlen;
    pSRActionVerb->dwActionNum = 1;
 MultiByteToWideChar(CP_ACP, 0, "sel", -1, (unsigned short *)&pSRActionVerb->szString[0], Actionlen);

 // Fill in Word  Data
    pSRChunk = (SRCHUNK *) ((PBYTE)pSRActionVerb + sizeof(SRACTIONVERB) + Actionlen);
 pSRChunk->dwChunkID = SRCKACTION_WORDSSEQUENCE;
 pSRChunk->dwChunkSize = wordlen;
    MultiByteToWideChar(CP_ACP, 0, "dummy", -1, (unsigned short *)&pSRChunk->avInfo[0], wordlen);

    m_pSpchActionSink = new SpchActionSink(this);
 hRes = m_pSpchCentral->GrammarLoad( (SRGRMFMT) IBM_SRGRMFMT_ACTION,
          actionGram,
          (PVOID)m_pSpchActionSink,
          IID_ISRGramNotifySink,
          &lpUnkAction );
 if( FAILED(hRes))
 {
  Error(hRes, TEXT("Could not load the IBM Action grammar"));
  goto initGrammars_done;
 }


    /*------------------------------------------------------------------------------------*/
 /* Now that we have the Unknown to the grammer object, lets get the Action interface. */
 /*------------------------------------------------------------------------------------*/
 hRes = lpUnkAction->QueryInterface( IID_IIBM_SRGramAction, (void**)&m_pGramAction );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get IBM SRGramAction interface."));
  goto initGrammars_done;
 }

    hRes = lpUnkAction->QueryInterface( IID_ISRGramCommon, (void**)&m_pGramActionCommon );
 if (FAILED(hRes))
 {
  Error( hRes, TEXT("Could not get ISRGramCommon interface."));
  goto initGrammars_done;
 }


   


initGrammars_done:
 if (lpUnkDict) lpUnkDict->Release();
 if (dictGram.pData) delete dictGram.pData;
 if (lpUnkLtd) lpUnkLtd->Release();
 if (ltdGram.pData) delete ltdGram.pData;

 if (lpUnkAction) lpUnkAction->Release();
 if (actionGram.pData) delete actionGram.pData;

 if (FAILED(hRes))
 {
        success = no;
    }

    return success;
}

//--------------------------------------------------------------------------
// Description: returns the "stop dictation" phrase that is appropriate for
//    the current language.
//--------------------------------------------------------------------------
const char *SapiSpeech:: getStopPhrase(const char *pCountryCode)
{
 if (0 == strcmp(pCountryCode, "US")) return "stop dictation"; // United States
 if (0 == strcmp(pCountryCode, "UK")) return "stop dictation"; // United Kingdom
 if (0 == strcmp(pCountryCode, "FR")) return "stop dictation"; // French
 if (0 == strcmp(pCountryCode, "GR")) return "stop dictation"; // German
 if (0 == strcmp(pCountryCode, "IT")) return "stop dictation"; // Italian
 if (0 == strcmp(pCountryCode, "ES")) return "stop dictation"; // Spanish

 return "unknown language";
}

//--------------------------------------------------------------------------
// Description: returns the prefix for the grammars based upon which language
//              we are in.                                         
//--------------------------------------------------------------------------
const char * SapiSpeech:: getGrammarLanguageSuffix(GUID &engGuid)
{
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeUS ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeUS)  // US english
  return "US";
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeUK ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeUK)  // UK english
  return "UK";
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeFR ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeFR)  // french
  return "FR";
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeGR ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeGR)  // german
  return "GR";
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeIT ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeIT)  // italian
  return "IT";
 if (engGuid == CLSID_SREngineEnumIBMDiscreteDictationModeES ||
  engGuid == CLSID_SREngineEnumIBMContinuousDictationModeES)  // spanish
  return "ES";

 return "";
}
 
//--------------------------------------------------------------------------
// Description: Activates the Grammar
//--------------------------------------------------------------------------
int SapiSpeech:: activate(BOOL pause)
{
 HRESULT hres;

    m_pCEdit->SetFocus();

 hres = m_pISRListen->StartListening(m_dwListenKey);
 if ( FAILED(hres) )
    {
        return( hres );
    }

    hres = m_pGramCommon->Activate( m_pCEdit->GetParent()->m_hWnd, pause, NULL );
    if ( FAILED(hres) )
    {
     return( hres );
    }

 

 return m_pLtdGramCommon->Activate( m_pCEdit->GetParent()->m_hWnd, pause, NULL );
 
}

//--------------------------------------------------------------------------
// Description: Deactivates the Grammar
//--------------------------------------------------------------------------
int SapiSpeech:: deactivate()
{
 HRESULT hres;

    if (0 != m_pISRListen)
    {
      hres = m_pISRListen->StopListening(m_dwListenKey);
   if ( FAILED(hres) )
   {
        return( hres );
   }
    }

    if (0 != m_pGramCommon)
    {
        hres = m_pGramCommon->Deactivate(NULL);
        if ( FAILED(hres) )
        {
            return hres;
        }
    }

    if (0 != m_pLtdGramCommon)
    {
        hres = m_pLtdGramCommon->Deactivate(NULL);
        if ( FAILED(hres) )
        {
            return hres;
        }
    }

    return RC_SUCCESS;
}

//--------------------------------------------------------------------------
// Description: Activates an Action in an action Grammar
//--------------------------------------------------------------------------
int SapiSpeech:: ActivateAction(char * szAction)
{
 HRESULT hres;
 WCHAR   wszAction[100];

   
// Activate Action Specified

    hres = MultiByteToWideChar(CP_ACP, 0, szAction, -1, wszAction, 100);
    hres = m_pGramActionCommon->Activate( m_pCEdit->GetParent()->m_hWnd, false, wszAction );
   

 return hres;
 
}

//--------------------------------------------------------------------------
// Description: Activates an Action in an action Grammar
//--------------------------------------------------------------------------
int SapiSpeech:: DeActivateAction(char * szAction)
{
 HRESULT hres;
    WCHAR   wszAction[100];
   
// Activate Action Specified

    hres = MultiByteToWideChar(CP_ACP, 0, szAction, -1, wszAction, 100);
    hres = m_pGramActionCommon->Deactivate(wszAction );
   

 return hres;
 
}

 


//--------------------------------------------------------------------------
// Description: This logs the events from the grammar sink and the engine sink.
//--------------------------------------------------------------------------
void SapiSpeech::logEventSink(SPCHEVENTID id, char *fmt, ...)
{
    static char buf[1000];
    va_list args;
    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);

 if (m_pStatusLB)
  m_pStatusLB->AddString(buf);
 else
 {
  TRACE(buf);
  TRACE("/n");
 }
}

//----------------------------------------------------------------------------------------------
// Description: reset the context for word(s) that are to be corrected.
//----------------------------------------------------------------------------------------------
int  SapiSpeech:: resetContext( void )
{

 PWSTR  pszPrior = NULL;
 PWSTR  pszAfter = NULL;

 // reset the context... prior and after words are null
 HRESULT hres = m_pSpchGramDict->Context( pszPrior, pszAfter );
 if ( hres != NOERROR )
    {
        return 0;
    }

 return 1;
}

void SapiSpeech::DisplayTopics(CListBox *pLB)
{
 HRESULT      hRes;
    PIIBM_SRSUBTOPIC         pISRTopic  = 0;
 PCWSTR                   pTopicList = NULL;
 DWORD                    dwTopicSize;
 char                     szTopic[256];


 hRes = m_pSpchCentral->QueryInterface(IID_IIBM_SRSubTopic, (void**)&pISRTopic);

 if (FAILED(hRes))
 {
   Error( hRes, TEXT("Error Querying IBM Topics Extension") );
   return;
 }
 else
 {
 pISRTopic->EnumSubTopics(&dwTopicSize,&pTopicList);

 // loop through all of the Topics and display them...

    if (dwTopicSize > 0)
 { 
  WCHAR *  pSRWord= (WCHAR *) pTopicList;
  WCHAR *  pSRMax = (WCHAR *) ((BYTE*)pTopicList + (dwTopicSize-2));
  while( pSRWord < pSRMax)
  {
  int count = WideCharToMultiByte(CP_ACP, NULL, (unsigned short *)pSRWord, -1, szTopic, dwTopicSize, NULL, NULL);
  if (count == 0)
  {
   Error( -1000, TEXT("WideCharToMultiByte failed") );
   continue;
  }
  else
  {
   if (pLB)
     pLB->AddString(szTopic);
  }

        pSRWord = (WCHAR *) pSRWord + count;
  
  }
 }

 pISRTopic->Release();
 if (pTopicList)
   CoTaskMemFree((VOID*)pTopicList);
 }
 return;
}


//------------------------------------------------------------------------------
// Description: Speech engine notification sink implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description: constructor
//------------------------------------------------------------------------------
SpchEngSink::SpchEngSink( SapiSpeech *pSpchObj )
{
 m_pSpchObj = pSpchObj;
 m_dwRefCnt = 0;
}

//----------------------------------------------------------------------------------------------
// Description: destructor
//----------------------------------------------------------------------------------------------
SpchEngSink::~SpchEngSink()
{
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::QueryInterface( REFIID riid, LPVOID *ppv )
{
 *ppv = NULL;

 // always return our IUnkown for IID_IUnknown...
 if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID(riid,IID_ISRNotifySink))
 {
  AddRef();
  *ppv = (LPVOID)this;
  return S_OK;
 }

 // otherwise, cant find...
 return ResultFromScode (E_NOINTERFACE);
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_ (ULONG) SpchEngSink::AddRef()
{
 return ++m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) SpchEngSink::Release()
{
 if( --m_dwRefCnt == 0 )
 {
  delete this;
  return 0;
 }
 return m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::AttribChanged( DWORD dwAttribID )
{
 if (tellMe.bEngAttribChanged)
  m_pSpchObj->logEventSink(ENG_ATTRIBCHANGED, TEXT("Attrib Id: 0x%x"), dwAttribID);

 return NOERROR;
}


//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::Interference( QWORD qTimeStampBegin,QWORD qTimeStampEnd, DWORD dwType )
{
 if (tellMe.bEngInterference)
  m_pSpchObj->logEventSink(ENG_INTERFERENCE, TEXT("Interference Beg: %I64x End: %I64x Type: 0x%04x"),
        qTimeStampBegin, qTimeStampEnd, dwType);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::Sound( QWORD qTimeStampBegin, QWORD qTimeStampEnd )
{
 if (tellMe.bEngSound)
  m_pSpchObj->logEventSink(ENG_SOUND, TEXT("Sound: Beg: %I64x, end %I64x"), qTimeStampBegin, qTimeStampEnd);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::UtteranceBegin( QWORD qTimeStampBegin )
{
 if (tellMe.bEngUtteranceBegin)
  m_pSpchObj->logEventSink(ENG_UTTERANCEBEGIN, TEXT("UtteranceBeg Beg: %I64x"), qTimeStampBegin);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::UtteranceEnd( QWORD qTimeStampBegin,QWORD qTimeStampEnd )
{
 if (tellMe.bEngUtteranceEnd)
  m_pSpchObj->logEventSink(ENG_UTTERANCEEND, TEXT("UtteranceEnd      Beg: %I64x End: %I64x"), qTimeStampBegin, qTimeStampEnd);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchEngSink::VUMeter( QWORD qTimeStampBegin, WORD wLevel )
{
 if (tellMe.bEngVUMeter)
  m_pSpchObj->logEventSink(ENG_VUMETER, TEXT("VUMeter Beg: %I64x Level: 0x%04x"), qTimeStampBegin, wLevel);

 return NOERROR;
}


//------------------------------------------------------------------------------
// Description: Dictation Grammar notification sink implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description: constructor
//------------------------------------------------------------------------------
SpchDctSink::SpchDctSink( SapiSpeech *pSpch)
:m_ResList(pSpch)
{
 m_pSpchObj = pSpch;
 m_dwRefCnt = 0;
}

//----------------------------------------------------------------------------------------------
// Description: destructor
//----------------------------------------------------------------------------------------------
SpchDctSink::~SpchDctSink()
{
}


//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::QueryInterface( REFIID riid, LPVOID *ppv )
{
 *ppv = NULL;

 // always return our IUnknown for IID_IUnknown...
 if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID(riid,IID_ISRGramNotifySink))
 {
  AddRef();
  *ppv = (LPVOID)this;
  return S_OK;
 }

 // otherwise, cant find...
 return ResultFromScode (E_NOINTERFACE);
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_ (ULONG) SpchDctSink::AddRef()
{
 return ++m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) SpchDctSink::Release()
{
 if( --m_dwRefCnt == 0 )
 {
  delete this;
  return 0;
 }
 return m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::BookMark( DWORD dwID )
{
 if (tellMe.bDctBookmark)
        m_pSpchObj->logEventSink(DCT_BOOKMARK, TEXT("Dict:BookMark id: 0x%lx"), dwID);
 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::Paused()
{
 if (tellMe.bDctPaused)
        m_pSpchObj->logEventSink(DCT_PAUSED, TEXT("Dict:Paused..."));

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::PhraseStart( QWORD qTimeStampBegin )
{
 if (tellMe.bDctPhraseStart)
        m_pSpchObj->logEventSink(DCT_PHRASESTART, TEXT("Dict:PhraseStart Beg: %I64x"), qTimeStampBegin );

 m_ResList.dctPhStart(qTimeStampBegin);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::PhraseHypothesis( DWORD dwFlags, QWORD qTimeStampBegin,
   QWORD qTimeStampEnd, PSRPHRASE pSRPhrase, LPUNKNOWN lpResults )
{
 if (tellMe.bDctPhraseHypothesis)
        m_pSpchObj->logEventSink(DCT_PHRASEHYPOTHESIS, TEXT("Dict:PhraseHypothesis Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );

 char  buf[MAX_PHRASELEN];
 CString  phrase;

    // Make sure that the reco is for us
    if ( !(dwFlags & ISRNOTEFIN_THISGRAMMAR)) return NOERROR;
 if ( !(dwFlags & ISRNOTEFIN_RECOGNIZED )) return NOERROR;

    // unrecognized utterance
 if( !pSRPhrase )
  return NOERROR;

 // loop through all of the words and display them...
 PSRWORD  pSRWord = (PSRWORD) (pSRPhrase->abWords);
 PSRWORD  pSRMax = (PSRWORD) ((BYTE*)pSRPhrase + pSRPhrase->dwSize);
 while( pSRWord < pSRMax )
 {
  int count = WideCharToMultiByte(CP_ACP, NULL, pSRWord->szWord, -1, buf, MAX_PHRASELEN, NULL, NULL);
  if (count = 0)
  {
   Error( -1000, TEXT("Dct PhraseHypothesis: WideCharToMultiByte failed") );
   continue;
  }
  if (phrase.GetLength() > 0)
         phrase += " ";
  phrase += buf;
  pSRWord = (PSRWORD) ((BYTE*) pSRWord + pSRWord->dwSize);
 }

 m_ResList.dctPhHypothesis(phrase);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::PhraseFinish( DWORD     dwFlags,
                                          QWORD     qTimeStampBegin,
                                          QWORD     qTimeStampEnd,
                                          PSRPHRASE pSRPhrase,
                                          LPUNKNOWN lpResults )
{
 char buf[MAX_PHRASELEN];


    // Make sure that the reco is for us
    if ( !(dwFlags & ISRNOTEFIN_THISGRAMMAR)) return NOERROR;
 if ( !(dwFlags & ISRNOTEFIN_RECOGNIZED )) return NOERROR;

 if (tellMe.bDctPhraseFinish)
        m_pSpchObj->logEventSink(DCT_PHRASEFINISH, TEXT("Dict:PhraseFinish Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );

 PSRWORD  pSRWord, pSRMax;
 CString  phrase;

    // unrecognized utterance
 if( !pSRPhrase )
  return NOERROR;

 // loop through all of the words and display them...
 pSRMax  = (PSRWORD) ((BYTE*)pSRPhrase + pSRPhrase->dwSize);
 pSRWord = (PSRWORD) (pSRPhrase->abWords);
 while( pSRWord < pSRMax )
 {
  int count = WideCharToMultiByte(CP_ACP, NULL, pSRWord->szWord, -1, buf, MAX_PHRASELEN, NULL, NULL);
  if (count = 0)
  {
   Error( -1000, TEXT("Dct PhraseHypothesis: WideCharToMultiByte failed") );
   continue;
  }

  // store the phrase to display in the results list box...
  if( lpResults )
  {
   if (phrase.GetLength() > 0)
             phrase += " ";
   phrase += buf;
  }
  pSRWord = (PSRWORD) ((BYTE*) pSRWord + pSRWord->dwSize);
 }

 if ("" == phrase)         // new phrase is empty
  return NOERROR;

 return m_ResList.dctText(lpResults, phrase);

   
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::ReEvaluate( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctReevaluate)
        m_pSpchObj->logEventSink(DCT_REEVALUATE, TEXT("Dict:Reevaluate lpUnk: %08x"), lpUnk);

 if ( 0 == lpUnk ) return NOERROR;

// Let the ResultList do its thing for correction.
 m_ResList.dctReevaluate(lpUnk);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::Training( DWORD dwTrain )
{
 if (tellMe.bDctTraining)
        m_pSpchObj->logEventSink(DCT_TRAINING, TEXT("Dict:TrainingRequest Flag: 0x%lx."), dwTrain );

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchDctSink::UnArchive( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctUnarchive)
        m_pSpchObj->logEventSink(DCT_UNARCHIVE, TEXT("Dict:Unarchive lpUnk: %08x"), lpUnk);

 return NOERROR;
}

 


//------------------------------------------------------------------------------
// Description: Limited-domain Grammar notification sink implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description: constructor
//------------------------------------------------------------------------------
SpchLtdSink::SpchLtdSink( SapiSpeech *pSpch)
:m_ResList(pSpch)
{
 m_pSpchObj = pSpch;
 m_dwRefCnt = 0;
}

//----------------------------------------------------------------------------------------------
// Description: destructor
//----------------------------------------------------------------------------------------------
SpchLtdSink::~SpchLtdSink()
{
}


//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::QueryInterface( REFIID riid, LPVOID *ppv )
{
 *ppv = NULL;

 // always return our IUnknown for IID_IUnknown...
 if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID(riid,IID_ISRGramNotifySink))
 {
  AddRef();
  *ppv = (LPVOID)this;
  return S_OK;
 }

 // otherwise, cant find...
 return ResultFromScode (E_NOINTERFACE);
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_ (ULONG) SpchLtdSink::AddRef()
{
 return ++m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) SpchLtdSink::Release()
{
 if( --m_dwRefCnt == 0 )
 {
  delete this;
  return 0;
 }
 return m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::BookMark( DWORD dwID )
{
 if (tellMe.bDctBookmark)
        m_pSpchObj->logEventSink(DCT_BOOKMARK, TEXT("Ltd:BookMark id: 0x%lx"), dwID);
 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::Paused()
{
 if (tellMe.bDctPaused)
        m_pSpchObj->logEventSink(DCT_PAUSED, TEXT("Ltd:Paused..."));

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::PhraseStart( QWORD qTimeStampBegin )
{
 if (tellMe.bDctPhraseStart)
        m_pSpchObj->logEventSink(DCT_PHRASESTART, TEXT("Ltd:PhraseStart Beg: %I64x"), qTimeStampBegin );

 m_ResList.dctPhStart(qTimeStampBegin);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::PhraseHypothesis( DWORD dwFlags, QWORD qTimeStampBegin,
   QWORD qTimeStampEnd, PSRPHRASE pSRPhrase, LPUNKNOWN lpResults )
{
 if (tellMe.bDctPhraseHypothesis)
        m_pSpchObj->logEventSink(DCT_PHRASEHYPOTHESIS, TEXT("Ltd:PhraseHypothesis Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec...
//              The "stop dictation" phrase is searched for here. If it is found, then dictaiton
//    is deactivated. Note that additional PhraseFinish invocation will still come
//    since the speech engine will firm up all remaining word
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::PhraseFinish( DWORD     dwFlags,
                                          QWORD     qTimeStampBegin,
                                          QWORD     qTimeStampEnd,
                                          PSRPHRASE pSRPhrase,
                                          LPUNKNOWN lpResults )
{
 char buf[MAX_PHRASELEN];


    // Make sure that the reco is for us
    if ( !(dwFlags & ISRNOTEFIN_THISGRAMMAR)) return NOERROR;
    if ( !(dwFlags & ISRNOTEFIN_RECOGNIZED )) return NOERROR;

 if (tellMe.bDctPhraseFinish)
        m_pSpchObj->logEventSink(DCT_PHRASEFINISH, TEXT("Ltd:PhraseFinish Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );

 PSRWORD  pSRWord, pSRMax;
 CString  phrase;

    // unrecognized utterance
 if( !pSRPhrase )
  return NOERROR;

 // loop through all of the words and display them...
 pSRMax  = (PSRWORD) ((BYTE*)pSRPhrase + pSRPhrase->dwSize);
 pSRWord = (PSRWORD) (pSRPhrase->abWords);
 while( pSRWord < pSRMax )
 {
  int count = WideCharToMultiByte(CP_ACP, NULL, pSRWord->szWord, -1, buf, MAX_PHRASELEN, NULL, NULL);
  if (count = 0)
  {
   Error( -1000, TEXT("Ltd PhraseHypothesis: WideCharToMultiByte failed") );
   continue;
  }

  // store the phrase to display in the results list box...
  if (phrase.GetLength() > 0)
         phrase += " ";
  phrase += buf;

        pSRWord = (PSRWORD) ((BYTE*) pSRWord + pSRWord->dwSize);
 }

 if ("" == phrase)         // new phrase is empty
  return NOERROR;

    // did we recognize the stop dictation phrase for this language
 if ( phrase.Compare(pGStopPhr) == 0 )
 {
  m_pSpchObj->m_pCEdit->GetParent()->PostMessage(WM_DICT_STOPPING, 0, 0);
 }


  
    return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::ReEvaluate( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctReevaluate)
        m_pSpchObj->logEventSink(DCT_REEVALUATE, TEXT("Ltd:Reevaluate lpUnk: %08x"), lpUnk);

 if ( 0 == lpUnk ) return NOERROR;

 // Let the ResultList do its thing for correction.
 m_ResList.dctReevaluate(lpUnk);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::Training( DWORD dwTrain )
{
 if (tellMe.bDctTraining)
        m_pSpchObj->logEventSink(DCT_TRAINING, TEXT("Ltd:TrainingRequest Flag: 0x%lx."), dwTrain );

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchLtdSink::UnArchive( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctUnarchive)
        m_pSpchObj->logEventSink(DCT_UNARCHIVE, TEXT("Ltd:Unarchive lpUnk: %08x"), lpUnk);

 return NOERROR;
}

 


//------------------------------------------------------------------------------
// Description: Action Grammar notification sink implementation
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Description: constructor
//------------------------------------------------------------------------------
SpchActionSink::SpchActionSink( SapiSpeech *pSpch)
:m_ResList(pSpch)
{
 m_pSpchObj = pSpch;
 m_dwRefCnt = 0;
}

//----------------------------------------------------------------------------------------------
// Description: destructor
//----------------------------------------------------------------------------------------------
SpchActionSink::~SpchActionSink()
{
}


//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::QueryInterface( REFIID riid, LPVOID *ppv )
{
 *ppv = NULL;

 // always return our IUnknown for IID_IUnknown...
 if (IsEqualIID (riid, IID_IUnknown) || IsEqualIID(riid,IID_ISRGramNotifySink))
 {
  AddRef();
  *ppv = (LPVOID)this;
  return S_OK;
 }

 // otherwise, cant find...
 return ResultFromScode (E_NOINTERFACE);
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_ (ULONG) SpchActionSink::AddRef()
{
 return ++m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP_(ULONG) SpchActionSink::Release()
{
 if( --m_dwRefCnt == 0 )
 {
  delete this;
  return 0;
 }
 return m_dwRefCnt;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::BookMark( DWORD dwID )
{
 if (tellMe.bDctBookmark)
        m_pSpchObj->logEventSink(DCT_BOOKMARK, TEXT("Action:BookMark id: 0x%lx"), dwID);
 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::Paused()
{
 if (tellMe.bDctPaused)
        m_pSpchObj->logEventSink(DCT_PAUSED, TEXT("Action:Paused..."));

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::PhraseStart( QWORD qTimeStampBegin )
{
 if (tellMe.bDctPhraseStart)
        m_pSpchObj->logEventSink(DCT_PHRASESTART, TEXT("Action:PhraseStart Beg: %I64x"), qTimeStampBegin );

 m_ResList.dctPhStart(qTimeStampBegin);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::PhraseHypothesis( DWORD dwFlags, QWORD qTimeStampBegin,
   QWORD qTimeStampEnd, PSRPHRASE pSRPhrase, LPUNKNOWN lpResults )
{
 if (tellMe.bDctPhraseHypothesis)
        m_pSpchObj->logEventSink(DCT_PHRASEHYPOTHESIS, TEXT("Action:PhraseHypothesis Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec...
//              The "stop dictation" phrase is searched for here. If it is found, then dictaiton
//    is deactivated. Note that additional PhraseFinish invocation will still come
//    since the speech engine will firm up all remaining word
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::PhraseFinish( DWORD     dwFlags,
                                           QWORD     qTimeStampBegin,
                                           QWORD     qTimeStampEnd,
                                           PSRPHRASE pSRPhrase,
                                           LPUNKNOWN lpResults )
{
 char buf[MAX_PHRASELEN];
 DWORD   dwActionID = 0; 


    // Make sure that the reco is for us
    if ( !(dwFlags & ISRNOTEFIN_THISGRAMMAR)) return NOERROR;
    if ( !(dwFlags & ISRNOTEFIN_RECOGNIZED )) return NOERROR;

    if (tellMe.bDctPhraseFinish)
       m_pSpchObj->logEventSink(DCT_PHRASEFINISH, TEXT("Action:PhraseFinish Beg: %I64x End: %I64x Flags: 0x%lx"), qTimeStampBegin, qTimeStampEnd, dwFlags );


 PSRWORD  pSRWord, pSRMax;
 CString  phrase;

    // unrecognized utterance
 if( !pSRPhrase )
  return NOERROR;

 // loop through all of the words
 pSRMax  = (PSRWORD) ((BYTE*)pSRPhrase + pSRPhrase->dwSize);
 pSRWord = (PSRWORD) (pSRPhrase->abWords);
 while( pSRWord < pSRMax )
 {
  int count = WideCharToMultiByte(CP_ACP, NULL, pSRWord->szWord, -1, buf, MAX_PHRASELEN, NULL, NULL);
  if (count = 0)
  {
   Error( -1000, TEXT("Ltd PhraseHypothesis: WideCharToMultiByte failed") );
   continue;
  }

  // store the phrase to display in the results list box...
  if (phrase.GetLength() > 0)
         phrase += " ";
  phrase += buf;

  if (dwActionID == 0)
    dwActionID = pSRWord->dwWordNum;

        pSRWord = (PSRWORD) ((BYTE*) pSRWord + pSRWord->dwSize);
 }

 if ("" == phrase)         // new phrase is empty
  return NOERROR;

    m_pSpchObj->logEventSink(DCT_PHRASEFINISH, TEXT("Action Recognized: %s Action ID = %d"), (LPCSTR)phrase , dwActionID);

   
  
    return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::ReEvaluate( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctReevaluate)
        m_pSpchObj->logEventSink(DCT_REEVALUATE, TEXT("Action:Reevaluate lpUnk: %08x"), lpUnk);

 if ( 0 == lpUnk ) return NOERROR;

 // Let the ResultList do its thing for correction.
 m_ResList.dctReevaluate(lpUnk);

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::Training( DWORD dwTrain )
{
 if (tellMe.bDctTraining)
        m_pSpchObj->logEventSink(DCT_TRAINING, TEXT("Action:TrainingRequest Flag: 0x%lx."), dwTrain );

 return NOERROR;
}

//----------------------------------------------------------------------------------------------
// Description: Defined in SAPI Spec
//----------------------------------------------------------------------------------------------
STDMETHODIMP SpchActionSink::UnArchive( LPUNKNOWN lpUnk )
{
 if (tellMe.bDctUnarchive)
        m_pSpchObj->logEventSink(DCT_UNARCHIVE, TEXT("Action:Unarchive lpUnk: %08x"), lpUnk);

 return NOERROR;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值