基于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