|
基于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,public CComCoClass,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,public CComCoClass,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的SAPIif(GetControllingUnknown() == dynamic_cast(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_WCECDrvGrammar(){}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,public CComCoClass,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 m_GrammarList;CSpBasicQueue m_ContextList;ULONG m_ulNextGrammarIndex;ULONG m_cActive;ULONGLONG m_ullStart;ULONGLONG m_ullEnd;BOOL m_bSoundStarted:1;BOOL m_bPhraseStarted:1;CComPtr m_cpSite;CComPtr m_cpDecoderThread;HANDLE m_hQueueHasRoom;CSpBasicQueue m_RuleList;CComPtr m_cpLexicon;CComPtr m_cpEngineObjectToken;CComPtr 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,public CComCoClass,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 #endif#include #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 #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_WCEextern "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}#elseextern "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}#endifSTDAPI 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"EXPORTSDllCanUnloadNow PRIVATEDllGetClassObject PRIVATEDllRegisterServer PRIVATEDllUnregisterServer 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"#endifstatic 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 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 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 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;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.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;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.hRule;pRuleEntry->m_fTopLevel = (pRules.Attributes & SPRAF_TopLevel);pRuleEntry->m_fActive = (pRules.Attributes & SPRAF_Active);m_RuleList.InsertHead(pRuleEntry);m_cpSite->SetRuleClientContext(pRules.hRule, (void *)pRuleEntry);}break;case SPCFGN_REMOVE:for (i = 0; i < cRules; i++){pRuleEntry = m_RuleList.Find(pRules.hRule);_ASSERT(pRuleEntry); // The rule must have been added before being removedm_RuleList.Remove(pRuleEntry);delete pRuleEntry;}break;case SPCFGN_ACTIVATE:for (i = 0; i < cRules; i++){pRuleEntry = m_RuleList.Find(pRules.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.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.hRule);_ASSERT(pRuleEntry);if (pRuleEntry != NULL){pRuleEntry->m_fTopLevel = (pRules.Attributes & SPRAF_TopLevel);pRuleEntry->m_fActive = (pRules.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 eventm_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.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.elem.pszDisplayText){delete const_cast(Path.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.pPhrase );SPPHRASE* pAltPhraseInfo = NULL;if( SUCCEEDED( hr ) ){hr = pResult->aPhraseAlts.pPhrase->GetPhrase( &pAltPhraseInfo );}if( SUCCEEDED( hr ) ){++pResult->ulNumAlts;pResult->aPhraseAlts.cElementsInParent = pPriPhraseInfo->Rule.ulCountOfElements;pResult->aPhraseAlts.cElementsInAlternate = pAltPhraseInfo->Rule.ulCountOfElements;static BYTE AltData[] = { 0xED, 0xED, 0xED, 0xED };pResult->aPhraseAlts.pvAltExtra = &AltData;pResult->aPhraseAlts.cbAltExtra = sp_countof( AltData );}if( pAltPhraseInfo ){::CoTaskMemFree( pAltPhraseInfo );}}}else{E_OUTOFMEMORY;}}// Cleanup main phrase informationif( pPriPhraseInfo ){::CoTaskMemFree( pPriPhraseInfo );}// Cleanup on failureif( FAILED( hr ) ){if( pResult->pPhrase ){pResult->pPhrase->Release();pResult->pPhrase = NULL;}for( ULONG i = 0; i < pResult->ulNumAlts; ++i ){pResult->aPhraseAlts.pPhrase->Release();pResult->aPhraseAlts.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 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 selectionULONG cchActiveChars = pGrammar->m_cchText - 2; //The default value with text selectionULONG 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 indexULONG nP = 0;for(cPhrase = pGrammar->m_pWordSequenceText + ulStartActiveOffset; nP != nPhrase; cPhrase++){if(*cPhrase == L'/0'){nP++;}}// Count words in sentenceULONG 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 wordnWord++;}}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 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; pulNumTokens * sizeof(SPDISPLAYTOKEN);for (unsigned int t=0; tulNumTokens; 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 memoryppCoMemPhrases[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; tulNumTokens; 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 (tulNumTokens-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; pulSize = 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) || pAlts == '/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) || pAlts == '/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 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 m_cpExt;hr = pAltRequest->pRecoContext->QueryInterface(&m_cpExt);if(SUCCEEDED(hr)){hr = m_cpExt->ExamplePrivateEngineCall();}for(i = 0; i < cWord; i++){_freea((void*)pElements.pszDisplayText);}_freea(pElements);if (FAILED(hr)){::CoTaskMemFree(*ppAlts);}return hr;}STDMETHODIMP CSrEngineAlternates::Commit(SPPHRASEALTREQUEST *pAltRequest,SPPHRASEALT *pAlt, void **ppvResultExtra, ULONG *pcbResultExtra){return S_OK;} |
|