Managed SAPI - .NET対応 SAPIライブラリ

SAPI (Speech API) を、C#C++/CLIといった.NET言語から使用できるようにするためのライブラリのコードです。


ライブラリのテストプログラムの実行イメージ

ダウンロード

ライブラリとテストプログラム (Visual Studio 2008)

managed-sapi.zip

コード解説

C++ コード部

音声処理を行うクラスです。

SpeechEngine.h

// SpeechEngine.h

#pragma once
#pragma warning(disable : 4996) // 古い関数の使用に対する警告を抑制する

#include <sphelper.h>

#define WM_REC_EVENT   WM_USER + 0  // 認識メッセージ
#define WORD_MAX_SIZE  0xFF         // 認識結果の語の最大サイズ

namespace SAPI
{
    // 音声エンジン
    class SpeechEngine
    {
    // Construction --------------------------------------------------------
    public:
        SpeechEngine();
        ~SpeechEngine();

    // Operation -----------------------------------------------------------
    public:
        void Init( HWND hWnd, const wchar_t* grammarFile );

        int GetRecognitionEvent();

        BOOL GetRecognitionResult( wchar_t* text );
        BOOL GetRecognizedPronunciation( wchar_t* text );

        BOOL GetConfidence( double& value );
        const wchar_t* GetState( int eventID );

    private:
        void InitMicrophone( CComPtr< ISpRecognizer > &recognizer );
        void InitGrammar( wchar_t const* grammarFile );

    // Attribute ===========================================================
    private:
        CComPtr< ISpRecoContext > m_recoContext;    // 認識コンテキスト
        CComPtr< ISpRecoGrammar > m_recoGrammar;    // ディクテーション文法

        CSpEvent m_spEvent;     // SAPIイベント
    };
}

SpeechEngine.cpp

#include "stdafx.h"
#include "SpeechEngine.h"
#include "SapiException.h "

using namespace SAPI;


// コンストラクタ
SpeechEngine::SpeechEngine() :
    m_recoContext( NULL ),
    m_recoGrammar( NULL )
{
}

// デストラクタ
SpeechEngine::~SpeechEngine()
{
    if( m_recoContext != NULL )
    {
        // 認識コンテキストを解放する
        m_recoContext.Release();
    }

    if( m_recoGrammar != NULL )
    {
        // ディクテーション文法を解放する
        m_recoGrammar.Release();
    }

    // COMを閉じる
    ::CoUninitialize();

    ::OutputDebugString( L"SAPIを破棄した\r\n" );
}

// 初期化する
void SpeechEngine::Init( HWND hWnd, const wchar_t* grammarFile )
{
    HRESULT result;
    CComPtr< ISpRecognizer > recognizer;    // 認識エンジン オブジェクト


    // COMを初期化する
    result = ::CoInitialize( NULL );
    if( FAILED( result ) )
    {
        throw new SapiException( L"COM の初期化に失敗した" );
    }

    // 認識エンジン オブジェクトを生成する
    result = recognizer.CoCreateInstance( CLSID_SpInprocRecognizer );
    if( FAILED( result ) )
    {
        throw new SapiException( L"認識エンジン オブジェクトの生成に失敗した" );
    }

    // 認識コンテクスト オブジェクトを生成する
    result = recognizer->CreateRecoContext( &m_recoContext );
    if( FAILED( result ) )
    {
        throw new SapiException( L"認識コンテクスト オブジェクトの生成に失敗した" );
    }

    // ウィンドウズ メッセージを認識コンテクストに登録する
    result = m_recoContext->SetNotifyWindowMessage( hWnd, WM_REC_EVENT, 0, 0 );
    if( FAILED( result ) )
    {
        throw new SapiException( L"ウィンドウズ メッセージの 認識コンテクストへの登録に失敗した" );
    }

    // 認識エンジンに要求するイベントの種類を設定する
    const ULONGLONG eventInterest =
        SPFEI( SPEI_RECOGNITION ) |         // 第2パス最終結果生成
        SPFEI( SPEI_FALSE_RECOGNITION ) |   // 第2パス最終結果生成
        SPFEI( SPEI_SOUND_START ) |         // 音声検出 (切り出しを行う場合は、切り出し開始位置検出時)
        SPFEI( SPEI_SOUND_END );            // 切り出し終了位置検出

    result = m_recoContext->SetInterest( eventInterest, eventInterest );
    if( FAILED( result ) )
    {
        throw new SapiException( L"認識エンジンに要求する イベントの種類の設定に失敗した" );
    }

    // マイクを初期化する
    InitMicrophone( recognizer );

    // 文法を初期化する
    InitGrammar( grammarFile );

    ::OutputDebugString( L"SAPIを初期化した\r\n" );
}

// マイクを初期化する
void SpeechEngine::InitMicrophone( CComPtr< ISpRecognizer > &recognizer )
{
    HRESULT result;
    CComPtr< ISpAudio > audio;  // リアルタイム オーディオ ストリーム


    // デフォルトのオーディオ オブジェクトを生成する
    result = SpCreateDefaultObjectFromCategoryId( SPCAT_AUDIOIN, &audio );
    if( FAILED( result ) )
    {
        throw new SapiException( L"オーディオ オブジェクトの生成に失敗した" );
    }

    // ... 入力ストリームに音声認識エンジンを使うように設定する
    result = recognizer->SetInput( audio, true );
    if( FAILED( result ) )
    {
        throw new SapiException( L"入力ストーの設定に失敗した" );
    }
}

// 文法を初期化する
void SpeechEngine::InitGrammar( wchar_t const* grammarFile )
{
    HRESULT result;
    const ULONGLONG grammarID = 0;  // 文法ID


    // XMLによるコマンド文法を生成する
    result = m_recoContext->CreateGrammar( grammarID, &m_recoGrammar );
    if( FAILED( result ) )
    {
        throw new SapiException( L"コマンド文法の生成に失敗した" );
    }

    if( grammarFile != NULL )
    {
        // ファイルからディクテーション文法を読み込む
        result = m_recoGrammar->LoadCmdFromFile( grammarFile, SPLO_STATIC );
        if( FAILED( result ) )
        {
            throw new SapiException( L"ファイルからのディクテショ文読込みに失敗した" );
        }

        // ディクテーションの文法規則をアクテブす
        result = m_recoGrammar->SetRuleState( NULL, NULL, SPRS_ACTIVE );
        if( FAILED( result ) )
        {
            throw new SapiException( L"ディクテーションの文法規則をアクティブにできなかった" );
        }
    }
    else
    {
        // デフォルトのディクテーション文法を読み込む
        result = m_recoGrammar->LoadDictation( NULL, SPLO_STATIC );
        if( FAILED( result ) )
        {
            throw new SapiException( L"デフォルトのディクテーション文法の読み込みに失敗した" );
        }

        // ディクテーションのトピックをアクティブにする
        result = m_recoGrammar->SetDictationState( SPRS_ACTIVE );
        if( FAILED( result ) )
        {
            throw new SapiException( L"ディクテーションのトピックを アクティブにできなかった" );
        }
    }
}

// 認識イベントを取得する
int SpeechEngine::GetRecognitionEvent()
{
    // キューにイベントがなければ何もしない
    if( m_spEvent.GetFrom( m_recoContext ) != S_OK )
    {
        return 0;
    }

    // イベントIDを返す
    return m_spEvent.eEventId;
}

// 認識結果を取得する
BOOL SpeechEngine::GetRecognitionResult( wchar_t* text )
{
    CSpDynamicString dynamicStrig;

    // 認識結果を取得する
    HRESULT result = m_spEvent.RecoResult()->GetText(
        ( ULONG )SP_GETWHOLEPHRASE,
        ( ULONG )SP_GETWHOLEPHRASE,
        true,
        &dynamicStrig,
        NULL
    );
    if( FAILED( result ) || ( dynamicStrig == NULL ) )
    {
        // 取得に失敗したならば、処理を中止する
        return false;
    }

    // 認識された文字列の型を変換して取得する
    wcscpy_s( text, WORD_MAX_SIZE, W2T( dynamicStrig ) );

    return true;
}

// 認識された発音を取得する
BOOL SpeechEngine::GetRecognizedPronunciation( wchar_t* text )
{
    SPPHRASE* phrase;

    // First-Bestのフレーズを取得する
    HRESULT result = m_spEvent.RecoResult()->GetPhrase( &phrase );
    if( FAILED( result ) )
    {
        return false;
    }

    // ... それの発音を取得する
    const SPPHONEID* phoneID = phrase->pElements->pszPronunciation;
    if( phoneID == NULL )
    {
        return false;
    }

    // 取得された文字列の型を変換する
    wcscpy_s( text, WORD_MAX_SIZE, reinterpret_cast< const wchar_t* >( phoneID ) );

    return true;
}

// 信頼度を取得する
BOOL SpeechEngine::GetConfidence( double& value )
{
    SPPHRASE* phrase;

    // First-Bestのフレーズを取得する
    HRESULT result = m_spEvent.RecoResult()->GetPhrase( &phrase );
    if( FAILED( result ) )
    {
        return false;
    }

    // ... それの信頼度を取得する
    value = phrase->Rule.SREngineConfidence;

    return true;
}

// 状態を取得する
const wchar_t* SpeechEngine::GetState( int eventID )
{
    switch( eventID )
    {
        case SPEI_SOUND_START:  // 音声が開始された
            return L"認識中";

        case SPEI_SOUND_END:    // 音声が終了された
            return L"終了";

        case SPEI_RECOGNITION:  // 認識した
            return L"待機中";

        case SPEI_FALSE_RECOGNITION:    // 認識に失敗した
            return L"認識失敗";
    }

    return L"error";
}

C++/CLI コード部

上記クラスのラッパーです。

Recognition.h

// Recognition.h

#pragma once

#include "SpeechEngine.h"

namespace SAPI
{
    class SpeechEngine;

    // 認識
    public ref class Recognition
    {
    // Construction --------------------------------------------------------
    public:
        ~Recognition() { Recognition::!Recognition(); }
        !Recognition();

    // Operation -----------------------------------------------------------
    public:
        bool Init( System::IntPtr hWnd );
        bool Init( System::IntPtr hWnd, System::String^ grammarFile );

        int GetRecognitionEvent();

        bool GetRecognitionResult( System::String^% text );
        bool GetRecognizedPronunciation( System::String^% text );

        bool GetConfidence( double& value );
        System::String^ GetState( int eventID );

    // Attribute ===========================================================
    private:
        SpeechEngine* m_sapi;

    public:
        literal int REC_EVENT = WM_REC_EVENT;           // 認識イベント

        literal int SOUND_START = SPEI_SOUND_START;             // 音声が開始された
        literal int SOUND_END = SPEI_SOUND_END;                 // 音声が終了された
        literal int RECOGNITION = SPEI_RECOGNITION;             // 認識した
        literal int FALSE_RECOGNITION = SPEI_FALSE_RECOGNITION; // 認識に失敗した
    };
}

Recognition.cpp

#include "StdAfx.h"
#include "Recognition.h"
#include "SapiException.h "

using namespace SAPI;
using namespace System::Diagnostics;


// ファイナライザ
Recognition::!Recognition()
{
    delete m_sapi;
}

// 初期化する
bool Recognition::Init( System::IntPtr hWnd )
{
    return Init( hWnd, nullptr );
}

// 初期化する
bool Recognition::Init( System::IntPtr hWnd, System::String^ grammarFile )
{
    Debug::Write( "SAPIを初期化する" );

    // SAPIを構築する
    m_sapi = new SpeechEngine();

    // ウィンドウ ハンドルへキャストする
    HWND windowHandle = reinterpret_cast< HWND >( hWnd.ToInt32() );

    try
    {
        pin_ptr< wchar_t > wcharPinptr = nullptr;

        if( grammarFile != nullptr )
        {
            // System::Stringをwchar_t型の配列にする
            array< wchar_t >^ wcharArray = grammarFile->ToCharArray();

            // ... アンマネージド関数に渡すために、配列のアドレスを固定する
            wcharPinptr = &wcharArray[ 0 ];
        }

        // 初期化する
        m_sapi->Init( windowHandle, wcharPinptr );
    }
    catch( SapiException* e )
    {
        // SAPIの例外を捕捉した
        Debug::Write( gcnew System::String( e->GetMessage() ) );
        Debug::Write( "SAPIの初期化に失敗した" );

        return false;
    }

    return true;
}

// 認識イベントを取得する
int Recognition::GetRecognitionEvent()
{
    return m_sapi->GetRecognitionEvent();
}

// 認識結果を取得する
bool Recognition::GetRecognitionResult( System::String^% text )
{
    wchar_t result[ WORD_MAX_SIZE ];

    if( !m_sapi->GetRecognitionResult( result ) )
    {
        return false;
    }

    // 型を変換する
    text = gcnew System::String( result );

    return true;
}

// 認識された発音を取得する
bool Recognition::GetRecognizedPronunciation( System::String^% text )
{
    wchar_t result[ WORD_MAX_SIZE ];

    if( !m_sapi->GetRecognizedPronunciation( result ) )
    {
        return false;
    }

    // 型を変換する
    text = gcnew System::String( result );

    return true;
}

// 信頼度を取得する
bool Recognition::GetConfidence( double& value )
{
    if( !m_sapi->GetConfidence( value ) )
    {
        return false;
    }

    return true;
}


// 状態を取得する
System::String^ Recognition::GetState( int eventID )
{
    return gcnew System::String( m_sapi->GetState( eventID ) );
}