基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音识别引擎(适用于windows 2

基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音识别引擎(适用于windows 2000/xp2003/vista   windows CE /mobile),本项目开源,源码请留下你们的Email,我给大家发

本人闲来无事,自行开发了一个小型的语音识别引擎,搭建起在微软平台上的语音识别框架服务体系,

鉴于本人个人力量有限,为了将语音识别引擎做的功能更加强悍,强大,

现在将该系统开源,需要源码的请在本人CSDN博客下留下EMail,

本系统属于系统框架,搭建起一个语音识别的引擎服务框架,

在微软平台上畅通无阻,

现在将本系统构架公布一下,

并贴出相关核心源码,源码体积为37M,编译后为3M,

适用于windows 2000/xp2003/vista   windows CE /mobile

框架头文件简介:

srengalt.h文件

此文件包含的语音CSrEngineAlternates类。
这实现了接口ISpSRAlternates ,
当一个应用程序GetAlternates或识别的结果, 将
寻找AlternatesCLSID的识别引擎对象,并
创建此对象。 并返回结果

#pragma once

#include "stdafx.h"
#include "SampleSrEngine.h"
#include "resource.h"

class ATL_NO_VTABLE CSrEngineAlternates :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSrEngineAlternates, &CLSID_SampleSREngineAlternates>,
public ISpSRAlternates
{
public:

DECLARE_REGISTRY_RESOURCEID(IDR_SRENGALT)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSrEngineAlternates)
COM_INTERFACE_ENTRY(ISpSRAlternates)
END_COM_MAP()

public:

STDMETHODIMP GetAlternates(
SPPHRASEALTREQUEST *pAltRequest,
SPPHRASEALT **ppAlts,
ULONG *pcAlts);

STDMETHODIMP Commit(
SPPHRASEALTREQUEST *pAltRequest,
SPPHRASEALT *pAlt,
void **ppvResultExtra,
ULONG *pcbResultExtra);
};

srengext.h 文件
此文件包含CSampleSRExtension类。
这实现了自定义接口ISampleSRExtension
当一个应用程序开始识别, SAPI的将
寻找ExtensionCLSID领域中的引擎对象的指针,并
创建该对象,然后创建语音识别的要求。
#pragma once

#include "stdafx.h"
#include "SampleSrEngine.h"
#include "resource.h"

class ATL_NO_VTABLE CSampleSRExtension :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSampleSRExtension, &CLSID_SampleSRExtension>,
public ISampleSRExtension,
public ISpDisplayAlternates,
public ISpEnginePronunciation
{
public:

DECLARE_REGISTRY_RESOURCEID(IDR_SRENGEXT)
DECLARE_GET_CONTROLLING_UNKNOWN()
DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSampleSRExtension)
COM_INTERFACE_ENTRY(ISampleSRExtension)
COM_INTERFACE_ENTRY(ISpDisplayAlternates)
COM_INTERFACE_ENTRY(ISpEnginePronunciation)
END_COM_MAP()

HRESULT FinalConstruct()
{
/ /失败CRecoExt作为一个非累计对象。
/ /创建CRecoExt的SAPI
if(GetControllingUnknown() == dynamic_cast<ISampleSRExtension *>(this) )
{
return E_FAIL;
}

/ /这个接口的处理的SAPI 5.1 。
/ /必须QI‘d中的FinalConstruct对象并没有释放。

return OuterQueryInterface(IID__ISpPrivateEngineCall, (void **)&m_pEngineCall);
}

void FinalRelease()
{
// 不释放IID__ISpPrivateEngineCall这里
}

STDMETHODIMP ExamplePrivateEngineCall(void); // 测试方法

// ISpDisplayAlternates 方法
STDMETHODIMP GetDisplayAlternates(
const SPDISPLAYPHRASE *pPhrase,
ULONG cRequestCount,
SPDISPLAYPHRASE **ppCoMemPhrases,
ULONG *pcPhrasesReturned);

STDMETHODIMP SetFullStopTrailSpace(ULONG ulTrailSpace);

// ISpEnginePronunciation 方法
STDMETHODIMP Normalize(
LPCWSTR pszWord,
LPCWSTR pszLeftContext,
LPCWSTR pszRightContext,
WORD LangID,
SPNORMALIZATIONLIST *pNormalizationList);

STDMETHODIMP GetPronunciations(
LPCWSTR pszWord,
LPCWSTR pszLeftContext,
LPCWSTR pszRightContext,
WORD LangID,
SPWORDPRONUNCIATIONLIST *pEnginePronunciationList);

private:
_ISpPrivateEngineCall *m_pEngineCall;

};

/******************************************************************************
* srengobj.h

*此文件包含的宣言CSrEngine类。
*本实施ISpSREngine , ISpSREngine2和ISpObjectWithToken 。
*这是主要识别引擎对象
******************************************************************************/
#pragma once

#include "stdafx.h"
#include "SampleSrEngine.h"
#include "resource.h"

//语音识别对象。每个条目的列表中的一个实例这个类。
class CContext
{
public:
CContext * m_pNext;
BOOL operator==(SPRECOCONTEXTHANDLE hContext)
{
return (m_hSapiContext == hContext);
}

CContext(SPRECOCONTEXTHANDLE hSapiContext) :
m_hSapiContext(hSapiContext)
{}

SPRECOCONTEXTHANDLE m_hSapiContext;
};//reco语法存储。每个条目的列表中的一个实例这个类。
class CDrvGrammar
{
public:
CDrvGrammar * m_pNext;
SPGRAMMARHANDLE m_hSapiGrammar; // 根据 SAPI 创建语法
BOOL m_SLMLoaded; // 语法是否与听写相关

BOOL m_SLMActive; // 词典是否被激活
WCHAR* m_pWordSequenceText; // 词典词表放在缓冲区

ULONG m_cchText; // 字序缓冲区大小

SPTEXTSELECTIONINFO* m_pInfo; // 文字选择字序缓冲区

CDrvGrammar(SPGRAMMARHANDLE hSapiGrammar) :
m_hSapiGrammar(hSapiGrammar),
m_SLMLoaded(FALSE),
m_SLMActive(FALSE),
m_pWordSequenceText(NULL),
m_cchText(0),
m_pInfo(NULL)
{
}

~CDrvGrammar()
{

/ /释放资源
/ /对于每个语法对象将被释放
SetWordSequenceData(NULL, 0, NULL).

/ / SetWordSequenceData和SetTextSelection将释放的内存
/ /在这里没有必要释放内存的m_pWordSequenceText和m_pInfo .
}
#ifdef _WIN32_WCE
CDrvGrammar()
{
}

static LONG Compare(const CDrvGrammar *, const CDrvGrammar *)
{
return 0;
}
#endif
};

/ /读取的RecognizeStream线程中的音频数据块。每一组
/ /决定如果数据讲话或沉默和价值补充说,此队列。
/ /解码器读取这些线程和进程。
/ /关键部分是用来使队列线程安全的,和一个事件是用来
/ /显示如果缓冲区已空或没有。
/ /这非常象roughtly模拟,这样做的特征提取
/ /一个线程,并通过功能流的解码器。

class CFrameQueue
{
public:
BOOL m_aFrames[100]; // 语音识别返回值
ULONG m_cFrames;
ULONG m_ulHeadIndex;
HANDLE m_hSpaceAvailEvent;
CRITICAL_SECTION m_cs;

CFrameQueue()
{
m_cFrames = 0;
m_ulHeadIndex = 0;
m_hSpaceAvailEvent = NULL;
InitializeCriticalSection(&m_cs);
}
~CFrameQueue()
{
DeleteCriticalSection(&m_cs);
}
void SetSpaceAvailEvent(HANDLE h)
{
m_hSpaceAvailEvent = h;
}
void InsertTail(BOOL b)
{
EnterCriticalSection(&m_cs);
ULONG ulTailIndex = (m_ulHeadIndex + m_cFrames) % sp_countof(m_aFrames);
m_aFrames[ulTailIndex] = b;
m_cFrames++;
if (m_cFrames == sp_countof(m_aFrames))
{
ResetEvent(m_hSpaceAvailEvent);
}
LeaveCriticalSection(&m_cs);
}
BOOL IsFull()
{
EnterCriticalSection(&m_cs);
BOOL b = (m_cFrames == sp_countof(m_aFrames));
LeaveCriticalSection(&m_cs);
return b;
}
BOOL RemoveHead()
{
EnterCriticalSection(&m_cs);
BOOL b = m_aFrames[m_ulHeadIndex];
m_ulHeadIndex = (m_ulHeadIndex + 1) % sp_countof(m_aFrames);
m_cFrames--;
SetEvent(m_hSpaceAvailEvent);
LeaveCriticalSection(&m_cs);
return b;
}
BOOL HasData()
{
EnterCriticalSection(&m_cs);
ULONG cFrames = m_cFrames;
LeaveCriticalSection(&m_cs);
return cFrames;
}
};

//我们可以使用CSpBasicQueue信息存储规则
class CRuleEntry
{
public:
BOOL operator==(SPRULEHANDLE rh)
{
return (m_hRule == rh);
}
CRuleEntry * m_pNext;
SPRULEHANDLE m_hRule; // SAPI 规则句柄
BOOL m_fTopLevel; // 显示规则是否被激活
BOOL m_fActive; // 显示识别引擎的设置
};

// 语音识别类

class ATL_NO_VTABLE CSrEngine :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSrEngine, &CLSID_SampleSREngine>,
public ISpSREngine2,
public ISpObjectWithToken,
public ISpThreadTask
{
public:
CSrEngine() :
m_ulNextGrammarIndex(0),
m_cActive(0),
m_bPhraseStarted(FALSE),
m_bSoundStarted(FALSE),
m_hQueueHasRoom(NULL),
m_hRequestSync(NULL),
m_LangID(0)
{}

DECLARE_REGISTRY_RESOURCEID(IDR_SRENG)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSrEngine)
COM_INTERFACE_ENTRY(ISpSREngine)
COM_INTERFACE_ENTRY(ISpSREngine2)
COM_INTERFACE_ENTRY(ISpObjectWithToken)
END_COM_MAP()

private:
HANDLE m_hRequestSync;
CFrameQueue m_FrameQueue;
ULONG m_cBlahBlah;
CSpBasicQueue<CDrvGrammar> m_GrammarList;
CSpBasicQueue<CContext> m_ContextList;
ULONG m_ulNextGrammarIndex;
ULONG m_cActive;
ULONGLONG m_ullStart;
ULONGLONG m_ullEnd;
BOOL m_bSoundStarted:1;
BOOL m_bPhraseStarted:1;
CComPtr<ISpSREngineSite> m_cpSite;
CComPtr<ISpThreadControl> m_cpDecoderThread;
HANDLE m_hQueueHasRoom;
CSpBasicQueue<CRuleEntry> m_RuleList;
CComPtr<ISpLexicon> m_cpLexicon;
CComPtr<ISpObjectToken> m_cpEngineObjectToken;
CComPtr<ISpObjectToken> m_cpUserObjectToken;
LANGID m_LangID;

public:

HRESULT RandomlyWalkRule(SPRECORESULTINFO * pResult, ULONG nWords, ULONGLONG ullAudioPos, ULONG ulAudioSize);
HRESULT RecurseWalk(SPSTATEHANDLE hState, SPPATHENTRY * pPath, ULONG * pcTrans);
HRESULT WalkCFGRule(SPRECORESULTINFO * pResult, ULONG cRulesActive, BOOL fHypothesis,
ULONG nWords, ULONGLONG ullAudioPos, ULONG ulAudioSize);
HRESULT WalkSLM(SPRECORESULTINFO * pResult, ULONG cSLMActive,
ULONG nWords, ULONGLONG ullAudioPos, ULONG ulAudioSize);
HRESULT WalkTextBuffer(void* pvGrammarCookie, SPPATHENTRY * pPath, SPTRANSITIONID hId, ULONG * pcTrans);

HRESULT AddEvent(SPEVENTENUM eEvent, ULONGLONG ullStreamPos, WPARAM wParam = 0, LPARAM lParam = 0);
HRESULT AddEventString(SPEVENTENUM eEvent, ULONGLONG ulLStreamPos, const WCHAR * psz, WPARAM = 0);

HRESULT CreatePhraseFromRule( CRuleEntry * pRule, BOOL fHypothesis,
ULONGLONG ullAudioPos, ULONG ulAudioSize,
ISpPhraseBuilder** ppPhrase );

CRuleEntry* FindRule( ULONG ulRuleIndex );
CRuleEntry* NextRuleAlt( CRuleEntry * pPriRule, CRuleEntry * pLastRule );

void _CheckRecognition();
void _NotifyRecognition(BOOL fHypothesis, ULONG nWords);

HRESULT FinalConstruct();
HRESULT FinalRelease();

STDMETHODIMP SetObjectToken(ISpObjectToken * pToken);
STDMETHODIMP GetObjectToken(ISpObjectToken ** ppToken);

STDMETHODIMP SetRecoProfile(ISpObjectToken * pProfileToken);
STDMETHODIMP SetSite(ISpSREngineSite *pSite);
STDMETHODIMP GetInputAudioFormat(const GUID * pSrcFormatId, const WAVEFORMATEX * pSrcWFEX,
GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWFEX);

STDMETHODIMP OnCreateRecoContext(SPRECOCONTEXTHANDLE hSAPIRecoContext, void ** ppvDrvCtxt);
STDMETHODIMP OnDeleteRecoContext(void * pvDrvCtxt);

STDMETHODIMP OnCreateGrammar(void * pvEngineRecoContext,
SPGRAMMARHANDLE hSAPIGrammar,
void ** ppvEngineGrammar);

STDMETHODIMP OnDeleteGrammar(void * pvEngineGrammar);

STDMETHODIMP WordNotify(SPCFGNOTIFY Action, ULONG cWords, const SPWORDENTRY * pWords);
STDMETHODIMP RuleNotify(SPCFGNOTIFY Action, ULONG cRules, const SPRULEENTRY * pRules);

STDMETHODIMP LoadProprietaryGrammar(void * pvEngineGrammar,
REFGUID rguidParam,
const WCHAR * pszStringParam,
const void * pvDataParam,
ULONG ulDataSize,
SPLOADOPTIONS Options)
{
return E_NOTIMPL;
}

STDMETHODIMP UnloadProprietaryGrammar(void * pvEngineGrammar)
{
return E_NOTIMPL;
}

STDMETHODIMP SetProprietaryRuleState(void * pvEngineGrammar,
const WCHAR * pszName,
void * pvReserved,
SPRULESTATE NewState,
ULONG * pcRulesChanged)
{
return E_NOTIMPL;
}
STDMETHODIMP SetProprietaryRuleIdState(void * pvEngineGrammar,
DWORD dwRuleId,
SPRULESTATE NewState)
{
return E_NOTIMPL;
}

/由于这个引擎不支持专有的语法,我们并不需要执行
/ /此方法不仅仅是返回S_OK 。注意执行不返回 E_NOTIMPL 。
/ /仅仅返回S_OK ,并忽略这个数据如果您不需要它执行专有语法。
STDMETHODIMP SetGrammarState(void * pvEngineGrammar, SPGRAMMARSTATE eGrammarState)
{
return S_OK;
}
STDMETHODIMP SetContextState(void * pvEngineContxt, SPCONTEXTSTATE eCtxtState)
{
return S_OK;
}

// 字典方法
STDMETHODIMP LoadSLM(void * pvEngineGrammar, const WCHAR * pszTopicName);
STDMETHODIMP UnloadSLM(void * pvEngineGrammar);
STDMETHODIMP SetSLMState(void * pvEngineGrammar, SPRULESTATE NewState);

STDMETHODIMP IsPronounceable(void *pDrvGrammar, const WCHAR *pszWord, SPWORDPRONOUNCEABLE * pWordPronounceable);
STDMETHODIMP SetWordSequenceData(void * pvEngineGrammar, const WCHAR * pText, ULONG cchText, const SPTEXTSELECTIONINFO * pInfo);
STDMETHODIMP SetTextSelection(void * pvEngineGrammar, const SPTEXTSELECTIONINFO * pInfo);
STDMETHODIMP SetAdaptationData(void * pvEngineCtxtCookie, const WCHAR * pText, const ULONG cch);
STDMETHODIMP SetPropertyNum( SPPROPSRC eSrc, void* pvSrcObj, const WCHAR* pName, LONG lValue );
STDMETHODIMP GetPropertyNum( SPPROPSRC eSrc, void* pvSrcObj, const WCHAR* pName, LONG * plValue );
STDMETHODIMP SetPropertyString( SPPROPSRC eSrc, void* pvSrcObj, const WCHAR* pName, const WCHAR* pValue );
STDMETHODIMP GetPropertyString( SPPROPSRC eSrc, void* pvSrcObj, const WCHAR* pName, __deref_out_opt WCHAR** ppCoMemValue );

// 语音识别方法
STDMETHODIMP RecognizeStream(REFGUID rguidFmtId, const WAVEFORMATEX * pWaveFormatEx,
HANDLE hRequestSync, HANDLE hDataAvailable,
HANDLE hExit, BOOL fNewAudioStream, BOOL fRealTimeAudio,
ISpObjectToken * pAudioObjectToken);

STDMETHODIMP PrivateCall(void * pvEngineContext, void * pCallFrame, ULONG ulCallFrameSize);
STDMETHODIMP PrivateCallEx(void * pvEngineContext, const void * pInCallFrame, ULONG ulCallFrameSize,
void ** ppvCoMemResponse, ULONG * pcbResponse);

// 语音识别线程
STDMETHODIMP InitThread( void * pvTaskData, HWND hwnd )
{
return S_OK;
}
LRESULT STDMETHODCALLTYPE WindowMessage( void *pvTaskData, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
return E_UNEXPECTED;
}

STDMETHODIMP ThreadProc( void *pvTaskData, HANDLE hExitThreadEvent, HANDLE hNotifyEvent, HWND hwndWorker, volatile const BOOL * pfContinueProcessing );

// 语音引擎方法
STDMETHODIMP PrivateCallImmediate(
void *pvEngineContext,
const void *pInCallFrame,
ULONG ulInCallFrameSize,
void **ppvCoMemResponse,
ULONG *pulResponseSize);

STDMETHODIMP SetAdaptationData2(
void *pvEngineContext,
__in_ecount(cch) const WCHAR *pAdaptationData,
const ULONG cch,
LPCWSTR pTopicName,
SPADAPTATIONSETTINGS eSettings,
SPADAPTATIONRELEVANCE eRelevance);

STDMETHODIMP SetGrammarPrefix(
void *pvEngineGrammar,
__in_opt LPCWSTR pszPrefix,
BOOL fIsPrefixRequired);

STDMETHODIMP SetRulePriority(
SPRULEHANDLE hRule,
void *pvClientRuleContext,
int nRulePriority);

STDMETHODIMP EmulateRecognition(
ISpPhrase *pPhrase,
DWORD dwCompareFlags);

STDMETHODIMP SetSLMWeight(
void *pvEngineGrammar,
float flWeight);

STDMETHODIMP SetRuleWeight(
SPRULEHANDLE hRule,
void *pvClientRuleContext,
float flWeight);

STDMETHODIMP SetTrainingState(
BOOL fDoingTraining,
BOOL fAdaptFromTrainingData);

STDMETHODIMP ResetAcousticModelAdaptation( void);

STDMETHODIMP OnLoadCFG(
void *pvEngineGrammar,
const SPBINARYGRAMMAR *pGrammarData,
ULONG ulGrammarID);

STDMETHODIMP OnUnloadCFG(
void *pvEngineGrammar,
ULONG ulGrammarID);
};

/******************************************************************************
* srengui.h

*此文件包含的语音识别界面CSrEngineUI类。
*这里的方法可以是所谓的应用程序直接从ISpObjectToken获取识别结果
******************************************************************************/
#pragma once

#include "resource.h"

class ATL_NO_VTABLE CSrEngineUI :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CSrEngineUI, &CLSID_SampleSREngineUI>,
public ISpTokenUI
{
public:

DECLARE_REGISTRY_RESOURCEID(IDR_SRENGUI)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSrEngineUI)
COM_INTERFACE_ENTRY(ISpTokenUI)
END_COM_MAP()

public:

STDMETHODIMP IsUISupported(
const WCHAR * pszTypeOfUI,
void * pvExtraData,
ULONG cbExtraData,
IUnknown * punkObject,
BOOL *pfSupported);
STDMETHODIMP DisplayUI(
HWND hwndParent,
const WCHAR * pszTitle,
const WCHAR * pszTypeOfUI,
void * pvExtraData,
ULONG cbExtraData,
ISpObjectToken * pToken,
IUnknown * punkObject);
};

#ifndef VER_H
/* ver.h 定义用到的常用值 */
//#include <winver.h>
#endif
#include <windows.h>
#define VER_FILETYPE VFT_APP
#define VER_FILESUBTYPE VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR "SR SAMPLE ENGINE 5"
#define VER_INTERNALNAME_STR "SRSAMPLEENG5"

#define VERSION "5.0"
#define VER_FILEVERSION_STR "5.0"
#define VER_FILEVERSION 5,0
#define VER_PRODUCTVERSION_STR "5.0"
#define VER_PRODUCTVERSION 5,0

#define OFFICIAL 1
#define FINAL 1
#if _DEBUG
#define VER_DEBUG VS_FF_DEBUG
#else
#define VER_DEBUG 0
#endif
#ifndef OFFICIAL
#define VER_PRIVATEBUILD VS_FF_PRIVATEBUILD
#else
#define VER_PRIVATEBUILD 0
#endif
#ifndef FINAL
#define VER_PRERELEASE VS_FF_PRERELEASE
#else
#define VER_PRERELEASE 0
#endif

#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#define VER_FILEOS VOS_DOS_WINDOWS32
#define VER_FILEFLAGS (VER_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG)

#define VER_COMPANYNAME_STR "Microsoft Corporation/0"
#define VER_PRODUCTNAME_STR "Microsoft/256 Windows(TM) Operating System/0"
#define VER_LEGALTRADEMARKS_STR /

SampleSrEngine.cpp语音识别引擎实例

创建一个语音识别服务

#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include "SampleSrEngine.h"

#include "SampleSrEngine_i.c"
#include "SampleSrEngine.h"
#include "srengobj.h"
#include "srengui.h"
#include "srengext.h"
#include "srengalt.h"

CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_SampleSREngine, CSrEngine)
OBJECT_ENTRY(CLSID_SampleSREngineUI, CSrEngineUI)
OBJECT_ENTRY(CLSID_SampleSRExtension, CSampleSRExtension)
OBJECT_ENTRY(CLSID_SampleSREngineAlternates, CSrEngineAlternates)
END_OBJECT_MAP()

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
#ifdef _WIN32_WCE
extern "C"
BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, (HINSTANCE)hInstance, &LIBID_SRENGLib);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
#else
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, hInstance, &LIBID_SRENGLib);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
#endif

STDAPI DllCanUnloadNow(void)
{
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _Module.GetClassObject(rclsid, riid, ppv);
}

STDAPI DllRegisterServer(void)
{

return _Module.RegisterServer(TRUE);
}

STDAPI DllUnregisterServer(void)
{
return _Module.UnregisterServer(TRUE);
}

SampleSrEngine.def引擎公开

LIBRARY "SampleSrEngine.DLL"

EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

/ / SampleSrEngine.idl : IDL编译器源SampleSrEngine.dll
/ /此文件将由MIDL工具
/ /产生的类型库( SampleSrEngine.tlb )和编组代码

import "oaidl.idl";
import "ocidl.idl";
import "sapiddk.idl";

typedef [restricted, hidden] struct SPDISPLAYTOKEN
{
const WCHAR *pszLexical;
const WCHAR *pszDisplay;
BYTE bDisplayAttributes;
} SPDISPLAYTOKEN;

typedef [restricted, hidden] struct SPDISPLAYPHRASE
{
ULONG ulNumTokens;
SPDISPLAYTOKEN *pTokens;
} SPDISPLAYPHRASE;

[
object,
uuid(BBC18F3B-CF35-4f7c-99E8-D1F803AB4851),
helpstring("ISampleSRExtension Interface"),
pointer_default(unique)
]
interface ISampleSRExtension : IUnknown
{
HRESULT ExamplePrivateEngineCall(void);
};

[
object,
uuid(C8D7C7E2-0DDE-44b7-AFE3-B0C991FBEB5E),
helpstring("ISpDisplayAlternates Interface"),
pointer_default(unique),
local
]
interface ISpDisplayAlternates : IUnknown
{
HRESULT GetDisplayAlternates(
[in] const SPDISPLAYPHRASE *pPhrase,
[in] ULONG cRequestCount,
[annotation("__out_ecount_part(cRequestCount, *pcPhrasesReturned)")][out] SPDISPLAYPHRASE **ppCoMemPhrases,
[out] ULONG *pcPhrasesReturned);
HRESULT SetFullStopTrailSpace([in] ULONG ulTrailSpace);
};

[
uuid(41B89B6C-9399-11D2-9623-00C04F8EE628),
version(1.0),
helpstring("SampleSrEngine 1.0 Type Library")
]
library SRENGLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");

[
uuid(41B89B79-9399-11D2-9623-00C04F8EE628),
helpstring("Sample SR Engine Class")
]
coclass SampleSREngine
{
[default] interface ISpSREngine;
};
[
uuid(B84714C0-3BFD-405D-83C5-E9C486826AD5),
helpstring("Sample SR Engine UI Class")
]
coclass SampleSREngineUI
{
[default] interface ISpTokenUI;
};
[
uuid(78771A48-CE55-46a5-B78C-B813E3403F82),
helpstring("Sample SR Engine Extension Class")
]
coclass SampleSRExtension
{
[default] interface ISampleSRExtension;
interface ISpDisplayAlternates;
};
[
uuid(882CAE4A-99BA-490b-BF80-CF69A60454A7),
helpstring("Sample SR Engine Alternates Class")
]
coclass SampleSREngineAlternates
{
[default] interface ISpSRAlternates;
};
};

* srengui.cpp
*此文件包含执行CSrEngineUI界面。
*本实施ISpTokenUI 。这是使用的应用程序,以显示用户界面。
*这里的方法可以是所谓的应用程序直接从ISpObjectToken获取电话
*能作为一个电话识别服务

******************************************************************************/

#include "stdafx.h"
#include "SampleSrEngine.h"
#include "srengui.h"

/************************************************* ***************************
* CSrEngineUI : : IsUISupported *
*----------------------------*
*描述:
*确定是否对用户界面的支持。提到主要引擎
*对象(如果已建立) ,可从punkObject 。
*如果没有空,这可能是一个ISpRecoContext ,其中一个引擎
*扩展接口可以得到。
*
*返回:
* S_OK成功
* E_INVALIDARG无效论点
************************************************** ***************************/
STDMETHODIMP CSrEngineUI::IsUISupported(const WCHAR * pszTypeOfUI, void * pvExtraData, ULONG cbExtraData, IUnknown * punkObject, BOOL *pfSupported)
{
*pfSupported = FALSE;

if (wcscmp(pszTypeOfUI, SPDUI_EngineProperties) == 0)
*pfSupported = TRUE;

if (wcscmp(pszTypeOfUI, SPDUI_UserTraining) == 0 && punkObject != NULL)
*pfSupported = TRUE;

if (wcscmp(pszTypeOfUI, SPDUI_MicTraining) == 0 && punkObject != NULL)
*pfSupported = TRUE;

return S_OK;
}

STDMETHODIMP CSrEngineUI::DisplayUI(HWND hwndParent, const WCHAR * pszTitle, const WCHAR * pszTypeOfUI, void * pvExtraData, ULONG cbExtraData, ISpObjectToken * pToken, IUnknown * punkObject)
{

if (wcscmp(pszTypeOfUI, SPDUI_EngineProperties) == 0)
{
if (punkObject)
{
MessageBoxW(hwndParent, L"Developer Sample Engine: Replace this with real engine properties dialog.", pszTitle, MB_OK);
}
}

if (wcscmp(pszTypeOfUI, SPDUI_UserTraining) == 0)
{
MessageBoxW(hwndParent, L"Developer Sample Engine: Replace this with real user training wizard / dialog.", pszTitle, MB_OK);
}

if (wcscmp(pszTypeOfUI, SPDUI_MicTraining) == 0)
{
MessageBoxW(hwndParent, L"Developer Sample Engine: Replace this with real microphone training wizard / dialog.", pszTitle, MB_OK);
}

return S_OK;
}

/******************************************************************************

* srengobj.cpp
*此文件包含执行CSrEngine级。
*本实施ISpSREngine , ISpSREngine2和ISpObjectWithToken 。
*这是主要识别对象

******************************************************************************/

#include "stdafx.h"
#include "SampleSrEngine.h"
#include "srengobj.h"
#include "SpHelper.h"
#ifndef _WIN32_WCE
#include "shfolder.h"
#endif

static const WCHAR DICT_WORD[] = L"Blah";
static const WCHAR ALT_WORD[] = L"Alt";

HRESULT CSrEngine::FinalConstruct()
{

HRESULT hr = S_OK;

m_hQueueHasRoom = ::CreateEvent(NULL, TRUE, TRUE, NULL);
m_FrameQueue.SetSpaceAvailEvent(m_hQueueHasRoom);

CComPtr<ISpTaskManager> cpTaskMgr;
hr = cpTaskMgr.CoCreateInstance(CLSID_SpResourceManager);
if (SUCCEEDED(hr))
{
hr = cpTaskMgr->CreateThreadControl(this, this, THREAD_PRIORITY_NORMAL, &m_cpDecoderThread);
}

if(SUCCEEDED(hr))
{

hr = m_cpLexicon.CoCreateInstance(CLSID_SpLexicon);
}
return hr;
}

HRESULT CSrEngine::FinalRelease()
{

::CloseHandle(m_hQueueHasRoom);
return S_OK;
}

/****************************************************************************

* CSrEngine : : SetObjectToken *
*---------------------------*
*描述:
*这种方法被称为后立即通过的SAPI引擎创建。
*它可以用来获得特定的注册表信息引擎。
*新的扫描引擎能恢复过来的凭证文件路径存储在安装过程中。
*该引擎还可以恢复用户设置为默认值的准确性,排斥等
*也可以有不同的发动机共享同一代码基础(的CLSID ) ,但具有不同登录信息
*例如:如果引擎支持不同的语言
*返回:
* S_OK
*失败(小时)

*****************************************************************************/
STDMETHODIMP CSrEngine::SetObjectToken(ISpObjectToken * pToken)
{

HRESULT hr = S_OK;
hr = SpGenericSetObjectToken(pToken, m_cpEngineObjectToken);
if(FAILED(hr))
{
return hr;
}
CComPtr<ISpDataKey> cpAttribKey;
hr = pToken->OpenKey(L"Attributes", &cpAttribKey);

if(SUCCEEDED(hr))
{
WCHAR *psz = NULL;
hr = cpAttribKey->GetStringValue(L"Desktop", &psz);
::CoTaskMemFree(psz);
if(SUCCEEDED(hr))
{
}
else if(hr == SPERR_NOT_FOUND)
{
hr = cpAttribKey->GetStringValue(L"Telephony", &psz);
::CoTaskMemFree(psz);
if(SUCCEEDED(hr))
{
}
}
}

if(SUCCEEDED(hr))
{
WCHAR *pszLangID = NULL;
hr = cpAttribKey->GetStringValue(L"Language", &pszLangID);
if(SUCCEEDED(hr))
{

m_LangID = (unsigned short)wcstol(pszLangID, NULL, 16);
::CoTaskMemFree(pszLangID);
}
else
{
// Default language (US English)
m_LangID = 0x409;
}
}

WCHAR *pszPath = NULL;

hr = pToken->GetStorageFileName(CLSID_SampleSREngine, L"SampleEngDataFile", NULL, 0, &pszPath);

::CoTaskMemFree(pszPath);

return hr;
}

/****************************************************************************

* CSrEngine : : GetObjectToken *
*---------------------------*
*描述:
*这种方法被称为的SAPI令牌,如果找到这些对象令牌,该引擎使用
*返回:
* S_OK
*失败(小时)

*****************************************************************************/
STDMETHODIMP CSrEngine::GetObjectToken(ISpObjectToken ** ppToken)
{

return SpGenericGetObjectToken(ppToken, m_cpEngineObjectToken);
}

/****************************************************************************

* CSrEngine : : SetSite *
*---------------------------*
*描述:
*这就是所谓的让引擎的参考ISpSREngineSite 。
*引擎使用此呼吁回的SAPI 。
*返回:
* S_OK
* S_OK
*失败(小时)

*****************************************************************************/
STDMETHODIMP CSrEngine::SetSite(ISpSREngineSite *pSite)
{
m_cpSite = pSite;
return S_OK;
}

/****************************************************************************

* CSrEngine : : SetRecoProfile *
*---------------------------*
*描述:
*在RecoProfile是一个对象令牌举行关于当前
*用户和注册会议。该引擎可以存储在这里的任何信息
*它喜欢。它应存放在一个关键的RecoProfile主要命名引擎类ID 。
*返回:
* S_OK
*失败(小时)

*****************************************************************************/
STDMETHODIMP CSrEngine::SetRecoProfile(ISpObjectToken *pProfile)
{
HRESULT hr = S_OK;
WCHAR *pszCLSID, *pszPath = NULL;
CComPtr<ISpDataKey> dataKey;

m_cpUserObjectToken = pProfile;

hr = ::StringFromCLSID(CLSID_SampleSREngine, &pszCLSID);
if(FAILED(hr))
{
return hr;
}

hr = pProfile->OpenKey(pszCLSID, &dataKey);
if(hr == SPERR_NOT_FOUND)
{

hr = pProfile->CreateKey(pszCLSID, &dataKey);
if(SUCCEEDED(hr))
{
hr = dataKey->SetStringValue(L"GENDER", L"UNKNOWN");
}
if(SUCCEEDED(hr))
{
hr = dataKey->SetStringValue(L"AGE", L"UNKNOWN");
}
if(SUCCEEDED(hr))
{
pProfile->GetStorageFileName(CLSID_SampleSREngine, L"SampleEngTrainingFile", NULL, CSIDL_FLAG_CREATE | CSIDL_LOCAL_APPDATA, &pszPath);
}

hr = AddEventString(SPEI_REQUEST_UI, 0, SPDUI_UserTraining);

}
else if(SUCCEEDED(hr))
{

WCHAR *pszGender = NULL, *pszAge = NULL;
hr = dataKey->GetStringValue(L"GENDER", &pszGender);
if(SUCCEEDED(hr))
{
hr = dataKey->GetStringValue(L"AGE", &pszAge);
}

if(SUCCEEDED(hr))
{
hr = pProfile->GetStorageFileName(CLSID_SampleSREngine, L"SampleEngTrainingFile", NULL, 0, &pszPath);
}

::CoTaskMemFree(pszGender);
::CoTaskMemFree(pszAge);
}

::CoTaskMemFree(pszPath);
::CoTaskMemFree(pszCLSID);
return hr;
}

/****************************************************************************

* CSrEngine : : OnCreateRecoContext *
*---------------------------*
*描述:
*这种方法被称为每当有新reco方面是建立在
*申请使用这个引擎。
*本示例引擎不严格需要信息reco背景
*但是,以供参考,我们将继续清单一人。
*返回:
* S_OK
*失败(小时)

*****************************************************************************/
STDMETHODIMP CSrEngine::OnCreateRecoContext(SPRECOCONTEXTHANDLE hSapiContext, void ** ppvDrvCtxt)
{

CContext * pContext = new CContext(hSapiContext);

// Store a reference to the CContext structure
*ppvDrvCtxt = pContext;
m_ContextList.InsertHead(pContext);

return S_OK;
}

/****************************************************************************

* CSrEngine : : OnDeleteRecoContext *
*---------------------------*
*描述:
*这种方法被称为每次reco方面被删除。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::OnDeleteRecoContext(void * pvDrvCtxt)
{

CContext * pContext = (CContext *) pvDrvCtxt;
m_ContextList.Remove(pContext);
delete pContext;

return S_OK;
}

/****************************************************************************

* CSrEngine : : OnCreateGrammar *
*---------------------------*
*描述:
*这种方法被称为每当有新reco语法中创建
*申请使用这个引擎。
*我们保留名单语法-存储一个指针列表条目ppvEngineGrammar 。
*返回:
* S_OK
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::OnCreateGrammar(void * pvEngineRecoContext, SPGRAMMARHANDLE hSapiGrammar, void ** ppvEngineGrammar)
{

CContext * pContext = (CContext *) pvEngineRecoContext;
_ASSERT(m_ContextList.Find(pContext->m_hSapiContext));

CDrvGrammar * pGrammar = new CDrvGrammar(hSapiGrammar);
*ppvEngineGrammar = pGrammar;
m_GrammarList.InsertHead(pGrammar);

return S_OK;
}

/****************************************************************************

* CSrEngine : : OnDeleteGrammar *
*---------------------------*
*描述:
*这种方法被称为每次reco语法被删除。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::OnDeleteGrammar(void * pvDrvGrammar)
{

CDrvGrammar * pGrammar = (CDrvGrammar *)pvDrvGrammar;
m_GrammarList.Remove(pGrammar);
delete pGrammar;

return S_OK;
}

STDMETHODIMP CSrEngine::WordNotify(SPCFGNOTIFY Action, ULONG cWords, const SPWORDENTRY * pWords)
{

HRESULT hr = S_OK;
ULONG i;
WCHAR *wordPron;

switch(Action){
case SPCFGN_ADD:
SPWORDENTRY WordEntry;
for(i = 0; SUCCEEDED(hr) && i < cWords; i++)
{
WordEntry = pWords[i];
hr = m_cpSite->GetWordInfo(&WordEntry, SPWIO_WANT_TEXT);
if(SUCCEEDED(hr) && WordEntry.aPhoneId)
{

size_t cWordPron = wcslen(WordEntry.aPhoneId) + 1;
wordPron = new WCHAR[cWordPron];
wcscpy_s(wordPron, cWordPron, WordEntry.aPhoneId);
::CoTaskMemFree((void*)WordEntry.aPhoneId);
}
else
{

SPWORDPRONUNCIATIONLIST PronList;
PronList.pFirstWordPronunciation = 0;
PronList.pvBuffer = 0;
PronList.ulSize = 0;
hr = m_cpLexicon->GetPronunciations(WordEntry.pszLexicalForm, eLEXTYPE_APP | eLEXTYPE_USER, pWords[i].LangID, &PronList);
if(SUCCEEDED(hr))
{
if(PronList.pFirstWordPronunciation != NULL)
{

size_t cWordPron = wcslen(PronList.pFirstWordPronunciation->szPronunciation) + 1;
wordPron = new WCHAR[cWordPron];
wcscpy_s(wordPron, cWordPron, PronList.pFirstWordPronunciation->szPronunciation);
::CoTaskMemFree(PronList.pvBuffer);
}
else
{

wordPron = NULL;
}
}
else if(hr == SPERR_NOT_IN_LEX)

wordPron = NULL;
hr = S_OK;
}
else
{
break;
}

if(SUCCEEDED(hr))
{

hr = m_cpSite->SetWordClientContext(WordEntry.hWord, wordPron);
}
}

if (SUCCEEDED(hr))
{
::CoTaskMemFree((void*)WordEntry.pszDisplayText);
::CoTaskMemFree((void*)WordEntry.pszLexicalForm);
}
}
break;
case SPCFGN_REMOVE:
for(i = 0; i < cWords; i++)
{
WordEntry = pWords[i];

wordPron = (WCHAR *) WordEntry.pvClientContext;
if(wordPron)
{
delete[] wordPron;
}
}
break;
}

return hr;
}

/****************************************************************************

* CSrEngine : : RuleNotify *
*---------------------------*
*描述:
*这种方法被称为由SAPI的通知引擎的规则,
*指挥及控制语法。该命令或行动CFG桩语法是这种形式:
* WordNotify ( SPCFGN_ADD ) -添加关键词
* RuleNotify ( SPCFGN_ADD ) -添加规则
* RuleNotify ( SPCFGN_ACTIVATE ) -激活规则,以表明它们是用于识别
* RuleNotify ( SPCFGN_INVALIDATE ) -如果规则得到编辑的应用程序那么这就是所谓的
* RuleNotify ( SPCFGN_DEACTIVE ) -停用规则
* RuleNotify ( SPCFGN_REMOVE ) -删除规则
* WordNotify ( SPCFGN_REMOVE ) -删除字词
*
*该引擎可致电GetRuleInfo找到初始状态中的规则,
*然后GetStateInfo找到有关国家和转型以后的规则。
*如果规则编辑然后SPCFGN_INVALIDATE称为表明规则已经改变,使引擎
*必须重法治的信息。
*
*新的扫描引擎能获得所有有关的规则之前或期间承认。
*在此示例中,我们只是保持发动机的清单规则最初然后等待
*直到我们要生成的结果,然后找到一个随机的路径规则。
*
*返回:
* S_OK
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::RuleNotify(SPCFGNOTIFY Action, ULONG cRules, const SPRULEENTRY * pRules)
{

ULONG i;
CRuleEntry *pRuleEntry;

switch (Action)
{
case SPCFGN_ADD:
for (i = 0; i < cRules; i++)
{

pRuleEntry = new CRuleEntry;
pRuleEntry->m_hRule = pRules[i].hRule;
pRuleEntry->m_fTopLevel = (pRules[i].Attributes & SPRAF_TopLevel);
pRuleEntry->m_fActive = (pRules[i].Attributes & SPRAF_Active);

m_RuleList.InsertHead(pRuleEntry);

m_cpSite->SetRuleClientContext(pRules[i].hRule, (void *)pRuleEntry);
}
break;
case SPCFGN_REMOVE:
for (i = 0; i < cRules; i++)
{
pRuleEntry = m_RuleList.Find(pRules[i].hRule);
_ASSERT(pRuleEntry); // The rule must have been added before being removed
m_RuleList.Remove(pRuleEntry);
delete pRuleEntry;
}
break;
case SPCFGN_ACTIVATE:
for (i = 0; i < cRules; i++)
{
pRuleEntry = m_RuleList.Find(pRules[i].hRule);

_ASSERT(pRuleEntry && !pRuleEntry->m_fActive && pRuleEntry->m_fTopLevel);
if (pRuleEntry != NULL)
{
pRuleEntry->m_fActive = TRUE;
}
}
break;
case SPCFGN_DEACTIVATE:
for (i = 0; i < cRules; i++)
{
pRuleEntry = m_RuleList.Find(pRules[i].hRule);
_ASSERT(pRuleEntry && pRuleEntry->m_fActive && pRuleEntry->m_fTopLevel);
if (pRuleEntry != NULL)
{
pRuleEntry->m_fActive = FALSE;
}
}
break;
case SPCFGN_INVALIDATE:
for (i = 0; i < cRules; i++)
{
pRuleEntry = m_RuleList.Find(pRules[i].hRule);
_ASSERT(pRuleEntry);
if (pRuleEntry != NULL)
{
pRuleEntry->m_fTopLevel = (pRules[i].Attributes & SPRAF_TopLevel);
pRuleEntry->m_fActive = (pRules[i].Attributes & SPRAF_Active);

}
}
break;
}

return S_OK;
}

/****************************************************************************

* CSrEngine : : LoadSLM *
*---------------------------*
*描述:
*时调用的SAPI希望引擎加载dictaion语言模式( SLM ) 。
*对于每一个听写reco gramar以及命令与征服规则可以被装载。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::LoadSLM(void * pvEngineGrammar, const WCHAR * pszTopicName)
{

if (pszTopicName)
{

}

CDrvGrammar * pGrammar = (CDrvGrammar *)pvEngineGrammar;
pGrammar->m_SLMLoaded = TRUE;

return S_OK;
}

/****************************************************************************

* CSrEngine : : UnloadSLM *
*---------------------------*
*描述:
*时调用的SAPI希望引擎删除解运。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::UnloadSLM(void *pvEngineGrammar)
{

CDrvGrammar * pGrammar = (CDrvGrammar *)pvEngineGrammar;
pGrammar->m_SLMLoaded = FALSE;

return S_OK;
}

/****************************************************************************

* CSrEngine : : SetSLMState *
*---------------------------*
*描述:
*调用以激活或停用的语法
* NewState要么SPRS_ACTIVE或SPRS_INACTIVE 。
*返回:
* S_OK

*****************************************************************************/
HRESULT CSrEngine::SetSLMState(void * pvDrvGrammar, SPRULESTATE NewState)
{

CDrvGrammar * pGrammar = (CDrvGrammar *)pvDrvGrammar;
if (NewState != SPRS_INACTIVE)
{
pGrammar->m_SLMActive = TRUE;
}
else
{
pGrammar->m_SLMActive = FALSE;
}

return S_OK;
}

/****************************************************************************

* CSrEngine : : SetWordSequenceData *
*---------------------------*
*描述:
*如果应用程序提交一个文本缓冲区的SAPI这种方法被称为。
*的文本缓冲区这里提供可以用于CFGs的文本缓冲区过渡,
*或听写提供资料的发动机事先看见屏幕上的文字。
*本示例引擎就是使用文字的文本缓冲区缓冲区过渡。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::SetWordSequenceData(void *pvEngineGrammar, const WCHAR *pText, ULONG cchText, const SPTEXTSELECTIONINFO *pInfo)
{

CDrvGrammar * pGrammar = (CDrvGrammar*)pvEngineGrammar;

if(pGrammar->m_pWordSequenceText)
{
delete pGrammar->m_pWordSequenceText;
}

if(cchText)
{
pGrammar->m_pWordSequenceText = new WCHAR[cchText];
memcpy((void *)pGrammar->m_pWordSequenceText, pText, sizeof(WCHAR) * cchText);
pGrammar->m_cchText = cchText;
}
else
{
pGrammar->m_pWordSequenceText = NULL;
pGrammar->m_cchText = NULL;
}

SetTextSelection(pvEngineGrammar, pInfo);

return S_OK;
}

/****************************************************************************

* CSrEngine : : SetTextSelection *
*---------------------------*
*描述:
*这种方法告诉引擎如果SPTEXTSELECTIONINFO结构
*已更新。本示例只使用发动机领域ulStartActiveOffset和cchActiveChars的SPTEXTSELECTIONINFO 。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::SetTextSelection(void * pvEngineGrammar, const SPTEXTSELECTIONINFO * pInfo)
{

CDrvGrammar * pGrammar = (CDrvGrammar*)pvEngineGrammar;

if (pGrammar->m_pInfo)
{
delete pGrammar->m_pInfo;
}

if (pInfo)
{
pGrammar->m_pInfo = new SPTEXTSELECTIONINFO(*pInfo);
}
else
{
pGrammar->m_pInfo = NULL;
}

return S_OK;
}

/****************************************************************************

* CSrEngine : : IsPronounceable *
*---------------------------*
*描述:
*发动机应该回到它是否已经或将能够
*产生的这个词的发音。
*在此示例中的引擎,这是总是如此。
*返回:
* S_OK

*****************************************************************************/
STDMETHODIMP CSrEngine::IsPronounceable(void * pDrvGrammar, const WCHAR * pszWord, SPWORDPRONOUNCEABLE * pWordPronounceable)
{

*pWordPronounceable = SPWP_KNOWN_WORD_PRONOUNCEABLE;
return S_OK;
}

/****************************************************************************

* CSrEngine : : SetAdaptationData *
*---------------------------*
*描述:
*这种方法可以使用的应用程序,使文本数据引擎
*为适应语言模型等方法只能被称为
*的应用程序后,如果收到了SPEI_ADAPTATION活动。

*返回:
* E_UNEXPECTED

*****************************************************************************/
STDMETHODIMP CSrEngine::SetAdaptationData(void * pvEngineCtxtCookie, const WCHAR *pAdaptationData, const ULONG cch)
{

_ASSERT(0);
return E_UNEXPECTED;
}

HRESULT CSrEngine::AddEvent(SPEVENTENUM eEventId, ULONGLONG ullStreamPos, WPARAM wParam, LPARAM lParam)
{

HRESULT hr = S_OK;

SPEVENT Event;
Event.eEventId = eEventId;
Event.elParamType = SPET_LPARAM_IS_UNDEFINED;
Event.ulStreamNum = 0;
Event.ullAudioStreamOffset = ullStreamPos;
Event.wParam = wParam;
Event.lParam = lParam;

hr = m_cpSite->AddEvent(&Event, NULL);

return hr;
}

HRESULT CSrEngine::AddEventString(SPEVENTENUM eEventId, ULONGLONG ullStreamPos, const WCHAR * psz, WPARAM wParam)
{

HRESULT hr = S_OK;

SPEVENT Event;
Event.eEventId = eEventId;
Event.elParamType = SPET_LPARAM_IS_STRING;
Event.ulStreamNum = 0;
Event.ullAudioStreamOffset = ullStreamPos;
Event.wParam = wParam;
Event.lParam = (LPARAM)psz;

hr = m_cpSite->AddEvent(&Event, NULL);

return hr;
}

/************************************************* ***************************
* CSrEngine : : RecognizeStream *
#定义BLOCKSIZE 220 / / 1 / 100秒
*---------------------------*
*描述:
*这是方法的SAPI呼吁承认发生。
*发动机只能由这个方法返回后,他们已经阅读所有数据
*并完成所有的承认,他们正在尽在此流。
*因此,这种方法是让一个线程的引擎做承认,
*和引擎可能会创造更多的线程。
*
*在此示例中,我们不断地读取数据,使用此线程,然后执行
*非常基本的语音检测,并通过数据传输到识别线程,这
*产生的假设和结果。
*
*参数:
*
* - REFGUID rguidFormatId -这是的GUID输入的音频格式
* -常量WAVEFORMATEX * pWaveFormatEx -这是扩大信息WAV格式的音频格式
* -拉手hRequestSync -这是使用的Win32事件表明,有尚未完成的任务
*和发动机应要求同步( )的SAPI的来处理这些。
* -拉手hDataAvailable -本的Win32事件是用来告诉引擎,数据可以被读取。
*频率,这是一套可控制的SetBufferNotifySize方法。
* -拉手hExit -本的Win32事件表示引擎正在关闭,并应立即结束。
* -布尔fNewAudioStream -这表明这是一个新的输入流
*例如:在应用方面做了新的SetInput要求,而不是仅仅重新启动前流。
* -布尔fRealTimeAudio -这表明,从投入的实时ISpAudio流,而不是说,一个文件
* - ISpObjectToken * pAudioObjectToken -这是象征性的对象代表音频输入装置
*引擎可能要查询这一点。
*
*返回:
* S_OK
*失败(小时)
************************************************** ***************************/

STDMETHODIMP CSrEngine::RecognizeStream(REFGUID rguidFormatId,
const WAVEFORMATEX * pWaveFormatEx,
HANDLE hRequestSync,
HANDLE hDataAvailable,
HANDLE hExit,
BOOL fNewAudioStream,
BOOL fRealTimeAudio,
ISpObjectToken * pAudioObjectToken)
{

HRESULT hr = S_OK;

m_hRequestSync = hRequestSync;

hr = m_cpDecoderThread->StartThread(0, NULL);

if (SUCCEEDED(hr))
{
const HANDLE aWait[] = { hExit, m_hQueueHasRoom };

while (TRUE) {

ULONG cbRead;
hr = m_cpSite->Read(aData, sizeof(aData), &cbRead);
if (hr != S_OK || cbRead < sizeof(aData))
{
break;
}

BOOL bNoiseDetected = FALSE;
SHORT * pBuffer = (SHORT *)aData;
for (ULONG i = 0; i < cbRead; i += 2, pBuffer++)
{
if (*pBuffer < (SHORT)-3000 || *pBuffer > (SHORT)3000)
{
bNoiseDetected = TRUE;
break;
}
}

BOOL bBlock = m_FrameQueue.IsFull();
if(bBlock)
{

if (::WaitForMultipleObjects(sp_countof(aWait), aWait, FALSE, INFINITE) == WAIT_OBJECT_0)
{
break;
}
}

m_FrameQueue.InsertTail(bNoiseDetected);
m_cpDecoderThread->Notify();

}

m_cpDecoderThread->WaitForThreadDone(TRUE, &hr, 30 * 1000);
}

m_hRequestSync = NULL;

return hr;
}

STDMETHODIMP CSrEngine::ThreadProc(void *, HANDLE hExitThreadEvent, HANDLE hNotifyEvent, HWND hwndWorker, volatile const BOOL * pfContinueProcessing)
{

HRESULT hr = S_OK;
const HANDLE aWait[] = { hExitThreadEvent, hNotifyEvent, m_hRequestSync };
ULONG block = 0;
ULONG silenceafternoise = 0;
DWORD waitres;

m_bSoundStarted = FALSE;
m_bPhraseStarted = FALSE;
m_cBlahBlah = 0;

m_ullStart = 0;
m_ullEnd = 0;
while (*pfContinueProcessing)
{

if(m_bPhraseStarted && (block - m_ullStart / BLOCKSIZE) < 5 * 100)
{
--cEvents;
}
waitres = ::WaitForMultipleObjects(cEvents, aWait, FALSE, INFINITE);
switch (waitres)
{

case WAIT_OBJECT_0:

break;

case WAIT_OBJECT_0 + 1:

m_cpSite->UpdateRecoPos((ULONGLONG)block * BLOCKSIZE);

if (m_ullStart == 0 && !m_bPhraseStarted)
{

m_cpSite->Synchronize((ULONGLONG)block * BLOCKSIZE);

}
while (m_FrameQueue.HasData())
{
BOOL bNoise = m_FrameQueue.RemoveHead();
block++; if (bNoise)
{

silenceafternoise = 0;
if (m_ullStart == 0)
{
m_ullStart = (ULONGLONG)block * BLOCKSIZE;
}
m_ullEnd = (ULONGLONG)block * BLOCKSIZE;
_CheckRecognition();
}
else
{

silenceafternoise++;
if (silenceafternoise > 50)
{
if (m_bSoundStarted)
{

if (m_bPhraseStarted)
{
_NotifyRecognition(FALSE, m_cBlahBlah);
}
AddEvent(SPEI_SOUND_END, m_ullEnd); // send the sound end event
m_bSoundStarted = FALSE;
m_bPhraseStarted = FALSE;
}
m_ullStart = 0;
m_ullEnd = 0;
}
}

if (block % (100 * 30) == 20 * 100)
{
const SPINTERFERENCE rgspi[] =
{ SPINTERFERENCE_NOISE, SPINTERFERENCE_NOSIGNAL, SPINTERFERENCE_TOOLOUD, SPINTERFERENCE_TOOQUIET };

AddEvent(SPEI_INTERFERENCE, block*BLOCKSIZE, 0, rgspi[rand() % 4]);
}
else if (block % (100 * 30) == 22 * 100)
{
AddEvent(SPEI_INTERFERENCE, block*BLOCKSIZE, 0, SPINTERFERENCE_NONE);
}

else if (block == 10 * 100)
{
AddEventString(SPEI_REQUEST_UI, block * BLOCKSIZE, SPDUI_UserTraining);
}
else if (block == 11 * 100) {
AddEventString(SPEI_REQUEST_UI, block * BLOCKSIZE, NULL);
}
}
break;

case WAIT_OBJECT_0 + 2:

m_cpSite->Synchronize((ULONGLONG)block * BLOCKSIZE);

m_ullStart = block * BLOCKSIZE;
if(m_ullEnd < m_ullStart)
{
m_ullEnd = m_ullStart;
}
break;

default:
_ASSERT(FALSE);

break;
}
}

if (m_bPhraseStarted)
{
_NotifyRecognition(FALSE, m_cBlahBlah);
}
if (m_bSoundStarted)
{
AddEvent(SPEI_SOUND_END, m_ullEnd);
}

return S_OK;
}

void CSrEngine::_CheckRecognition()
{

ULONG duration, blahs;

if (m_ullEnd > m_ullStart)
{
duration = (ULONG)(m_ullEnd - m_ullStart);
if (duration >= BLOCKSIZE * 100 * 1 / 8)
{
if (!m_bSoundStarted)
{

AddEvent(SPEI_SOUND_START, m_ullStart);
m_bSoundStarted = TRUE;
m_cBlahBlah = 0;
}
if (duration >= BLOCKSIZE * 100 * 1 / 4)
{

blahs = duration / (BLOCKSIZE * 100 * 1 / 4);
if (blahs != m_cBlahBlah)
{
m_cBlahBlah = blahs;
if (!m_bPhraseStarted)
{
m_bPhraseStarted = TRUE;
AddEvent(SPEI_PHRASE_START, m_ullStart);
}
_NotifyRecognition(TRUE, blahs);
}
}
}
}
}

void CSrEngine::_NotifyRecognition( BOOL fHypothesis, ULONG nWords )
{

HRESULT hr = S_OK;

ULONG cActiveCFGRules = 0;
CRuleEntry * pRule = m_RuleList.GetHead();
for(; pRule; pRule = m_RuleList.GetNext(pRule))
{
if( pRule->m_fActive )
{
cActiveCFGRules++;
}
}

ULONG cActiveSLM = 0;
CDrvGrammar * pGram = m_GrammarList.GetHead();
for(; pGram; pGram = m_GrammarList.GetNext(pGram))
{
if(pGram->m_SLMActive)
{
cActiveSLM++;
}
}

if(cActiveCFGRules && cActiveSLM)
{
if(rand() % 2)
{
cActiveSLM = 0;
}
else
{
cActiveCFGRules = 0;
}
}

SPRECORESULTINFO Result;
memset(&Result, 0, sizeof(SPRECORESULTINFO));
Result.cbSize = sizeof(SPRECORESULTINFO);
Result.fHypothesis = fHypothesis;
Result.ullStreamPosStart = m_ullStart;
Result.ullStreamPosEnd = m_ullEnd;

if( cActiveCFGRules )
{

hr = WalkCFGRule(&Result, cActiveCFGRules, fHypothesis, nWords, m_ullStart, (ULONG)(m_ullEnd - m_ullStart));
if( SUCCEEDED(hr) )
{

m_cpSite->Recognition(&Result);

for(ULONG i = 0; i < Result.ulNumAlts; i++)
{
Result.aPhraseAlts[i].pPhrase->Release();
}
Result.pPhrase->Release();
delete[] Result.aPhraseAlts;
}
}
else if(cActiveSLM)
{

hr = WalkSLM(&Result, cActiveSLM, nWords, m_ullStart, (ULONG)(m_ullEnd - m_ullStart));
if( SUCCEEDED(hr) )
{

m_cpSite->Recognition(&Result);

Result.pPhrase->Release();
delete[] Result.pvEngineData;
}
}
else if(!fHypothesis)
{

Result.eResultType = SPRT_FALSE_RECOGNITION;
m_cpSite->Recognition(&Result);
}

}

HRESULT CSrEngine::CreatePhraseFromRule( CRuleEntry * pRule, BOOL fHypothesis,
ULONGLONG ullAudioPos, ULONG ulAudioSize,
ISpPhraseBuilder** ppPhrase )
{
HRESULT hr = S_OK;
SPRULEENTRY RuleInfo;
RuleInfo.hRule = pRule->m_hRule;
hr = m_cpSite->GetRuleInfo(&RuleInfo, SPRIO_NONE);
if( SUCCEEDED(hr) )
{

const ULONG MAXPATH = 200;
SPPATHENTRY Path[MAXPATH];
ULONG cTrans;

hr = RecurseWalk(RuleInfo.hInitialState, Path, &cTrans);

if (cTrans)
{
ULONG ulInterval = ulAudioSize/cTrans;
for (ULONG ul = 0; ul < cTrans && ul < MAXPATH; ul++)
{
Path[ul].elem.ulAudioStreamOffset = ul * ulInterval;
Path[ul].elem.ulAudioSizeBytes = ulInterval/2;
}
}

if (SUCCEEDED(hr))
{

SPPARSEINFO ParseInfo;
memset(&ParseInfo, 0, sizeof(ParseInfo));
ParseInfo.cbSize = sizeof(SPPARSEINFO);
ParseInfo.hRule = pRule->m_hRule;
ParseInfo.ullAudioStreamPosition = ullAudioPos;
ParseInfo.ulAudioSize = ulAudioSize;
ParseInfo.cTransitions = cTrans;
ParseInfo.pPath = Path;
ParseInfo.fHypothesis = fHypothesis;
ParseInfo.SREngineID = CLSID_SampleSREngine;
ParseInfo.ulSREnginePrivateDataSize = 0;
ParseInfo.pSREnginePrivateData = NULL;

hr = m_cpSite->ParseFromTransitions(&ParseInfo, ppPhrase );
if(SUCCEEDED(hr))
{

for(ULONG i = 0; i < cTrans; i++)
{
if(Path[i].elem.pszDisplayText)
{
delete const_cast<WCHAR*>(Path[i].elem.pszDisplayText);
}
}
}
}
}
return hr;
}

CRuleEntry* CSrEngine::FindRule( ULONG ulRuleIndex )
{
CRuleEntry * pRule = m_RuleList.GetHead();
ULONG ulRule = 0;
while( pRule )
{
if( pRule->m_fActive && ( ulRule++ == ulRuleIndex ) )
{
break;
}
pRule = m_RuleList.GetNext( pRule );
}
_ASSERT(pRule && pRule->m_fActive);
return pRule;
}

CRuleEntry* CSrEngine::NextRuleAlt( CRuleEntry * pPriRule, CRuleEntry * pLastRule )
{
CRuleEntry * pRule = (pLastRule)?(pLastRule):(m_RuleList.GetHead());
for(; pRule; pRule = m_RuleList.GetNext(pRule))
{
if( pRule->m_fActive &&
( m_cpSite->IsAlternate( pPriRule->m_hRule, pRule->m_hRule ) == S_OK ) )
{
break;
}
}
return pRule;
}

HRESULT CSrEngine::WalkCFGRule( SPRECORESULTINFO * pResult, ULONG cRulesActive, BOOL fHypothesis,
ULONG nWords, ULONGLONG ullAudioPos, ULONG ulAudioSize)
{
HRESULT hr = E_FAIL;
CRuleEntry * pPriRule = NULL;
pResult->ulSizeEngineData = 0;
pResult->pvEngineData = NULL;
pResult->eResultType = SPRT_CFG;
pResult->hGrammar = NULL;

while (hr == E_FAIL)
{

pPriRule = FindRule( rand() % cRulesActive );

hr = CreatePhraseFromRule( pPriRule, fHypothesis, ullAudioPos,
ulAudioSize, &pResult->pPhrase );
}

if (hr != S_OK)
{
_ASSERT(FALSE);
}

SPPHRASE* pPriPhraseInfo = NULL;
if( SUCCEEDED( hr ) )
{
hr = pResult->pPhrase->GetPhrase( &pPriPhraseInfo );
}

ULONG ulNumAlts = 0;
if( SUCCEEDED( hr ) )
{
hr = m_cpSite->GetMaxAlternates( pPriRule->m_hRule, &ulNumAlts );
}

if( SUCCEEDED( hr ) && ulNumAlts )
{
pResult->aPhraseAlts = new SPPHRASEALT[ulNumAlts];
if( pResult->aPhraseAlts )
{
memset( pResult->aPhraseAlts, 0, ulNumAlts * sizeof(SPPHRASEALT) );
CRuleEntry * pAltRule = NULL;

for( ULONG i = 0; SUCCEEDED( hr ) && (i < ulNumAlts); ++i )
{

pAltRule = NextRuleAlt( pPriRule, pAltRule );
if( !pAltRule )
{
break;
}

hr = CreatePhraseFromRule( pAltRule, fHypothesis, ullAudioPos,
ulAudioSize, &pResult->aPhraseAlts[i].pPhrase );

SPPHRASE* pAltPhraseInfo = NULL;
if( SUCCEEDED( hr ) )
{
hr = pResult->aPhraseAlts[i].pPhrase->GetPhrase( &pAltPhraseInfo );
}

if( SUCCEEDED( hr ) )
{
++pResult->ulNumAlts;

pResult->aPhraseAlts[i].cElementsInParent = pPriPhraseInfo->Rule.ulCountOfElements;
pResult->aPhraseAlts[i].cElementsInAlternate = pAltPhraseInfo->Rule.ulCountOfElements;

static BYTE AltData[] = { 0xED, 0xED, 0xED, 0xED };
pResult->aPhraseAlts[i].pvAltExtra = &AltData;
pResult->aPhraseAlts[i].cbAltExtra = sp_countof( AltData );
}

if( pAltPhraseInfo )
{
::CoTaskMemFree( pAltPhraseInfo );
}
}
}
else
{
E_OUTOFMEMORY;
}
}

// Cleanup main phrase information
if( pPriPhraseInfo )
{
::CoTaskMemFree( pPriPhraseInfo );
}

// Cleanup on failure
if( FAILED( hr ) )
{
if( pResult->pPhrase )
{
pResult->pPhrase->Release();
pResult->pPhrase = NULL;
}

for( ULONG i = 0; i < pResult->ulNumAlts; ++i )
{
pResult->aPhraseAlts[i].pPhrase->Release();
pResult->aPhraseAlts[i].pPhrase = NULL;
}
pResult->ulNumAlts = 0;
delete[] pResult->aPhraseAlts;
pResult->aPhraseAlts = NULL;
}

return hr;
}

HRESULT CSrEngine::WalkSLM(SPRECORESULTINFO * pResult, ULONG cSLMActive,
ULONG nWords, ULONGLONG ullAudioPos, ULONG ulAudioSize)
{
HRESULT hr = S_OK;

ULONG ulGramIndex = rand() % cSLMActive;
CDrvGrammar * pGram = m_GrammarList.GetHead();
ULONG nGram = 0;
for(; pGram; pGram = m_GrammarList.GetNext(pGram))
{
if(pGram->m_SLMActive)
{
if(nGram == ulGramIndex)
{
break;
}
nGram++;
}
}
_ASSERT(pGram && pGram->m_SLMActive);

if( pGram == NULL )
{
return E_FAIL;
}

SPPHRASE phrase;
memset(&phrase, 0, sizeof(SPPHRASE));
phrase.cbSize = sizeof(SPPHRASE);
phrase.LangID = m_LangID;
phrase.ullAudioStreamPosition = ullAudioPos;
phrase.ulAudioSizeBytes = ulAudioSize;
phrase.SREngineID = CLSID_SampleSREngine;

ULONG cb = nWords * sizeof(SPPHRASEELEMENT);
SPPHRASEELEMENT* pElements = (SPPHRASEELEMENT *)_malloca(cb);
memset(pElements, 0, cb);

for (ULONG n = 0; n < nWords; n++)
{
ULONG ulInterval = ulAudioSize/nWords;

pElements[n].bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
pElements[n].pszDisplayText = DICT_WORD;
pElements[n].ulAudioStreamOffset = n * ulInterval;
pElements[n].ulAudioSizeBytes = ulInterval/2;

}

phrase.Rule.ulCountOfElements = nWords;
phrase.pElements = pElements;

CComPtr<ISpPhraseBuilder> cpBuilder;
hr = cpBuilder.CoCreateInstance(CLSID_SpPhraseBuilder);
if (SUCCEEDED(hr))
{
hr = cpBuilder->InitFromPhrase(&phrase);
}

if (SUCCEEDED(hr))
{

pResult->ulSizeEngineData = sizeof(ALT_WORD) * nWords;
pResult->pvEngineData = new WCHAR[(sizeof(ALT_WORD) / sizeof(WCHAR )) * nWords];
if (pResult->pvEngineData == NULL)
{
hr = E_OUTOFMEMORY;
}
}

if (SUCCEEDED(hr))
{
WCHAR *pC = (WCHAR *)pResult->pvEngineData;
size_t cRemainingSize = (size_t)pResult->ulSizeEngineData / sizeof(WCHAR);
for(ULONG i = 0; i < nWords; i++)
{
wcscpy_s(pC, cRemainingSize, ALT_WORD);
size_t cAltWord = wcslen(ALT_WORD);
pC += cAltWord;
*pC = ‘ ‘;
pC++;
cRemainingSize -= cAltWord + 1;
}
*(--pC) = ‘/0‘;

pResult->eResultType = SPRT_SLM;
pResult->hGrammar = pGram->m_hSapiGrammar;
}

if (SUCCEEDED(hr))
{
pResult->pPhrase = cpBuilder.Detach();
}
else
{
delete[] pResult->pvEngineData;
pResult->pvEngineData = NULL;
pResult->ulSizeEngineData = 0;
}

_freea(pElements);

return hr;
}

HRESULT CSrEngine::WalkTextBuffer(void* pvGrammarCookie, SPPATHENTRY * pPath, SPTRANSITIONID hId, ULONG * pcTrans)
{
HRESULT hr = S_OK;

CDrvGrammar * pGrammar = (CDrvGrammar *) pvGrammarCookie;
_ASSERT(pGrammar->m_pWordSequenceText && pGrammar->m_cchText >= 2);
if (!pGrammar->m_pWordSequenceText || pGrammar->m_cchText < 2)
{
return E_UNEXPECTED;
}

*pcTrans = 0;

ULONG nPhrase = 0;
const WCHAR *cPhrase;

ULONG ulStartActiveOffset = 0; //The default value with text selection
ULONG cchActiveChars = pGrammar->m_cchText - 2; //The default value with text selection
ULONG ccChars = 0;

if (pGrammar->m_pInfo)
{
ulStartActiveOffset = pGrammar->m_pInfo->ulStartActiveOffset;
cchActiveChars = pGrammar->m_pInfo->cchActiveChars;
}

for (cPhrase = pGrammar->m_pWordSequenceText + ulStartActiveOffset;
ccChars < cchActiveChars && (*cPhrase != L‘/0‘ || *(cPhrase + 1) != ‘/0‘);
ccChars++, cPhrase++)
{
if(*cPhrase != L‘/0‘ && *(cPhrase + 1) == L‘/0‘)
{
nPhrase++;
}
}

if (nPhrase == 0)
{
return E_FAIL;
}

nPhrase = rand() % nPhrase; //nPhrase would be 0 index
ULONG nP = 0;
for(cPhrase = pGrammar->m_pWordSequenceText + ulStartActiveOffset; nP != nPhrase; cPhrase++)
{
if(*cPhrase == L‘/0‘)
{
nP++;
}
}

// Count words in sentence
ULONG nWord = 1;
const WCHAR *cWord;
for(cWord = cPhrase; *cWord != L‘/0‘ && ULONG(cWord - pGrammar->m_pWordSequenceText) < ulStartActiveOffset + cchActiveChars; cWord++)
{
if(iswspace(*cWord))
{
while(*(cWord+1) && iswspace(*(cWord+1)) && ULONG(cWord - pGrammar->m_pWordSequenceText) < ulStartActiveOffset + cchActiveChars - 1) {cWord++;}
nWord++;
}
}

ULONG startWord = rand() % nWord;
ULONG countWord = rand() % (nWord - startWord) + 1;

for(nWord = 0, cWord = cPhrase; nWord != startWord; cWord++)
{
if(iswspace(*cWord))
{
while(*(cWord+1) && iswspace(*(cWord+1)) && ULONG(cWord - pGrammar->m_pWordSequenceText) < ulStartActiveOffset + cchActiveChars - 1) {cWord++;}
nWord++;
}
}

const WCHAR *cW = cWord;
for(nWord = 0; nWord != countWord; cWord++)
{
if(*cWord == L‘/0‘ || iswspace(*cWord) || ULONG(cWord - pGrammar->m_pWordSequenceText) == ulStartActiveOffset + cchActiveChars)
{

pPath->hTransition = hId;
memset(&pPath->elem, 0, sizeof(pPath->elem));
pPath->elem.bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
WCHAR *pszWord = new WCHAR[cWord - cW + 1];
wcsncpy_s(pszWord, cWord - cW + 1, cW, cWord - cW);
pszWord[cWord - cW] = ‘/0‘;
pPath->elem.pszDisplayText = pszWord;

pPath++;
(*pcTrans)++;

while(*(cWord+1) && iswspace(*(cWord+1)) && ULONG(cWord - pGrammar->m_pWordSequenceText) < ulStartActiveOffset + cchActiveChars - 1) {cWord++;}
cW = cWord + 1; // first char of next word
nWord++;
}
}

return hr;
}

/****************************************************************************
/************************************************* ***************************
* CSrEngine : : RecognizeStream *
*---------------------------*
*描述:
*这是方法的SAPI呼吁承认发生。
*发动机只能由这个方法返回后,他们已经阅读所有数据
*并完成所有的承认,他们正在尽在此流。
*因此,这种方法是让一个线程的引擎做承认,
*和引擎可能会创造更多的线程。
* CSrEngine : : RecurseWalk *
*----------------------*
*描述:
*这种方法产生的随机路径通过积极CFG桩。如果路径中包含
*规则参考过渡RecurseWalk是递归要求生产的道路虽然
*分规则。结果是一系列的SPPATHENTRY内容包含过渡。
*
*初始状态每个规则中得到致电GetRuleInfo 。然后为每个
*国家GetStateInfo可称为。这使一系列SPTRANSITION条目
*在包含的信息类型的转型,转型的ID和
*在未来国家的过渡去。过渡编号是主要的信息
*包括在SPPATHENTRY 。只适用于Word过渡SPPATHENTRY创建,
*因为这是所有所需的ParseFromTransitions 。
*
*返回:
* S_OK
*失败(小时)
****************************************************************************/
HRESULT CSrEngine::RecurseWalk(SPSTATEHANDLE hState, SPPATHENTRY * pPath, ULONG * pcTrans)
{
HRESULT hr = S_OK;

CSpStateInfo StateInfo;
*pcTrans = 0;
while (SUCCEEDED(hr) && hState)
{
ULONG cTrans;
hr = m_cpSite->GetStateInfo(hState, &StateInfo);
if (SUCCEEDED(hr))
{

ULONG cTransInState = StateInfo.cEpsilons + StateInfo.cWords + StateInfo.cRules + StateInfo.cSpecialTransitions;
if (cTransInState == 0)
{

hr = E_FAIL;
break;
}
SPTRANSITIONENTRY * pTransEntry = StateInfo.pTransitions + (rand() % cTransInState);

switch(pTransEntry->Type)
{
case SPTRANSEPSILON:

break;
case SPTRANSRULE:

hr = RecurseWalk(pTransEntry->hRuleInitialState, pPath, &cTrans);
*pcTrans += cTrans;
pPath += cTrans;
break;
case SPTRANSWORD:
case SPTRANSWILDCARD:
pPath->hTransition = pTransEntry->ID;
memset(&pPath->elem, 0, sizeof(pPath->elem));
pPath->elem.bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
pPath++;
(*pcTrans)++;
break;
case SPTRANSTEXTBUF:
hr = WalkTextBuffer(pTransEntry->pvGrammarCookie, pPath, pTransEntry->ID, &cTrans);
*pcTrans += cTrans;
pPath += cTrans;
break;
case SPTRANSDICTATION:
pPath->hTransition = pTransEntry->ID;
memset(&pPath->elem, 0, sizeof(pPath->elem));
pPath->elem.bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
size_t cDictWord = wcslen(DICT_WORD);
WCHAR *pszWord = new WCHAR[cDictWord + 1];
wcscpy_s(pszWord, cDictWord + 1, DICT_WORD);
pPath->elem.pszDisplayText = pszWord;
pPath++;
(*pcTrans)++;
break;
}

hState = pTransEntry->hNextState;
}
}
return hr;
}

STDMETHODIMP CSrEngine::GetInputAudioFormat(const GUID * pSourceFormatId, const WAVEFORMATEX * pSourceWaveFormatEx,
GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWFEX)
{

ppCoMemDesiredWFEX);
}

STDMETHODIMP CSrEngine::
SetPropertyNum( SPPROPSRC eSrc, PVOID pvSrcObj, const WCHAR* pName, LONG lValue )
{

HRESULT hr = S_OK;

hr = S_FALSE;

return hr;
}

STDMETHODIMP CSrEngine::
GetPropertyNum( SPPROPSRC eSrc, PVOID pvSrcObj, const WCHAR* pName, LONG * plValue )
{

HRESULT hr = S_OK;

hr = S_FALSE;
*plValue = 0;

return hr;
}

STDMETHODIMP CSrEngine::
SetPropertyString( SPPROPSRC eSrc, PVOID pvSrcObj, const WCHAR* pName, const WCHAR* pValue )
{

HRESULT hr = S_OK;

hr = S_FALSE;

return hr;
}

STDMETHODIMP CSrEngine::
GetPropertyString( SPPROPSRC eSrc, PVOID pvSrcObj, const WCHAR* pName, __deref_out_opt WCHAR** ppCoMemValue )
{

HRESULT hr = S_OK;

hr = S_FALSE;
*ppCoMemValue = NULL;

return hr;
}

STDMETHODIMP CSrEngine::PrivateCall(void * pvEngineContext, void * pCallFrame, ULONG ulCallFrameSize)
{

return S_OK;
}

STDMETHODIMP CSrEngine::PrivateCallEx(void * pvEngineContext, const void * pInCallFrame, ULONG ulCallFrameSize,
void ** ppvCoMemResponse, ULONG * pcbResponse)
{

HRESULT hr = S_OK;

*ppvCoMemResponse = NULL;
*pcbResponse = 0;

return hr;
}

STDMETHODIMP CSrEngine::PrivateCallImmediate(
void *pvEngineContext,
const void *pInCallFrame,
ULONG ulInCallFrameSize,
void **ppvCoMemResponse,
ULONG *pulResponseSize)
{
*ppvCoMemResponse = NULL;
*pulResponseSize = 0;

return S_OK;
}

STDMETHODIMP CSrEngine::SetAdaptationData2(
void *pvEngineContext,
__in_ecount(cch) const WCHAR *pAdaptationData,
const ULONG cch,
LPCWSTR pTopicName,
SPADAPTATIONSETTINGS eSettings,
SPADAPTATIONRELEVANCE eRelevance)
{
return S_OK;
}

STDMETHODIMP CSrEngine::SetGrammarPrefix(
void *pvEngineGrammar,
__in_opt LPCWSTR pszPrefix,
BOOL fIsPrefixRequired)
{
return S_OK;
}

STDMETHODIMP CSrEngine::SetRulePriority(
SPRULEHANDLE hRule,
void *pvClientRuleContext,
int nRulePriority)
{
return S_OK;
}

STDMETHODIMP CSrEngine::EmulateRecognition(
ISpPhrase *pPhrase,
DWORD dwCompareFlags)
{
// Let SAPI do its own emulation.
return E_NOTIMPL;
}

STDMETHODIMP CSrEngine::SetSLMWeight(
void *pvEngineGrammar,
float flWeight)
{
return S_OK;
}

STDMETHODIMP CSrEngine::SetRuleWeight(
SPRULEHANDLE hRule,
void *pvClientRuleContext,
float flWeight)
{
return S_OK;
}

STDMETHODIMP CSrEngine::SetTrainingState(
BOOL fDoingTraining,
BOOL fAdaptFromTrainingData)
{
return S_OK;
}

STDMETHODIMP CSrEngine::ResetAcousticModelAdaptation( void)
{
return S_OK;
}

STDMETHODIMP CSrEngine::OnLoadCFG(
void *pvEngineGrammar,
const SPBINARYGRAMMAR *pGrammarData,
ULONG ulGrammarID)
{
return S_OK;
}

STDMETHODIMP CSrEngine::OnUnloadCFG(
void *pvEngineGrammar,
ULONG ulGrammarID)
{
return S_OK;
}

/******************************************************************************
* srengext.cpp

*此文件包含执行CSampleSRExtension级。
*这实现了自定义接口ISampleSRExtension 。
*当一个应用程序启这一从reco方面, SAPI的将
*寻找ExtensionCLSID领域中的引擎对象的原因,并
*创建该对象,然后齐界面的要求。

******************************************************************************/

#include "stdafx.h"
#include "srengext.h"

STDMETHODIMP CSampleSRExtension::ExamplePrivateEngineCall(void)
{

static BYTE Data[4] = { 1, 2, 3, 4 };
HRESULT hr = S_OK;

CComPtr<ISpPrivateEngineCallEx> cpEngineCallEx;
OuterQueryInterface(IID_ISpPrivateEngineCallEx, (void **)&cpEngineCallEx);

if (cpEngineCallEx)
{
void *pCoMemOutFrame = NULL;
ULONG ulOutFrameSize;
hr = cpEngineCallEx->CallEngineSynchronize( (void*)Data, sp_countof(Data), &pCoMemOutFrame, &ulOutFrameSize );
::CoTaskMemFree( pCoMemOutFrame );
}
else
{

hr = m_pEngineCall->CallEngine( (void*)Data, sp_countof(Data) );
}

return hr;
}

STDMETHODIMP CSampleSRExtension::GetDisplayAlternates(
const SPDISPLAYPHRASE *pPhrase,
ULONG cRequestCount,
SPDISPLAYPHRASE **ppCoMemPhrases,
ULONG *pcPhrasesReturned)
{
HRESULT hr = S_OK;

memset(ppCoMemPhrases, 0, sizeof(*ppCoMemPhrases) * cRequestCount);

*pcPhrasesReturned = cRequestCount;

for (unsigned int p=0; p<*pcPhrasesReturned; p++)
{
size_t cbPhraseSize = sizeof(SPDISPLAYPHRASE);

cbPhraseSize += pPhrase->ulNumTokens * sizeof(SPDISPLAYTOKEN);

for (unsigned int t=0; t<pPhrase->ulNumTokens; t++)
{
if (pPhrase->pTokens[t].pszDisplay != NULL)
{
cbPhraseSize += (wcslen(pPhrase->pTokens[t].pszDisplay) + 1) * sizeof(WCHAR);
}

if (pPhrase->pTokens[t].pszLexical != NULL)
{
cbPhraseSize += (wcslen(pPhrase->pTokens[t].pszLexical) + 1) * sizeof(WCHAR);
}
}

// Allocate the memory
ppCoMemPhrases[p] = (SPDISPLAYPHRASE *)CoTaskMemAlloc(cbPhraseSize);
if (ppCoMemPhrases[p] == NULL)
{
hr = E_OUTOFMEMORY;
goto CleanUp;
}

SPDISPLAYPHRASE *pCoMemPhrase = ppCoMemPhrases[p];
pCoMemPhrase->ulNumTokens = pPhrase->ulNumTokens;

pCoMemPhrase->pTokens = (SPDISPLAYTOKEN *)(pCoMemPhrase + 1);

LPWSTR pStringTable = (LPWSTR)(pCoMemPhrase->pTokens + pCoMemPhrase->ulNumTokens);
LPWSTR pEndOfStringTable = (LPWSTR)(((BYTE*)pCoMemPhrase) + cbPhraseSize);

for (unsigned int t=0; t<pPhrase->ulNumTokens; t++)
{

pCoMemPhrase->pTokens[t].bDisplayAttributes = pPhrase->pTokens[t].bDisplayAttributes;

if (t == 0)
{
if (pPhrase->pTokens[t].pszDisplay != NULL)
{

pCoMemPhrase->pTokens[t].bDisplayAttributes |= SPAF_ONE_TRAILING_SPACE;
}
}
else
{

if (t<pPhrase->ulNumTokens-1)
{

pCoMemPhrase->pTokens[t].bDisplayAttributes |= SPAF_ONE_TRAILING_SPACE;
}
}

if (pPhrase->pTokens[t].pszDisplay != NULL)
{

size_t length = wcslen(pPhrase->pTokens[t].pszDisplay);

if (wcscpy_s(pStringTable, pEndOfStringTable - pStringTable, pPhrase->pTokens[t].pszDisplay))
{
hr = E_OUTOFMEMORY;
goto CleanUp;
}
pCoMemPhrase->pTokens[t].pszDisplay = pStringTable;

pStringTable += length + 1;
}
else
{
ppCoMemPhrases[p]->pTokens[t].pszDisplay = NULL;
}

if (pPhrase->pTokens[t].pszLexical != NULL)
{
size_t length = wcslen(pPhrase->pTokens[t].pszLexical);

if (wcscpy_s(pStringTable, pEndOfStringTable - pStringTable, pPhrase->pTokens[t].pszLexical))
{
hr = E_OUTOFMEMORY;
goto CleanUp;
}

pCoMemPhrase->pTokens[t].pszLexical = pStringTable;
pStringTable += length + 1;
}
else
{
ppCoMemPhrases[p]->pTokens[t].pszLexical = NULL;
}
}
}

CleanUp:
if (FAILED(hr))
{
for (unsigned int p=0; p<*pcPhrasesReturned; p++)
{
CoTaskMemFree(ppCoMemPhrases[p]);
ppCoMemPhrases[p] = NULL;
}

*pcPhrasesReturned = 0;
}

return hr;
}

STDMETHODIMP CSampleSRExtension::SetFullStopTrailSpace(ULONG ulTrailSpace)
{

return S_OK;
}

STDMETHODIMP CSampleSRExtension::Normalize(
LPCWSTR pszWord,
LPCWSTR pszLeftContext,
LPCWSTR pszRightContext,
WORD LangID,
SPNORMALIZATIONLIST *pNormalizationList)
{

pNormalizationList = NULL;

return S_NOTSUPPORTED;
}

STDMETHODIMP CSampleSRExtension::GetPronunciations(
LPCWSTR pszWord,
LPCWSTR pszLeftContext,
LPCWSTR pszRightContext,
WORD LangID,
SPWORDPRONUNCIATIONLIST *pEnginePronunciationList)
{

pEnginePronunciationList->ulSize = 0;
pEnginePronunciationList->pvBuffer = 0;
pEnginePronunciationList->pFirstWordPronunciation = 0;

return S_NOTSUPPORTED;
}

/******************************************************************************
* srengalt.h

*此文件包含执行CSrEngineAlternates级。
*这实现了接口ISpSRAlternates 。
*当一个应用程序要求GetAlternates或犯下的结果, SAPI的将
*寻找AlternatesCLSID领域中的引擎对象的原因,并
*创建此对象。
*然后,将在这里呼吁的方法,通过相关的结果信息。
*这包括任何序列数据的主要动力已返回
*结果让候补产生离线。

******************************************************************************/

#include "stdafx.h"
#include "srengalt.h"

STDMETHODIMP CSrEngineAlternates::GetAlternates(SPPHRASEALTREQUEST *pAltRequest,
SPPHRASEALT **ppAlts, ULONG *pcAlts)
{
HRESULT hr = S_OK;

*pcAlts = 1;
*ppAlts = (SPPHRASEALT *)::CoTaskMemAlloc(sizeof(SPPHRASEALT));

if( *ppAlts == NULL)
{
return E_OUTOFMEMORY;
}

(*ppAlts)[0].ulStartElementInParent = pAltRequest->ulStartElement;
(*ppAlts)[0].cElementsInParent = pAltRequest->cElements;
(*ppAlts)[0].cElementsInAlternate = pAltRequest->cElements;
(*ppAlts)[0].pvAltExtra = NULL;
(*ppAlts)[0].cbAltExtra = 0;

SPPHRASE phrase;
memset(&phrase, 0, sizeof(phrase));
phrase.cbSize = sizeof(phrase);

phrase.LangID = 1033;

WCHAR *pAlts = (WCHAR *) pAltRequest->pvResultExtra;
ULONG nAltChars = pAltRequest->cbResultExtra / sizeof(WCHAR);
ULONG nWord = 0;

ULONG i;
for(i = 0; i < nAltChars; i++)
{
if(iswspace(pAlts[i]) || pAlts[i] == ‘/0‘)
{
nWord++;
}
}

SPPHRASEELEMENT* pElements = (SPPHRASEELEMENT*)_malloca(sizeof(SPPHRASEELEMENT) * nWord);
memset(pElements, 0, sizeof(SPPHRASEELEMENT)*nWord);

ULONG cW = 0;
ULONG cWord = 0;
for(i = 0; i < nAltChars && cWord < nWord; i++)
{
if(iswspace(pAlts[i]) || pAlts[i] == ‘/0‘)
{
pElements[cWord].bDisplayAttributes = SPAF_ONE_TRAILING_SPACE;
WCHAR *pszWord = (WCHAR *)_malloca(sizeof(WCHAR) * (i - cW + 1));
wcsncpy_s(pszWord, i - cW + 1, &pAlts[cW], i - cW);
pszWord[i - cW] = ‘/0‘;
pElements[cWord].pszDisplayText = pszWord;

cW = i + 1;
cWord++;
}
}

phrase.Rule.ulCountOfElements = cWord;
phrase.pElements = pElements;

CComPtr<ISpPhraseBuilder> cpBuilder;
hr = cpBuilder.CoCreateInstance(CLSID_SpPhraseBuilder);
if(SUCCEEDED(hr))
{
hr = cpBuilder->InitFromPhrase(&phrase);
}
if(SUCCEEDED(hr))
{
(*ppAlts)[0].pPhrase = cpBuilder;
(*ppAlts)[0].pPhrase->AddRef();
}

CComPtr<ISampleSRExtension> m_cpExt;
hr = pAltRequest->pRecoContext->QueryInterface(&m_cpExt);
if(SUCCEEDED(hr))
{
hr = m_cpExt->ExamplePrivateEngineCall();
}

for(i = 0; i < cWord; i++)
{
_freea((void*)pElements[i].pszDisplayText);
}
_freea(pElements);

if (FAILED(hr))
{
::CoTaskMemFree(*ppAlts);
}

return hr;
}

STDMETHODIMP CSrEngineAlternates::Commit(SPPHRASEALTREQUEST *pAltRequest,
SPPHRASEALT *pAlt, void **ppvResultExtra, ULONG *pcbResultExtra)
{
return S_OK;
}

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

原文地址:https://www.cnblogs.com/wicnwicnwh/p/10164782.html

时间: 2024-10-05 11:04:53

基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音识别引擎(适用于windows 2的相关文章

Visual Studio 2008 + ObjectARX2012环境配置

经过好大一番周折,终于成功运行了第一个ARX程序,期间遇到了好多调试上错误. 需要下载ObjectARX  SDK和Visual Studio 2008(将近4个G) 在Autodesk官网下载ObjectARX2012 SDK,我的AutoCAD是2012版,ObjectARX程序是向后兼容(用ObjectARX2010写的ARX程序可以在AutcCAD2010及以后的版本运行,而不能在AutoCAD2010之前版本运行),ObjectARX 2012版分成了两个包下载,下载地址:http:/

基于Visual C++2010与windows SDK fo windows7开发windows7平台的tabletp

基于Visual C++2010与windows SDK fo windows7开发windows7平台的tabletpc应用(2)-汉字文档手写轨迹输入多语言识别 大家先看看流程与效果,然后我来讲解代码, 1.VS2010帅气的启动画面 2.VS2010的工程画面 3.程序最终生成画面 4.程序启动画面 5 程序运行画面 6.程序枚举所有的语言识别手写识别器 7 英文识别范例 8.韩文识别范例 9.中文识别范例 10.线条式文档 11.格子式样文档 12.书写向导模式 13.tablet pc

基于Visual C++2010与windows SDK fo windows7开发Windows 7的多点触摸特性应用

2008年5月28日,微软即将退休的精神领袖比尔·盖茨和首席执行官史蒂夫·鲍尔默共同在北圣地亚哥四季艾维亚拉洲际度假村举办的2008 D6 All Things数字化大会上向到场的嘉宾展示了windows7的测试版.     鲍尔默向记者打趣道:"今天只给你们看一丁点儿(just a snippet)哟!"然而就是那么一丁点儿,已经让世界为之惊艳! 盖茨和鲍尔默在D6 All Things数字化大会上重点展示的是多触点技术(multitouch technology),这是运行Wind

基于XP打造windows7的C++开发平台--vs2010+windows SDK for windows7

IT业是一个创造奇迹的行业,IT业也是一个年轻的行业,IT业更是一个不断更新的行业.在今年2009年,微软已经连续推出visual studio2010 beta1 与 visual studio2010 beta2 两个版本.在2010.2月就要推出正式版了,beta版本已经展示了visual studio2010的所有新特性与革新,自从visual studio 2002推出以来,visual studio 2002 -> 2003 ->2005 ->2008 ->2010,产

使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍

使用Visual Studio 2008创建你的第一个Windows Mobile程序介绍 Windows MobileMobileWindowsMicrosoftWinForm 介绍 Microsoft Visual Studio 2008 专业版或者更高版本提供了一个Windows Mobile程序开发环境,允许你使用本地代码(C / C++)或托管代码(C# / Visual Basic.NET)为Windows Mobile设备创建程序. 这篇文章将带你正确的安装Visual Studi

Visual C++ 2008 Express Edition开发SDK应用程序

1.   启动Visual C++ 许多从来没有编写过Windows应用程序的人可能会认为这是一件很费力的事情,但是选择正确的编程工具可以让我们的工作变得简单一些.在这里我们选择VC++2008,同时又采用开源的wxWidgets库来开发程序,这是非常强大的库,会使我们编写Windows程序更加简单.特别在跨平台设计也会更方便.朋友们得多花一些时间来学习Visual C++的基本知识,磨刀不误砍柴功. 从Windows的开始菜单中选择Microsoft Visual C++ 2008 Expre

Visual Studio 2008常见问题

1.asp.net在什么软件上运行?学习asp往往需要测试asp程序,电脑不能直接测试,需要装IIS才能运行,但装IIS要么需要安装盘,要么需要安装包,而且设置也很复搜索杂.这里给大学推荐两个替代IIS的工具.Nlife.rar和NetBox.rar测试方法把主程序放到需要测试的文件的目录中,双击程序就自动运行,这时就不用管它了.在浏览器中输入: http://localhost 或 http://127.0.0.1就会进入该目录中,点击文件就可测试.下载地址: Nlife.rar 下载地址 h

Kinect for Windows SDK v2.0 开发笔记 (十五) 手势帧

 (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,因为SDK未完成,不附上函数/方法/接口的超链接. 这次终于是新的东西了,是"手势帧",不过原名是"可视化手势构建器"(Visual Gesture Builder)帧,是 SDK 2.0自带的手势解决方案,不过,如果您觉得微软写得不可靠,甚至垃圾,您可以尝试自己写个,笔者在 提供的范例中,写了个简单的样子(几十行而已,不要期

[转]How do I run msbuild from the command line using Windows SDK 7.1?

本文转自:http://stackoverflow.com/questions/6319274/how-do-i-run-msbuild-from-the-command-line-using-windows-sdk-7-1 Q: I'm setting up .NET 4.0 support on our CI server. I've installed .NET 4.0, and the .NET tools from the Windows 7.1 SDK. On .NET 2.0 an