IBM Voice CMDMenu语音命令控制技术 适用于Emmbbed IBM Viavoice的语音菜单,语音拨号

Posted wicnwicnwh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IBM Voice CMDMenu语音命令控制技术 适用于Emmbbed IBM Viavoice的语音菜单,语音拨号相关的知识,希望对你有一定的参考价值。

class CVCmdMenuDlg;

class CIVCmdNotifySink: public IVCmdNotifySink
{
private:
   DWORD m_dwRefCnt;     /* count how many people our using us (the object)*/
 CVCmdMenuDlg *pDlg;  /* used to send notifications back to demo dialog object */

public:
   CIVCmdNotifySink (void);                       /* obligatory constructor*/
   ~CIVCmdNotifySink (void);                      /* obligatory destructory*/
 CIVCmdNotifySink( CVCmdMenuDlg *pDlgInit );  /* overloaded constructor for this demo */

   /* IUnknown */
   STDMETHODIMP QueryInterface (REFIID, LPVOID FAR*);
   STDMETHODIMP_(ULONG)AddRef(void);                    /* increment  count*/
   STDMETHODIMP_(ULONG)Release(void);                   /* decrements count*/

   /* IVCCmdNotifySink member functions */
   STDMETHODIMP CommandRecognize (DWORD, PVCMDNAME, DWORD, DWORD, PVOID, DWORD, PSTR, PSTR);
   STDMETHODIMP CommandOther (PVCMDNAME, PTSTR);
   STDMETHODIMP CommandStart (void);
   STDMETHODIMP MenuActivate (PVCMDNAME, BOOL);
   STDMETHODIMP UtteranceBegin (void);
   STDMETHODIMP UtteranceEnd (void);
   STDMETHODIMP VUMeter (WORD);
   STDMETHODIMP AttribChanged (DWORD);
   STDMETHODIMP Interference (DWORD);
};

typedef CIVCmdNotifySink* PCIVCmdNotifySink;

 

 


#include "stdafx.h"
#include "winreg.h"   // supports reading the registry
#include "speech.h"   // defines SAPI structures, interfaces
#include "VCmdNfy.h"
#include "VCmdMenu.h"
#include "VCmdDlg.h"
#include "initguid.h"  // required by references to GUIDs
#include "SrWrapEn.h"  // defines IBM speech engine GUIDs

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// external for accessing the application object
extern CVCmdMenuApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
 CAboutDlg();

// Dialog Data
 //{{AFX_DATA(CAboutDlg)
 enum { IDD = IDD_ABOUTBOX };
 //}}AFX_DATA

 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CAboutDlg)
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 //{{AFX_MSG(CAboutDlg)
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
 //{{AFX_DATA_INIT(CAboutDlg)
 //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CAboutDlg)
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
 //{{AFX_MSG_MAP(CAboutDlg)
  // No message handlers
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVCmdMenuDlg dialog

CVCmdMenuDlg::CVCmdMenuDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CVCmdMenuDlg::IDD, pParent)
{
 // don‘t forget to init pointers being tested later on !!! 11/05/96 pwa
 gpIVCmdMenu=NULL;
 gpIVoiceCommand=NULL;
 
 //{{AFX_DATA_INIT(CVCmdMenuDlg)
 m_strRecoEcho = _T("");
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CVCmdMenuDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CVCmdMenuDlg)
 DDX_Control(pDX, IDC_STOP, m_buttonDeactivate);
 DDX_Control(pDX, IDC_START, m_buttonActivate);
 DDX_Control(pDX, IDC_PHRASELIST, m_listPhrase);
 DDX_Text(pDX, IDC_RECOEOCHO, m_strRecoEcho);
 //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CVCmdMenuDlg, CDialog)
 //{{AFX_MSG_MAP(CVCmdMenuDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_START, OnActivate)
 ON_BN_CLICKED(IDC_STOP, OnDeactivate)
 ON_WM_CLOSE()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVCmdMenuDlg message handlers

// Return value of UseSpeech in registry, or -1 on read error.
int CVCmdMenuDlg::GetUseSpeech()
{
 HKEY  hKey;
 DWORD dwType, dwSize, dwVal;
 CString s;

 dwType = REG_DWORD;
 dwSize = sizeof(DWORD);

 s.LoadString( IDS_KEYVOICE );

 if( ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER, s.GetBuffer(0), 0, KEY_READ, &hKey) ) {
  CString sMsg;
  AfxFormatString1( sMsg, IDS_ERROR14, s.GetBuffer(0) );
  AfxMessageBox( sMsg );
  return -1;
 }

 s.LoadString( IDS_VALUE );
 if( ERROR_SUCCESS != RegQueryValueEx (hKey, s.GetBuffer(0), 0, &dwType, (LPBYTE)&dwVal, &dwSize) ) {
  CString sMsg;
  AfxFormatString1( sMsg, IDS_ERROR15, s.GetBuffer(0) );
  AfxMessageBox( sMsg );
  return -1;
 }

 RegCloseKey (hKey);

 return (int)dwVal;
}

// Create a pointer to a voice command interface
// On error, show message box and return 0.
// On success, return valid pointer.
PIVOICECMD CVCmdMenuDlg::CreatePIVCmd()
{
 PIVOICECMD pIVCmd = 0;

 if ( S_OK != CoCreateInstance
    (CLSID_VCmd,     //  voice command object class identifier
     NULL,
     CLSCTX_LOCAL_SERVER,
     IID_IVoiceCmd, // voice command object interface identifier
     (LPVOID*)&pIVCmd //ptr to voice command object interface
     )
    )
  AfxMessageBox( IDS_ERROR1 );
 
 return pIVCmd;
}

// See if default site is using IBM speech engine
// If not, ask user if we can change it.
// Show error message and return FALSE on any error
// Assume: gpIVoiceCommand has already been registered
BOOL CVCmdMenuDlg::CheckSelectIBMEngine()
{

 BOOL bRc = FALSE;
 PIVCMDATTRIBUTES pIVCmdAttr = 0;
 GUID modeGuid;
 BOOL bMBoxRc = FALSE;
 
 if ( !gpIVoiceCommand )
  return FALSE;

 if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
  AfxMessageBox( IDS_ERROR16 );
 else {
  if ( NOERROR != pIVCmdAttr->SRModeGet(&modeGuid) )
   AfxMessageBox( IDS_ERROR17 );
  else {
   //check for US English navigation mode
    if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeUS,modeGuid) ) {
    theApp.LanguageID=LANG_ENGLISH;
    theApp.SubLangID =SUBLANG_ENGLISH_US;
    bRc=TRUE;
   }

   //check for UK English navigation mode
   if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeUK,modeGuid) ) {
    theApp.LanguageID=LANG_ENGLISH;
    theApp.SubLangID =SUBLANG_ENGLISH_UK;
    bRc=TRUE;
   }

   //check for German navigation mode
    if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeGR,modeGuid) ) {
    theApp.LanguageID=LANG_GERMAN;
    theApp.SubLangID =SUBLANG_GERMAN;
    bRc=TRUE;
   }

   //check for French navigation mode
    if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeFR,modeGuid) ) {
    theApp.LanguageID=LANG_FRENCH;
    theApp.SubLangID =SUBLANG_FRENCH;
    bRc=TRUE;
   }

   //check for Italian navigation mode
    if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeIT,modeGuid) ) {
    theApp.LanguageID=LANG_ITALIAN;
    theApp.SubLangID =SUBLANG_ITALIAN;
    bRc=TRUE;
   }

   //check for Spanish navigation mode
    if ( !bRc && ::IsEqualGUID(CLSID_SREngineEnumIBMContinuousModeES,modeGuid) ) {
    theApp.LanguageID=LANG_SPANISH;
    theApp.SubLangID =SUBLANG_SPANISH;
    bRc=TRUE;
   }

   //prompt on unknown GUID mode
   if ( !bRc )
    bMBoxRc = AfxMessageBox(IDS_STRING151, MB_OKCANCEL);

   if ( !bRc && bMBoxRc == IDOK ) {
    if ( NOERROR != pIVCmdAttr->SRModeSet(CLSID_SREngineEnumIBMContinuousModeUS) ) {
//    if ( NOERROR != pIVCmdAttr->SRModeSet(CLSID_SREngineEnumIBMContinuousModeGR) ) {
     AfxMessageBox( IDS_ERROR18 );
     bRc = FALSE;
          }
    else {
     theApp.LanguageID=LANG_ENGLISH;
     theApp.SubLangID =SUBLANG_ENGLISH_US;
//     theApp.LanguageID=LANG_GERMAN;
//     theApp.SubLangID =SUBLANG_GERMAN;
     bRc = TRUE;
    }
   }
   else if ( !bRc && bMBoxRc == IDCANCEL ) {
    // Want to use whatever engine is set in site.
    bRc = TRUE;
   }
  }
 }

 if ( pIVCmdAttr )
  pIVCmdAttr->Release();

 return bRc;
}

// Create a voice command menu for this app
// nAppState is the resource ID of a string specifying app state when menu should
// be active.
// dwFlags specifies how to create the menu
// Shows message box on any error and returns 0
// Returns pointer to menu object on success.
PIVCMDMENU CVCmdMenuDlg::CreateMainMenu( UINT nAppState, DWORD dwFlags )
{
 PIVCMDMENU pIVCmdMenu = 0;
 VCMDNAME VCmdName; // Command Name
 LANGUAGE Language; // language to use
 CString s;
 int iLangStringID;

 //findresourceex
 // Get our app name from our resource file
 s.LoadString( IDS_STRING148 );
 // Truncate our name to field length
 lstrcpy( VCmdName.szApplication,
   (s.Left(VCMD_APPLEN)).GetBuffer(0)
   );

 // Get our app state from our resource file
 if ( !s.LoadString( nAppState ) )
  AfxMessageBox( IDS_ERROR19 );
 // Truncate our state to field length
 lstrcpy( VCmdName.szState,
   (s.Left(VCMD_STATELEN)).GetBuffer(0)
   );

 // Specify United States English language model
 Language.LanguageID = theApp.LanguageID;
 
 switch(theApp.LanguageID)
 {
 case LANG_ENGLISH:
  switch(theApp.SubLangID)
  {
  case SUBLANG_ENGLISH_US:
   iLangStringID=IDS_Lang_US;
   break;
  case SUBLANG_ENGLISH_UK:
   iLangStringID=IDS_Lang_UK;
   break;
  }
  break;
 case LANG_GERMAN:
  iLangStringID=IDS_Lang_GR;
  break;
 case LANG_FRENCH:
  iLangStringID=IDS_Lang_FR;
  break;
 case LANG_ITALIAN:
  iLangStringID=IDS_Lang_IT;
  break;
 case LANG_SPANISH:
  iLangStringID=IDS_Lang_ES;
  break;
 default:
  iLangStringID=IDS_Lang_US;
  break;
 }

 s.LoadString( iLangStringID );
 lstrcpy (Language.szDialect,
   (s.Left(LANG_LEN)).GetBuffer(0)
    );

 if ( NOERROR != gpIVoiceCommand->MenuCreate(&VCmdName,
          &Language,
          dwFlags,
          &pIVCmdMenu
          )
    )
    AfxMessageBox( IDS_ERROR4 );

 return pIVCmdMenu;
}

// Initialize SAPI voice command interface on default site,
// register a notification sink, and create a temporary voice command menu.
// On success, global pointers
//  gpIVoiceCommand
//  gpVCmdNotifySink
//  gpIVCmdMenu
// are non-zero and ready to be used.
// Error messages displayed as appropriate.
// Application exits if error reading required entries in registry
// If default site is not using IBM engine, user is given a chance to set it,
void CVCmdMenuDlg::OnInitSpeech()
{

 /* ----------------------------------------------------------- */
 /* Check the registry to see if user has installed and enabled */
 /* SAPI voice recognition                                      */
 /* ----------------------------------------------------------- */
 int nUseSpeech = GetUseSpeech();
 switch( nUseSpeech ) {
 case -1:
  // Cannot find required key/value in registry. Something‘s wrong
  // with user‘s install of SAPI etc.
  AfxMessageBox( IDS_STRING147 );
  //OnClose();   //don‘t do that !!! 11/05/96 pwa
  this->EndDialog(0);  //bye-bye due to errors 11/05/96 pwa
  break;
 case 0:
  // User has installed SAPI speech, but it is not enabled.
  // You should ask the user whether to continue.
  // We‘re going to go ahead anyway.
  // See SAPI Speech API Developer‘s Guide, Chapter 8.
 case 1:
  // User has installed and enabled SAPI speech
 default:
  // The key/value exists, but the value is unexpected...
  break;
 }

 /* -------------------------------------------------------- */
 /* Create an instance of the voice command and voice menu   */
 /* objects.                                                 */
 /* -------------------------------------------------------- */
 gpIVoiceCommand = 0;
 gpVCmdNotifySink = 0;
 gpIVCmdMenu = 0;

 gpIVoiceCommand = CreatePIVCmd();

 if ( gpIVoiceCommand ) {
    /* -------------------------------------------------- */
    /* Create the VCmd notification sink interface object */
    /* ---------------------------------------------------*/
    gpVCmdNotifySink = new CIVCmdNotifySink( this );
    if ( 0 == gpVCmdNotifySink )
     AfxMessageBox( IDS_ERROR2 );
    else {
     /* ------------------------------------------------------ */
     /* Register the notification sink with the voice cmd obj. */
     /* We are passing VCMDRF_ALLMESSAGES because we want our  */
     /* app to be notified of all possible notifications.      */
     /* ------------------------------------------------------ */
     // Note: This version of the call uses the default
     // site with default settings
     if ( NOERROR != gpIVoiceCommand->Register(
         "",       // means voice input is from computer
      gpVCmdNotifySink,// adr of voice-command object
           // notification interface
      IID_IVCmdNotifySink,// GUID of sink type being passed
      VCMDRF_ALLMESSAGES,// send us all notification msgs
      NULL    // use the voice-site settings from the
        // registry, or the defaults if there are none
         )
     )
     AfxMessageBox( IDS_ERROR3 );
    else {
     // See if default engine is IBM. Let user select it.
     if ( !CheckSelectIBMEngine() )
      return;

     // init the voice command list
     InitListBox();
     // Save current SAPI site enabled state. We‘ll restore it when we exit.
     gdwSiteState = GetSiteState();
     // Now, make sure SAPI site is enabled
     SetSiteState( TRUE );

     gpIVCmdMenu = CreateMainMenu( IDS_STRING149, VCMDMC_CREATE_TEMP );
    }
    }
 }
}

void CVCmdMenuDlg::OnExitSpeech()
{
    /* ------------------------------------------ */
    /* Release the voice command menu interface   */
    /* ------------------------------------------ */
    if (gpIVCmdMenu) {
        gpIVCmdMenu->Release();
        gpIVCmdMenu = 0;
    }   

    /* ------------------------------------------ */
    /* Restore the voice command enabled state    */
    /* before releasing voice command object      */
    /* ------------------------------------------ */
 SetSiteState( gdwSiteState );

    /* ------------------------------------------ */
    /* Release the voice command object interface */
    /* ------------------------------------------ */
    if (gpIVoiceCommand) {
        gpIVoiceCommand->Release();
        gpIVoiceCommand = 0;
    }
 
 // Note: gpIVoiceCommand object releases our gpVCmdNotifySink object,
 // which we "new"ed in OnInitSpeech(). Its release logic deletes it
 //  when the last (ie. one and only) reference is released, so we
 // do not delete it here.

}

BOOL CVCmdMenuDlg::OnInitDialog()
{
 m_strRecoEcho.LoadString( IDS_INITRECOECHO );

 CDialog::OnInitDialog();

 // Add "About..." menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 CMenu* pSysMenu = GetSystemMenu(FALSE);
 CString strAboutMenu;
 strAboutMenu.LoadString(IDS_ABOUTBOX);
 if (!strAboutMenu.IsEmpty())
 {
  pSysMenu->AppendMenu(MF_SEPARATOR);
  pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 }

 // Set the icon for this dialog.  The framework does this automatically
 //  when the application‘s main window is not a dialog
 SetIcon(m_hIcon, TRUE);   // Set big icon
 SetIcon(m_hIcon, FALSE);  // Set small icon
 
 // TODO: Add extra initialization here

 OnInitSpeech(); // Initialize SAPI voice command speech recognition

 return TRUE;  // return TRUE  unless you set the focus to a control
}

void CVCmdMenuDlg::InitListBox()
{
 /********************************************************/
 /* Initialize the phrase list box.      */
 /* This code depends on the phrases being consecutively */
 /* numbered string resources between IDS_PhraseBase and */
 /* IDS_PhraseLast.          */
 /********************************************************/
 CString s;
 int iPhraseBase, iPhraseLast;
 
 switch(theApp.LanguageID)
 {
 case LANG_ENGLISH:
  switch(theApp.SubLangID)
  {
  case SUBLANG_ENGLISH_US:
   iPhraseBase=IDS_PhraseBase_US;
   iPhraseLast=IDS_PhraseLast_US;
   break;
  case SUBLANG_ENGLISH_UK:
   iPhraseBase=IDS_PhraseBase_UK;
   iPhraseLast=IDS_PhraseLast_UK;
   break;
  }
  break;
 case LANG_GERMAN:
  iPhraseBase=IDS_PhraseBase_GR;
  iPhraseLast=IDS_PhraseLast_GR;
  break;
 case LANG_FRENCH:
  iPhraseBase=IDS_PhraseBase_FR;
  iPhraseLast=IDS_PhraseLast_FR;
  break;
 case LANG_ITALIAN:
  iPhraseBase=IDS_PhraseBase_IT;
  iPhraseLast=IDS_PhraseLast_IT;
  break;
 case LANG_SPANISH:
  iPhraseBase=IDS_PhraseBase_ES;
  iPhraseLast=IDS_PhraseLast_ES;
  break;
 default:
  iPhraseBase=IDS_PhraseBase_US;
  iPhraseLast=IDS_PhraseLast_US;
  break;
 }

 for( int i = iPhraseBase + 1; i < iPhraseLast; i++ ) {
  if ( s.LoadString(i) ) {
   if ( LB_ERR == m_listPhrase.AddString( s.GetBuffer(0) ) ) {
    AfxMessageBox( IDS_ERROR5 );
    break;
   }
  }
 }
 m_listPhrase.SetSel( 0 );  // select the first phrase
 m_buttonDeactivate.EnableWindow( FALSE );
}

void CVCmdMenuDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 {
  CAboutDlg dlgAbout;
  dlgAbout.DoModal();
 }
 else
 {
  CDialog::OnSysCommand(nID, lParam);
 }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CVCmdMenuDlg::OnPaint()
{
 if (IsIconic())
 {
  CPaintDC dc(this); // device context for painting

  SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

  // Center icon in client rectangle
  int cxIcon = GetSystemMetrics(SM_CXICON);
  int cyIcon = GetSystemMetrics(SM_CYICON);
  CRect rect;
  GetClientRect(&rect);
  int x = (rect.Width() - cxIcon + 1) / 2;
  int y = (rect.Height() - cyIcon + 1) / 2;

  // Draw the icon
  dc.DrawIcon(x, y, m_hIcon);
 }
 else
 {
  CDialog::OnPaint();
 }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CVCmdMenuDlg::OnQueryDragIcon()
{
 return (HCURSOR) m_hIcon;
}

void CVCmdMenuDlg::OnActivate()
{
 // TODO: Add your control notification handler code here

 // If no phrases selected, then we can‘t build a voice command menu
 int nCount = m_listPhrase.GetSelCount();
 if ( 0 >= nCount ) {
  AfxMessageBox( IDS_STRING141 );
  return;
 }

 // If voice command menu setup ok
    if (   VoiceCmdMenuEmpty()
  && VoiceCmdMenuFill()
  && VoiceCmdMenuActivate()
     ) {
  // toggle buttons
  m_buttonActivate.EnableWindow( FALSE );
  m_buttonDeactivate.EnableWindow( TRUE );
  // reinitialize recognized text area
  m_strRecoEcho.LoadString( IDS_INITRECOECHO );
  UpdateData( FALSE );
 }
}

void CVCmdMenuDlg::OnDeactivate()
{
 // TODO: Add your control notification handler code here
 if ( gpIVCmdMenu )
  if ( NOERROR != gpIVCmdMenu->Deactivate() )
   AfxMessageBox( IDS_ERROR20 );

 m_buttonActivate.EnableWindow( TRUE );
 m_buttonDeactivate.EnableWindow( FALSE ); 
 
}


BOOL CVCmdMenuDlg::VoiceCmdMenuActivate()
{
 HRESULT hResult;

 // check initialization did not fail
 if ( 0 == gpIVCmdMenu )
  return FALSE;

 // first argument is handle of window to associate with this menu. NULL makes it global to this application
 // second argument is whether menu should be active when voice reco is "awake" (0) or "asleep" (VWGFLAG_ASLEEP)
 hResult = gpIVCmdMenu->Activate( NULL, 0 );
 if ( NOERROR != hResult ) {
  AfxMessageBox( IDS_ERROR6 );
  return FALSE;
 } else return TRUE;

}

BOOL CVCmdMenuDlg::VoiceCmdMenuEmpty()
{
 HRESULT hResult;
 DWORD dwNum;

 // check initialization did not fail
 if ( 0 == gpIVCmdMenu )
  return FALSE;

 // get the number of items in a voice command menu
 hResult = gpIVCmdMenu->Num( &dwNum );
 if ( NOERROR != hResult ) {
  AfxMessageBox( IDS_ERROR7 );
  return FALSE;
 }

 // remove items from first parameter to first plus second parameter from a voice command menu
 // if third parameter is VCMD_BY_IDENTIFIER, then second parameter is identifier of commands to remove
 if ( dwNum ) {
  hResult = gpIVCmdMenu->Remove( 1, dwNum, VCMD_BY_POSITION );
  if ( NOERROR != hResult ) {
   AfxMessageBox( IDS_ERROR8 );
   return FALSE;
  }
 }

 return TRUE;
}

BOOL CVCmdMenuDlg::VoiceCmdMenuFill()
{
 HRESULT hResult;
 SDATA data;
 PVCMDCOMMAND pVCmdCmd;
 DWORD dwNum, dwStart, dwSize, dwCatSize;
 CHAR szCat[] = "Main";
 int *nArraySelect;

 // check initialization did not fail
 if ( 0 == gpIVCmdMenu )
  return FALSE;

 dwNum = m_listPhrase.GetSelCount();
 if ( 0 == dwNum ) {
  AfxMessageBox( IDS_STRING142 );
  return FALSE;
 }
 nArraySelect = (int *)CoTaskMemAlloc( dwNum* sizeof(int) );
 if ( NULL == nArraySelect ) {
  AfxMessageBox( IDS_ERROR9 );
  return FALSE;
 }
 m_listPhrase.GetSelItems( dwNum, nArraySelect );

 // SDATA can refer to an "array" of VCMDCOMMAND structures.
 // We‘ll build this array be reallocating pVCmdCmd, once
 // each time through our list loop below.
 dwSize = 0;
 pVCmdCmd = (PVCMDCOMMAND)CoTaskMemAlloc( dwSize );
 if ( 0 == pVCmdCmd ) {
  AfxMessageBox( IDS_ERROR10 );
  return FALSE;
 }
 
 // The variable data at the end of VCMDCOMMAND structure must all begin on 32-bit boundaries
 // See SAPI specification for more details
 dwCatSize = 1 + lstrlen( szCat );
 dwCatSize = (dwCatSize+3)&(~3);

 for( int i = 0; i < (int)dwNum; i++ ) {
  PCHAR pNext;
  PVCMDCOMMAND pVCmdNew;
  DWORD dwStrSize, dwAlignSize, dwNewSize;

  // extend existing structure for next VCMDCOMMAND structure
  dwStrSize   = 1 + m_listPhrase.GetTextLen( nArraySelect[i] );
  dwAlignSize = (dwStrSize+3)&(~3);
  dwNewSize = dwSize + sizeof(VCMDCOMMAND) + 2*dwAlignSize + dwCatSize + sizeof(DWORD);
  pVCmdCmd = (PVCMDCOMMAND)CoTaskMemRealloc( pVCmdCmd, dwNewSize );
  if ( 0 == pVCmdCmd ) {
   AfxMessageBox( IDS_ERROR11 );
   return FALSE;
  }
  // fill in the new VCMDCOMMAND structure
  pNext    = (PCHAR)pVCmdCmd + dwSize;
  memset( pNext, 0, dwNewSize - dwSize );
  pVCmdNew = (PVCMDCOMMAND)pNext;
  pVCmdNew->dwSize       = dwNewSize - dwSize; // sizeof this structure
  pVCmdNew->dwFlags      = 0;      // these flags can specify confirmaton, disabled. See SAPI spec.
  pVCmdNew->dwCommandText= NULL;     // use dwCommand to show voice command menu to user
  pVCmdNew->dwActionSize = sizeof(DWORD);   // size of action data
  // fill in the variable data at end of new structure
  pNext   += sizeof(VCMDCOMMAND);     // variable data starts at abdata[]
  pVCmdNew->dwAction     = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to app-unique action code
  *(DWORD *)(pNext) = (DWORD)i;        // make up an action code for this command
  pNext += sizeof(DWORD);
  pVCmdNew->dwCommand    = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command string
  if ( (int)dwStrSize != 1 + m_listPhrase.GetText(nArraySelect[i], (LPTSTR)pNext) ) {
   AfxMessageBox( IDS_ERROR12 );
   return FALSE;
  }
  pNext += dwAlignSize;
  pVCmdNew->dwDescription = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command description
  if ( (int)dwStrSize != 1 + m_listPhrase.GetText(nArraySelect[i], (LPTSTR)pNext) ) {
   AfxMessageBox( IDS_ERROR12 );
   return FALSE;
  }
  pNext += dwAlignSize;
  pVCmdNew->dwCategory = (DWORD)(pNext - (PCHAR)pVCmdNew); // offset to command category
  strcpy( pNext, szCat );
  dwSize = dwNewSize;
 }

 data.pData  = pVCmdCmd;
    data.dwSize = dwSize;

 hResult = gpIVCmdMenu->Add( dwNum, data, &dwStart );
 if ( NOERROR != hResult ) {
  AfxMessageBox( IDS_ERROR13 );
  return FALSE;
 }

 CoTaskMemFree( nArraySelect );
 CoTaskMemFree( data.pData );
 return TRUE;
}

void CVCmdMenuDlg::CommandRecognized( PSTR pszText )
{
 m_strRecoEcho = pszText;
 UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::CommandOther( PSTR pszText )
{
 if ( NULL == pszText )
  m_strRecoEcho.LoadString( IDS_NOTRECOED );
 else {
  m_strRecoEcho.LoadString( IDS_CMDOTHER );
  m_strRecoEcho += pszText;
 }
 UpdateData( FALSE );
}
void CVCmdMenuDlg::TooNoisy()
{
 m_strRecoEcho.LoadString( IDS_TOONOISY );
 UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::NoSignal()
{
 m_strRecoEcho.LoadString( IDS_NOSIGNAL );
 UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::TooLoud()
{
 m_strRecoEcho.LoadString( IDS_TOOLOUD );
 UpdateData( FALSE ); // send fields to dialog window
}

void CVCmdMenuDlg::TooQuiet()
{
 m_strRecoEcho.LoadString( IDS_TOOQUIET );
 UpdateData( FALSE ); // send fields to dialog window
}

// Read enabled state of voice command site
// Show message box on error.
DWORD CVCmdMenuDlg::GetSiteState()
{
 PIVCMDATTRIBUTES pIVCmdAttr = 0;
 DWORD dwEnabled = 0;
 
 if ( gpIVoiceCommand ) {
  if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
   AfxMessageBox( IDS_ERROR16 );
  else {
   if ( NOERROR != pIVCmdAttr->EnabledGet(&dwEnabled) )
    AfxMessageBox( IDS_ERROR21 );
  }
 }

 if ( pIVCmdAttr )
  pIVCmdAttr->Release();

 return dwEnabled;
}

// Set enabled state of voice command site
// Show message box on error.
void CVCmdMenuDlg::SetSiteState( DWORD dwEnabled )
{
 PIVCMDATTRIBUTES pIVCmdAttr = 0;
 
 if ( gpIVoiceCommand ) {
  if ( NOERROR != gpIVoiceCommand->QueryInterface(IID_IVCmdAttributes, (LPVOID FAR *)&pIVCmdAttr) )
   AfxMessageBox( IDS_ERROR16 );
  else {
   if ( NOERROR != pIVCmdAttr->EnabledSet(dwEnabled) )
    AfxMessageBox( IDS_ERROR22 );
  }
 }

 if ( pIVCmdAttr )
  pIVCmdAttr->Release();
}

void CVCmdMenuDlg::OnOK()
{
 // TODO: Add extra validation here

 // Restore site state and shut down voice reco objects...
 OnExitSpeech();

 CDialog::OnOK();
}

void CVCmdMenuDlg::OnClose()
{
 // TODO: Add your message handler code here and/or call default
 
 // Restore site state and shut down voice reco objects...
 OnExitSpeech();

 CDialog::OnClose();
}

void CVCmdMenuDlg::WinHelp(DWORD dwData, UINT nCmd)
{
 // TODO: Add your specialized code here and/or call the base class
 return;
}

需要源码的留下邮件,我来发,

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow













































































































































































































































































































































































































































































































































































































































































































以上是关于IBM Voice CMDMenu语音命令控制技术 适用于Emmbbed IBM Viavoice的语音菜单,语音拨号的主要内容,如果未能解决你的问题,请参考以下文章

unimrcp-voice-activity语音检测

Hololens官方教程精简版 - 05. Voice(语音)

Hololens官方教程精简版 - 05. Voice(语音)

Microsoft Teams Voice语音落地系列-5 实战: Sonus语音网关配置

js微信语音怎么实现的

Discord.js v13,@discordjs/voice 播放音乐命令