スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【同じタグを付けた記事の一覧】

Windows の音声認識を C++ で(基礎編)

2013年07月01日(月)00時59分

JavaScript では…

最近、Windows の音声合成で英語の発音練習をしてみる、というようなことをやっています(タグ:英語発音矯正実験)。
そのために、JScript(JavaScript)で練習用のサポートスクリプトなどをいくつか作っているのですが、これは簡単で手軽ではあるものの、どうにも細かいところで、微妙に「かゆいところに手が届かない」的なものを感じるときがあります。
そこで、面倒は増えるものの、細かい制御が可能な C++ での音声認識にも手を出してみることにしました。
で、今回の内容は、そのメモです。
これは、以前に「Windows の音声認識を JavaScript で(基礎編)」等を書きましたが、その C++ 版となる予定です。
前回同様、何回か続いた場合には「音声認識」タグが目次代わりとなりますので、他のネタを見たいというときには、「音声認識」をクリックしていただけますと、一覧していただけるかと思います。

Windows の音声認識

Windows では Vista 以降は標準で日本語音声認識が使用できます(日本語版 OS でないと標準では日本語認識エンジンが入っていませんが)。
WinXP 以前でも Speech SDK 5.1 のページにある「SpeechSDK51.exe」と「SpeechSDK51LangPack.exe」をインストールすることで、無償で日本語の音声認識が使えるようになります。
これら標準(または準標準)の音声システムは、SAPI5(Speech Application Program Interface ver.5)と呼ばれており、WinXP 以前で使用できるのは SAPI5.1、Vista 以降標準で入っているのは SAPI5.3、と細かいバージョンは微妙に違いますが、基本的な機能しか使用しない限りでは、その違いを意識する必要はないと思います。
また、その SAPI5 の後継(とも言い切れないのですが)として、Microsoft Speech Platform(以下 MSSP)というものもリリースされており、これを使うことでも、音声認識を利用可能です。
この MSSP は、内部的にはほぼ SAPI5 と同じで、使い方も全く変わりません。

MSSP の音声認識

SAPI5 の音声認識で使用できる言語は、SAPI5.1 では「英語」「中国語」「日本語」の三か国語分、SAPI5.3 では「日本語版 Win7 で英語音声認識機能を使う」のような作業をすれば「スペイン語」「ドイツ語」「フランス語」「英語」「中国語」「日本語」の六か国語分となります(自分は未所有なため未確認ですが Win8 には韓国語もあるっぼい?)。
これが MSSP では、言語パックのダウンロードサイトを見る限り、「カタロニア語」「デンマーク語」「ドイツ語」「英語」「スペイン語」「フィンランド語」「フランス語」「イタリア語」「日本語」「韓国語」「ノルウェー語」「オランダ語」「ポーランド語」「ポルトガル語」「ロシア語」「スウェーデン語」「中国語」と、実に十七か国語分の認識エンジンが用意されています。
となると、「使うなら断然 MSSP でしょう!」といいたいところなのですが、残念ながら、MSSP 用の音声認識エンジンは、今のところ、自由に話した内容を文字列化する「口述筆記」モードが使えず、あらかじめ登録した単語(文章)のどれが一番近いか?を認識する「コマンド認識」モードのみのようです(多分)。
これはおそらく、MSSP はもともと電話応答システムを念頭に開発されたもののようで、その目的のためには「コマンド認識」モードのみで十分、という判断だったのではないかと思います。
また、Kinect の開発キットにも MSSP が含まれているようですが、「電話応答システム」に「ゲーム用途」が加わったところで、「コマンド認識」モードがあれば問題なし、という方向性に変わりはないかもしれません。

「sapi.h」と「sphelper.h」

概要の話が終わったところで、開発の話に入ります。
SAPI5 または MSSP 対応のアプリケーションを C++ で作成するにあたって、必須であるのは「sapi.h」のみです。
「sphelper.h」は「使える環境であれば」使うと楽になりますが、無くても「開発できない」というようなものではありません。
この二つのファイルは、前述の「SpeechSDK51.exe」(SAPI5 用)や、あるいは「MicrosoftSpeechPlatformSDK.msi」(MSSP 用)をインストールすることで、手に入ります。
が、自分の場合、単にこの二つ(「sapi.h」「sphelper.h」)のみ入手できればそれでよかったので、わざわざ SDK をインストールせず、インストーラをバラして、中身だけ抜き取りました(「Microsoft Speech Platform SDK のインストールとエラー」参照)。
で、SAPI5 用と MSSP 用のどちらの「sapi.h」を使えばいいのか?という話ですが、単純な認識等基本的な機能しか使わないのであれば、どちらでも同じです。
ただ、MSSP 用の方が新しいため、こちらには SAPI5.3 以降で追加された関数の定義等が含まれており、そういうものを使うのであれば MSSP 用の SDK から抜き取ってきます。
ただし当然、そういう機能を使えば WinXP では実行できなくなるはずですので、対応 OS に注意する必要があります。

「sphelper.h」と「atlbase.h」

上記「sphelper.h」の説明で、「使える環境であれば」と書きました。
というのも、この「sphelper.h」は「atlbase.h」を使っており、この「atlbase.h」というのは ATL の一部で、その ATL というのは、開発環境「Visual C++」の無料版である「Express」系には含まれていないのです。
つまり、Visual Studio Express を使用している場合、「sphelper.h」は使えません。
まあ、いろいろやって「Express」系で ATL を使えるようにする…、という手もなくはないのですが、「sphelper.h」内で必要になるヘルパー関数群は、大体が本来ソースコード本文でやるべき定型作業をまとめたマクロのようなものです。
またその処理内容もヘッダファイル中に直書きされてますので、SDK のヘルプファイルなどに記述されたサンプルソース内に、ここで定義されているヘルパー関数が使用されているのであれば、その関数の内容を読み、必要な処理を ATL 無し版に修正移植することで、「sphelper.h」を使わなくとも済みます(面倒ですが)。
なお、「ATL を使っている」といっても、おそらく「CComPtr」を使うのが主目的ではないかと思いますので、これに気を付けていれば移植もそれほど手間はかからないと思います(「CComPtr」は COM コンポーネント自動解放用のスマートポインタです)。

サンプル

まだあといろいろと書こうかと思ったのですが、ソース内にかなりのコメントをつけてありますので、それで代用することにします。
サンプルの内容は、まずシステムで使用可能な音声認識エンジン名と音声入力デバイス名を列挙し、日本語認識エンジンと標準入力デバイスに設定し、あとはひたすら認識結果を表示し続けるコンソールプログラムです。
「終了」という文字列を含む認識結果がくると終了します(つまりマイクに向かって「終了」といえばプログラムが終了するということです)。
以下に SyntaxHighlighter によるソースコードを掲載します。
ソースコード部分でダブルクリックすると、全選択されますのでコピーしやすくなりますが、それとは別に TEXT ファイルとしてもアップロードしておきます(→「DictCPP00.txt」)。

//WindowsのSAPI5またはMicrosoft Speech PlatformとC++で音声認識を使用するサンプル。
//
//■サンプルの動作内容は以下の通り。
//1.認識エンジン名の一覧を表示し日本語認識エンジンを設定。
//2.入力デバイス名の一覧を表示し標準入力デバイスを設定。
//3.音声入力を永久ループで待ち受け、認識文を表示し続ける(非コールバック)。
//4.「終了」という文字を含む文字列が来ればループを打ち切り終了。
//
//■その他雑記。
//・開発環境は「Win7x64」と「VC++2010」。
//・「Win32 コンソール アプリケーション」。
//・Unicode文字セット(SAPI5の関数群はUnicodeを使用するためマルチバイト文字セットを使う場合は変換が必要になる)。
//・「sapi.h」をプロジェクトに含める必要がある。
//・サンプルであるためSAPI5関数群の戻り値hResultのチェックとエラー処理は省略している。
//
//http://denspe.blog84.fc2.com/blog-entry-190.html

//古い形式の関数の使用警告を表示しないプラグマ。
#pragma warning(disable:4996)

#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <locale.h>

#include "sapi.h"

//開始時にCoInitialize、終了時にCoUninitializeするだけのクラス。
//COMコンポーネントを使用するアプリケーションの最初で実体を確保しておくことで、終了時にCoUninitializeを不要にする。
//CComPtr等の自動解放系システムの使用時には、システムが各COMコンポーネントを自動解放した後に
//CoUninitializeが実行されるようにしなければならないため、スコープを分ける必要がある。
class CAutoCoInitialize
{
public:
	HRESULT hResult;
	//コンストラクタ。
	CAutoCoInitialize():hResult(S_FALSE){hResult=CoInitialize(NULL);}
	//デストラクタ。
	~CAutoCoInitialize(){CoUninitialize();hResult=S_FALSE;}
} AutoCoInitialize;

//COMオブジェクトの自動解放をカプセル化したもの。
//atlbase.hにあるCComQIPtrの劣化版。atlbase.hを使用しないため似たものを自作。
template <class T> class AutoCom
{
public:
	//実装していない機能は実体をそのまま使う。
	T *pCom;

	//標準のコンストラクタ。
	AutoCom(void):pCom(NULL){}
	//初期化用コンストラクタ(コピー・コンストラクタ呼び出し)。
	AutoCom(T *pSrcCom):pCom(NULL){operator=(pSrcCom);}
	//デストラクタ。
	~AutoCom(void){if(pCom){pCom->Release();pCom=NULL;}}

	//////////////////////
	//有効・無効の確認。//
	//////////////////////
	bool IsAvailable(void){return pCom?true:false;}
	bool IsNull(void){return pCom?false:true;}

	///////////////////////////////////////////////////
	//COMポインタと同等に扱えるようにするための定義。//
	///////////////////////////////////////////////////
	operator T*(void){return pCom;}
	operator T**(void){return &pCom;}
	operator T&(void){return *pCom;}
	T& operator*(void){return *pCom;}
	T** operator&(void){if(pCom){pCom->Release();pCom=NULL;}return &pCom;}
	T* operator->(void){return pCom;}
	T* operator=(T *pSrcCom){if(pSrcCom==pCom)return pCom;if(pCom)pCom->Release();pCom=pSrcCom;return pCom;}

	////////////////////////////
	//その他作業用関数の定義。//
	////////////////////////////
	//COMオブジェクト生成。
	HRESULT Create(GUID ClsID,GUID IID=__uuidof(T))
	{
		if(pCom){pCom->Release();pCom=NULL;}
		HRESULT hResult=CoCreateInstance(ClsID,NULL,CLSCTX_ALL,IID,(LPVOID *)&pCom);
		if(FAILED(hResult))pCom=NULL;
		return hResult;
	}
};

//メイン関数。
int _tmain(int argc,TCHAR* argv[])
{
	//日本語の表示に必要な処理。
	_tsetlocale(LC_ALL,_T(""));
	//SAPI5関連の戻り値を受ける。
	//今回のサンプルではただ受けるだけで内容は無視しているが本来はエラー処理等を行う必要がある。
	HRESULT	hResult=S_OK;
	
	/////////////////////////
	//ISpRecognizerの生成。//
	/////////////////////////
	//ISpRecognizerは認識エンジンを管理するオブジェクト。
	AutoCom<ISpRecognizer> acRecognizer;
	acRecognizer.Create(CLSID_SpInprocRecognizer);
	
	//////////////////////////////////
	//認識エンジンの一覧表示と設定。//
	//////////////////////////////////
	//認識エンジンの変更は、CreateRecoContext後にはできなくなるため、ISpRecognizer生成直後に行う必要がある。
	if(acRecognizer.IsAvailable())
	{
		//認識エンジン一覧を管理するオブジェクトの生成。
		AutoCom<ISpObjectTokenCategory> acRecognizerCategory;
		acRecognizerCategory.Create(CLSID_SpObjectTokenCategory);
		//認識エンジン一覧記録位置の設定(上はMSSP11で下がSAPI5)。
		//hResult=acRecognizerCategory->SetId(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech Server\\v11.0\\Recognizers",TRUE);
		hResult=acRecognizerCategory->SetId(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Recognizers",TRUE);
		//認識エンジン一覧を格納するオブジェクト。
		AutoCom<IEnumSpObjectTokens> acRecognizerTokens;
		//認識エンジン一覧の取得。
		hResult=acRecognizerCategory->EnumTokens(NULL,NULL,&acRecognizerTokens);
		//標準認識エンジンIDの取得。
		WCHAR *pDefaultRecognizerId=NULL;
		if(FAILED(acRecognizerCategory->GetDefaultTokenId(&pDefaultRecognizerId)))pDefaultRecognizerId=NULL;

		//認識エンジンの一覧表示と設定。
		wprintf(L"【認識エンジン一覧】\n");
		while(true)
		{
			//特定の認識エンジンを格納するオブジェクト。
			AutoCom<ISpObjectToken> acRecognizerToken;
			//以下で先頭から末尾までを走査できる。
			if(FAILED(acRecognizerTokens->Next(1,&acRecognizerToken,NULL))||acRecognizerToken.IsNull())break;

			//認識エンジンIDを取得し標準認識エンジンIDと比較する。
			WCHAR *pRecognizerId=NULL;
			bool IsDefaultRecognizer=false;
			if(SUCCEEDED(acRecognizerToken->GetId(&pRecognizerId)))
			{
				//標準認識エンジンIDと一致すれば標準マーク「*」をつける指示。
				if(pDefaultRecognizerId&&wcscmp(pRecognizerId,pDefaultRecognizerId)==0)IsDefaultRecognizer=true;
				//取得した文字列は解放する必要がある。
				CoTaskMemFree(pRecognizerId);pRecognizerId=NULL;
			}

			//認識エンジン名の表示と設定。
			WCHAR *pRecognizerName=NULL;
			//GetStringValue関数を必要な情報名を与えずに呼び出すと、標準値(ここでは認識エンジン名)が返る。
			if(SUCCEEDED(acRecognizerToken->GetStringValue(NULL,&pRecognizerName)))
			{
				//標準認識エンジンであれば表示名の頭に「*」をつける。
				if(IsDefaultRecognizer)
					wprintf(L"*%s\n",pRecognizerName);
				else
					wprintf(L" %s\n",pRecognizerName);

				//言語IDが411(日本語)の場合はその認識エンジンに設定。
				BOOL IsMatches=FALSE;
				hResult=acRecognizerToken->MatchesAttributes(L"language=411",&IsMatches);
				if(IsMatches==TRUE)hResult=acRecognizer->SetRecognizer(acRecognizerToken);
				//取得した文字列は解放する必要がある。
				CoTaskMemFree(pRecognizerName);pRecognizerName=NULL;
			}
		}
		
		//認識エンジンを取得することで正しく設定されたか確認。
		AutoCom<ISpObjectToken> acCurrentRecognizerToken;
		WCHAR *pCurrentRecognizerName=NULL;
		if(SUCCEEDED(acRecognizer->GetRecognizer(&acCurrentRecognizerToken)))
		{
			//取得に成功すれば設定された認識エンジン名を取得。
			//GetStringValue関数を必要な情報名を与えずに呼び出すと、標準値(ここでは認識エンジン名)が返る。
			hResult=acCurrentRecognizerToken->GetStringValue(NULL,&pCurrentRecognizerName);
		}
		else if(pDefaultRecognizerId)
		{
			//取得に失敗した(認識エンジンが設定されていない)場合は標準認識エンジンを設定。
			acCurrentRecognizerToken.Create(CLSID_SpObjectToken);
			//標準認識エンジンを取得。
			acCurrentRecognizerToken->SetId(NULL,pDefaultRecognizerId,FALSE);
			//取得した標準認識エンジンを認識エンジンとして設定し認識エンジン名を取得。
			if(SUCCEEDED(acRecognizer->SetRecognizer(acCurrentRecognizerToken)))hResult=acCurrentRecognizerToken->GetStringValue(NULL,&pCurrentRecognizerName);
		}

		//使用する認識エンジン名の表示。
		if(pCurrentRecognizerName)
		{
			wprintf(L"※%sを使用。\n\n",pCurrentRecognizerName);
			//取得した文字列は解放する必要がある。
			CoTaskMemFree(pCurrentRecognizerName);pCurrentRecognizerName=NULL;
		}
		else
		{
			//使用する認識エンジン名が設定されていない場合は非表示でカラ改行。
			wprintf(L"\n");
		}

		//取得した文字列は解放する必要がある。
		if(pDefaultRecognizerId){CoTaskMemFree(pDefaultRecognizerId);pDefaultRecognizerId=NULL;}
	}

	//////////////////////////////////
	//入力デバイスの一覧表示と設定。//
	//////////////////////////////////
	//InProc(非共有)タイプの音声認識システムは標準では入力デバイスが未設定であるため、必ず何かを設定する必要がある。
	if(acRecognizer.IsAvailable())
	{
		//入力デバイス一覧を管理するオブジェクトの生成。
		AutoCom<ISpObjectTokenCategory> acAudioInputCategory;
		acAudioInputCategory.Create(CLSID_SpObjectTokenCategory);
		//入力デバイス一覧記録位置の設定(上はMSSP11で下がSAPI5)。
		//hResult=acAudioInputCategory->SetId(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech Server\\v11.0\\AudioInput",TRUE);
		hResult=acAudioInputCategory->SetId(L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\AudioInput",TRUE);
		//入力デバイス一覧を格納するオブジェクト。
		AutoCom<IEnumSpObjectTokens> acAudioInputTokens;
		//入力デバイス一覧の取得。
		hResult=acAudioInputCategory->EnumTokens(NULL,NULL,&acAudioInputTokens);
		//標準入力デバイスIDの取得。
		WCHAR *pDefaultAudioInputId=NULL;
		if(FAILED(acAudioInputCategory->GetDefaultTokenId(&pDefaultAudioInputId)))pDefaultAudioInputId=NULL;

		//入力デバイスの一覧表示と設定。
		wprintf(L"【入力デバイス一覧】\n");
		while(true)
		{
			//特定の入力デバイスを格納するオブジェクト。
			AutoCom<ISpObjectToken> acAudioInputToken;
			//以下で先頭から末尾までを走査できる。
			if(FAILED(acAudioInputTokens->Next(1,&acAudioInputToken,NULL))||acAudioInputToken.IsNull())break;
			
			//入力デバイスIDを取得し標準入力デバイスIDと比較する。
			WCHAR *pAudioInputId=NULL;
			bool IsDefaultAudioInput=false;
			if(SUCCEEDED(acAudioInputToken->GetId(&pAudioInputId)))
			{
				//標準入力デバイスIDと一致すれば標準マーク「*」をつける指示。
				if(pDefaultAudioInputId&&wcscmp(pAudioInputId,pDefaultAudioInputId)==0)IsDefaultAudioInput=true;
				//取得した文字列は解放する必要がある。
				CoTaskMemFree(pAudioInputId);pAudioInputId=NULL;
			}

			//入力デバイス名の表示と設定。
			WCHAR *pAudioInputName=NULL;
			//GetStringValue関数を必要な情報名を与えずに呼び出すと、標準値(ここでは入力デバイス名)が返る。
			if(SUCCEEDED(acAudioInputToken->GetStringValue(NULL,&pAudioInputName)))
			{
				//標準入力デバイスであれば表示名の頭に「*」をつける。
				if(IsDefaultAudioInput)
				{
					//標準入力デバイスであれば表示名の頭に「*」をつける。
					wprintf(L"*%s\n",pAudioInputName);
					//標準入力デバイスであればその入力デバイスに設定。
					hResult=acRecognizer->SetInput(acAudioInputToken,TRUE);
				}
				else
				{
					//標準入力デバイスでなければ表示名の頭には半角スペースを置く。
					wprintf(L" %s\n",pAudioInputName);
				}
				
				//取得した文字列は解放する必要がある。
				CoTaskMemFree(pAudioInputName);pAudioInputName=NULL;
			}
		}
		
		//入力デバイスを取得することで正しく設定されたか確認。
		AutoCom<ISpObjectToken> acCurrentAudioInputToken;
		WCHAR *pCurrentAudioInputName=NULL;
		if(SUCCEEDED(acRecognizer->GetInputObjectToken(&acCurrentAudioInputToken)))
		{
			//取得に成功すれば設定された入力デバイス名を取得。
			//GetStringValue関数を必要な情報名を与えずに呼び出すと、標準値(ここでは入力デバイス名)が返る。
			hResult=acCurrentAudioInputToken->GetStringValue(NULL,&pCurrentAudioInputName);
		}
		else if(pDefaultAudioInputId)
		{
			//取得に失敗した(入力デバイスが設定されていない)場合は標準入力デバイスを設定。
			acCurrentAudioInputToken.Create(CLSID_SpObjectToken);
			//標準入力デバイスを取得。
			acCurrentAudioInputToken->SetId(NULL,pDefaultAudioInputId,FALSE);
			//取得した標準入力デバイスを入力デバイスとして設定し入力デバイス名を取得。
			if(SUCCEEDED(acRecognizer->SetInput(acCurrentAudioInputToken,TRUE)))hResult=acCurrentAudioInputToken->GetStringValue(NULL,&pCurrentAudioInputName);
		}

		//使用する入力デバイス名の表示。
		if(pCurrentAudioInputName)
		{
			wprintf(L"※%sを使用。\n\n",pCurrentAudioInputName);
			//取得した文字列は解放する必要がある。
			CoTaskMemFree(pCurrentAudioInputName);pCurrentAudioInputName=NULL;
		}
		else
		{
			//使用する入力デバイス名が設定されていない場合は非表示でカラ改行。
			wprintf(L"\n");
		}

		//取得した文字列は解放する必要がある。
		if(pDefaultAudioInputId){CoTaskMemFree(pDefaultAudioInputId);pDefaultAudioInputId=NULL;}
	}
	
	////////////////////////////////
	//ISpRecoContextの生成と設定。//
	////////////////////////////////
	//ISpRecoContextは音声認識管理用オブジェクト。
	//認識エンジン管理オブジェクトISpRecognizeや後述の文法管理オブジェクトISpRecoGrammarを統括し
	//音声認識利用者はこのISpRecoContextオブジェクトを通して認識結果を取得する。
	//認識エンジン管理オブジェクトISpRecognizeと密接に結びついており、このオブジェクトが単体で存在することはない。
	//このオブジェクトを直接生成した場合には内部で標準の認識エンジンを管理するISpRecognizeが生成される。
	//また、一度このオブジェクトが生成されると、
	//それが持つISpRecognizeが管理する認識エンジンやISpRecognize自体を差し替えることはできなくなるため、
	//認識言語(エンジン)を変更する際にはこのオブジェクトも作り直す必要がある。
	AutoCom<ISpRecoContext> acRecoContext;
	acRecognizer->CreateRecoContext(&acRecoContext);
	//認識イベント発生まで待機するための関数「WaitForNotifyEvent()」を使用するための準備。
	//なぜかコメントアウトしても問題なく動作したが一応やっておく。
	hResult=acRecoContext->SetNotifyWin32Event();
	//どのイベントが発生した場合に通知させるかを設定。「SPEI_RECOGNITION」は認識完了時。
	hResult=acRecoContext->SetInterest(SPFEI(SPEI_RECOGNITION),SPFEI(SPEI_RECOGNITION));
	
	////////////////////////////////
	//ISpRecoGrammarの生成と設定。//
	////////////////////////////////
	//ISpRecoGrammarは音声認識文法管理用オブジェクト。
	//あらかじめ登録した単語(文章)のどれが一番近いか?を認識する「コマンド認識」モードの場合は
	//ここでこのオブジェクトに対してコマンドの登録などを行う。
	//自由に話した内容を文字列化する「口述筆記」モード使用時には特にやることはない。
	AutoCom<ISpRecoGrammar> acRecoGrammar;
	acRecoContext->CreateGrammar(NULL,&acRecoGrammar);
	//辞書の読み込み。読み込み対象無指定(NULL)で一般的な辞書(「口述筆記」モード用の辞書)が読み込まれる。
	hResult=acRecoGrammar->LoadDictation(NULL,SPLO_STATIC);
	//読み込んだ辞書の活動を開始させる。これは実質的には認識処理開始の合図となる。
	hResult=acRecoGrammar->SetDictationState(SPRS_ACTIVE);

	////////////////////
	//イベントの処理。//
	////////////////////
	//永久ループでイベント発生を待受け続け、日本語で「終了」の文字が含まれる文が来るまで認識結果を表示し続ける。
	bool IsLoop=true;
	while(IsLoop)
	{
		//イベント発生まで待機。
		hResult=acRecoContext->WaitForNotifyEvent(INFINITE);
		//イベントが発生すれば発生したイベントを取得。
		SPEVENT SpEvent;memset(&SpEvent,0,sizeof(SPEVENT));
		hResult=acRecoContext->GetEvents(1,&SpEvent,NULL);

		//発生したイベントの種類を確認し必要な処理を実行する。
		switch(SpEvent.eEventId)
		{
		case SPEI_RECOGNITION:
			//「SpEvent.elParamType」が「SPET_LPARAM_IS_OBJECT」のとき「SpEvent.lParam」に結果オブジェクト(ISpRecoResult)が入っている。
			if(SpEvent.elParamType==SPET_LPARAM_IS_OBJECT)
			{
				//「SpEvent.lParam」を結果オブジェクトISpRecoResultとして扱う。
				ISpRecoResult* pResult=(ISpRecoResult *)SpEvent.lParam;
				//ISpRecoResultのGetText関数で認識結果を文字列で取得できる。
				WCHAR *pResultText=NULL;
				if(SUCCEEDED(pResult->GetText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE,TRUE,&pResultText,NULL)))
				{
					wprintf(L"%s\n",pResultText);
					//「終了」の文字が含まれればループ打ち切り。
					if(wcsstr(pResultText,L"終了"))IsLoop=false;
					//取得した文字列は解放する必要がある。
					CoTaskMemFree(pResultText);pResultText=NULL;
				}
			}
			break;
		default:
			break;
		}

		//イベント通知のためにSAPI5側が内部で動的確保した各種情報は受け取り側の責任で解放する必要がある。
		//これは「sphelper.h」内で定義されているヘルパー関数SpClearEventで行えるが
		//「sphelper.h」はATLがない環境では使用できないため、必要な処理を手作業で移植する。
		//以下「sphelper.h」のSpClearEvent関数の内容を移植。
		if(SpEvent.elParamType!=SPEI_UNDEFINED)
		{
			if(SpEvent.elParamType==SPET_LPARAM_IS_POINTER||SpEvent.elParamType==SPET_LPARAM_IS_STRING)
				CoTaskMemFree((void *)SpEvent.lParam);
			else if(SpEvent.elParamType==SPET_LPARAM_IS_TOKEN||SpEvent.elParamType==SPET_LPARAM_IS_OBJECT)
				((IUnknown*)SpEvent.lParam)->Release();
		}
		memset(&SpEvent,0,sizeof(SPEVENT));
		//以上「sphelper.h」のSpClearEvent関数の内容を移植。
	}

	//////////
	//終了。//
	//////////
	//認識結果に「終了」の文字が含まれていれば認識ループが打ち切られてここに来る。
	return EXIT_SUCCESS;
}
関連記事

【同じタグを付けた記事の一覧】
ソースコード プログラミング C++ Windows 音声技術 音声認識

スポンサーサイト

コメントの投稿

非公開コメント

最新記事
最新コメント
Amazonおまかせリンク
カテゴリ
タグクラウド
Amazonお買い得ウィジェット
カレンダー
03 | 2017/04 | 05
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 - - - - - -
月別アーカイブ
プロフィール

電脳太助

Author:電脳太助
Website:電脳スピーチ web

RSSリンクの表示
メールフォーム

名前:
メール:
件名:
本文:

サイト内検索
Ads by Google
FC2アクセスランキング
Ads by Google
FC2拍手ランキング
ユーザータグ

音楽管理(65)
ポータブル(57)
ソフト紹介(44)
プログラミング(42)
音声技術(41)
自作ソフト(34)
サイト運営(32)
FC2(31)
ブログ(30)
iTunes(26)
Windows(25)
LISMO(24)
音声合成(23)
音声認識(22)
x-アプリ(22)
電子ブック(22)
eラーニング(20)
バックアップ(19)
語学学習(19)
foobar2000(18)
ソースコード(17)
画像管理(15)
WindowsLiveWriter(15)
C++(14)
アフィリエイト(10)
DnspTools(10)
ウォークマン(9)
fi-6130(9)
FLAC(9)
Gracenote(8)
英語音読学習計画(8)
Prolog(8)
JavaScript(8)
ベクター(8)
雑記(8)
CodeBlocks(7)
SyntaxHighlighter(7)
TraConv(7)
wxWidgets(7)
spcbght(7)
DCP-J552N(6)
W63CA(6)
MP3Gain(6)
WinRT(6)
iGoinLM(6)
VirtualBox(6)
WindowsLiveMesh(6)
英語発音矯正実験(6)
ExactAudioCopy(6)
楽器演奏(5)
Mery(5)
LAME(5)
音楽技術(5)
GalateaProject(4)
LLVM(4)
nLite(4)
MIDI(4)
ホームページ(4)
WindowsLiveSkyDrive(4)
GalateaTalk(4)
PC-98(3)
カウンター(3)
AACGain(3)
iTCDini(3)
OverCutChecker(3)
拍手(3)
PK-513L(3)
UniversalExtractor(3)
アクセスランキング(3)
ImageCompositeEditor(2)
アクセス解析(2)
OCR(2)
qtaacenc(2)
資格試験(1)
AquesTalk(1)
AquesCmdDl(1)

FC2アクセスランキング
最新トラックバック
アクセスランキング
[ジャンルランキング]
コンピュータ
102位
アクセスランキングを見る>>

[サブジャンルランキング]
ソフトウェア
10位
アクセスランキングを見る>>
FC2カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。