DirectX での音声入力Voice input in DirectX

この記事では、Windows Mixed Reality の DirectX アプリで音声コマンドと小さな語句と文認識を実装する方法について説明します。This article explains how to implement voice commands plus small-phrase and sentence recognition in a DirectX app for Windows Mixed Reality.

注意

この記事のコードスニペットではC++、 C++ holographic プロジェクトテンプレートで使用されるC++C + c++ 17 準拠の/WinRT ではなく、/cx を使用します。The code snippets in this article use C++/CX rather than C++17-compliant C++/WinRT, which is used in the C++ holographic project template. これらの概念は、1 C++つの WinRT プロジェクトに相当しますが、コードを変換する必要があります。The concepts are equivalent for a C++/WinRT project, but you need to translate the code.

SpeechRecognizer を使用して音声認識を継続するUse SpeechRecognizer for continuous speech recognition

このセクションでは、音声認識を使用してアプリで音声コマンドを有効にする方法について説明します。This section describes how to use continuous speech recognition to enable voice commands in your app. このチュートリアルでは、 HolographicVoiceInputサンプルのコードを使用します。This walk-through uses code from the HolographicVoiceInput sample. サンプルを実行している場合は、登録されているいずれかのカラーコマンドの名前を読み上げて、回転しているキューブの色を変更します。When the sample is running, speak the name of one of the registered color commands to change the color of the spinning cube.

最初に、新しいWindows:: Media:: SpeechRecognition:: SpeechRecognizerインスタンスを作成します。First, create a new Windows::Media::SpeechRecognition::SpeechRecognizer instance.

HolographicVoiceInputSampleMain:: CreateSpeechConstraintsForCurrentStateから:From HolographicVoiceInputSampleMain::CreateSpeechConstraintsForCurrentState:

m_speechRecognizer = ref new SpeechRecognizer();

レコグナイザーがリッスンする音声コマンドのリストを作成します。Create a list of speech commands for the recognizer to listen for. ここでは、ホログラムの色を変更するための一連のコマンドを作成します。Here, we construct a set of commands to change the color of a hologram. 便宜上、後でコマンドに使用するデータも作成します。For convenience, we also create the data that we'll use for the commands later.

m_speechCommandList = ref new Platform::Collections::Vector<String^>();
   m_speechCommandData.clear();
   m_speechCommandList->Append(StringReference(L"white"));
   m_speechCommandData.push_back(float4(1.f, 1.f, 1.f, 1.f));
   m_speechCommandList->Append(StringReference(L"grey"));
   m_speechCommandData.push_back(float4(0.5f, 0.5f, 0.5f, 1.f));
   m_speechCommandList->Append(StringReference(L"green"));
   m_speechCommandData.push_back(float4(0.f, 1.f, 0.f, 1.f));
   m_speechCommandList->Append(StringReference(L"black"));
   m_speechCommandData.push_back(float4(0.1f, 0.1f, 0.1f, 1.f));
   m_speechCommandList->Append(StringReference(L"red"));
   m_speechCommandData.push_back(float4(1.f, 0.f, 0.f, 1.f));
   m_speechCommandList->Append(StringReference(L"yellow"));
   m_speechCommandData.push_back(float4(1.f, 1.f, 0.f, 1.f));
   m_speechCommandList->Append(StringReference(L"aquamarine"));
   m_speechCommandData.push_back(float4(0.f, 1.f, 1.f, 1.f));
   m_speechCommandList->Append(StringReference(L"blue"));
   m_speechCommandData.push_back(float4(0.f, 0.f, 1.f, 1.f));
   m_speechCommandList->Append(StringReference(L"purple"));
   m_speechCommandData.push_back(float4(1.f, 0.f, 1.f, 1.f));

辞書に含まれていない可能性のある発音語を使用して、コマンドを指定できます。You can use phonetic words that might not be in a dictionary to specify commands.

m_speechCommandList->Append(StringReference(L"SpeechRecognizer"));
   m_speechCommandData.push_back(float4(0.5f, 0.1f, 1.f, 1.f));

Speech レコグナイザーの制約の一覧にコマンドリストを読み込むには、 SpeechRecognitionListConstraintオブジェクトを使用します。To load the commands list into the list of constraints for the speech recognizer use a SpeechRecognitionListConstraint object.

SpeechRecognitionListConstraint^ spConstraint = ref new SpeechRecognitionListConstraint(m_speechCommandList);
   m_speechRecognizer->Constraints->Clear();
   m_speechRecognizer->Constraints->Append(spConstraint);
   create_task(m_speechRecognizer->CompileConstraintsAsync()).then([this](SpeechRecognitionCompilationResult^ compilationResult)
   {
       if (compilationResult->Status == SpeechRecognitionResultStatus::Success)
       {
           m_speechRecognizer->ContinuousRecognitionSession->StartAsync();
       }
       else
       {
           // Handle errors here.
       }
   });

音声認識エンジンのSpeechContinuousRecognitionSessionresultgeneratedイベントをサブスクライブします。Subscribe to the ResultGenerated event on the speech recognizer's SpeechContinuousRecognitionSession. このイベントは、いずれかのコマンドが認識されたときにアプリに通知します。This event notifies your app when one of your commands has been recognized.

m_speechRecognizer->ContinuousRecognitionSession->ResultGenerated +=
       ref new TypedEventHandler<SpeechContinuousRecognitionSession^, SpeechContinuousRecognitionResultGeneratedEventArgs^>(
           std::bind(&HolographicVoiceInputSampleMain::OnResultGenerated, this, _1, _2)
           );

Onresultgeneratedイベントハンドラーは、 SpeechContinuousRecognitionResultGeneratedEventArgsインスタンス内のイベントデータを受信します。Your OnResultGenerated event handler receives event data in a SpeechContinuousRecognitionResultGeneratedEventArgs instance. 確信度が定義したしきい値を超える場合、アプリはイベントが発生したことを確認する必要があります。If the confidence is greater than the threshold that you defined, your app should note that the event happened. 後続の更新ループで使用できるように、イベントデータを保存します。Save the event data so that you can use it in a subsequent update loop.

HolographicVoiceInputSampleMainから:From HolographicVoiceInputSampleMain.cpp:

// Change the cube color, if we get a valid result.
   void HolographicVoiceInputSampleMain::OnResultGenerated(SpeechContinuousRecognitionSession ^sender, SpeechContinuousRecognitionResultGeneratedEventArgs ^args)
   {
       if (args->Result->RawConfidence > 0.5f)
       {
           m_lastCommand = args->Result->Text;
       }
   }

このコード例では、ユーザーのコマンドに従って、回転したホログラムキューブの色を変更します。In our example code, we change the color of the spinning hologram cube according to the user's command.

HolographicVoiceInputSampleMain:: Updateから:From HolographicVoiceInputSampleMain::Update:

// Check for new speech input since the last frame.
   if (m_lastCommand != nullptr)
   {
       auto command = m_lastCommand;
       m_lastCommand = nullptr;

       int i = 0;
       for each (auto& iter in m_speechCommandList)
       {
           if (iter == command)
           {
               m_spinningCubeRenderer->SetColor(m_speechCommandData[i]);
               break;
           }

           ++i;
       }
   }

"ワンショット" 認識を使用するUse "one-shot" recognition

ユーザーが話す語句や文をリッスンするように音声認識エンジンを構成できます。You can configure a speech recognizer to listen for phrases or sentences that the user speaks. この例では、必要な入力の種類を音声認識エンジンに伝えるSpeechRecognitionTopicConstraintを適用します。In this case, we apply a SpeechRecognitionTopicConstraint that tells the speech recognizer what type of input to expect. このシナリオのアプリワークフローを次に示します。Here's an app workflow for this scenario:

  1. アプリによって SpeechRecognizer が作成され、UI プロンプトが表示され、音声コマンドのリッスンが開始されます。Your app creates the SpeechRecognizer, provides UI prompts, and starts listening for a spoken command.
  2. ユーザーは、語句または文を読み上げます。The user speaks a phrase or sentence.
  3. ユーザーの音声認識が発生し、結果がアプリに返されます。Recognition of the user's speech occurs, and a result is returned to the app. この時点で、アプリは、認識が発生したことを示す UI プロンプトを提供する必要があります。At this point, your app should provide a UI prompt to indicate that recognition has occurred.
  4. 応答する信頼レベルと音声認識の結果の信頼レベルに応じて、アプリは結果を処理し、必要に応じて応答することができます。Depending on the confidence level that you want to respond to and the confidence level of the speech recognition result, your app can process the result and respond as appropriate.

このセクションでは、SpeechRecognizer を作成し、制約をコンパイルして、音声入力をリッスンする方法について説明します。This section describes how to create a SpeechRecognizer, compile the constraint, and listen for speech input.

次のコードでは、トピック制約をコンパイルします。この場合、この例では web 検索用に最適化されています。The following code compiles the topic constraint, which in this case is optimized for web search.

auto constraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::WebSearch, L"webSearch");
   m_speechRecognizer->Constraints->Clear();
   m_speechRecognizer->Constraints->Append(constraint);
   return create_task(m_speechRecognizer->CompileConstraintsAsync())
       .then([this](task<SpeechRecognitionCompilationResult^> previousTask)
   {

コンパイルが成功した場合は、音声認識を続行できます。If compilation succeeds, we can proceed with speech recognition.

try
       {
           SpeechRecognitionCompilationResult^ compilationResult = previousTask.get();

           // Check to make sure that the constraints were in a proper format and the recognizer was able to compile it.
           if (compilationResult->Status == SpeechRecognitionResultStatus::Success)
           {
               // If the compilation succeeded, we can start listening for the user's spoken phrase or sentence.
               create_task(m_speechRecognizer->RecognizeAsync()).then([this](task<SpeechRecognitionResult^>& previousTask)
               {

その後、結果がアプリに返されます。The result is then returned to the app. 結果に十分な確信があれば、コマンドを処理することができます。If we're confident enough in the result, we can process the command. このコード例では、少なくとも中程度の自信を持つ結果を処理します。This code example processes results with at least medium confidence.

try
                   {
                       auto result = previousTask.get();

                       if (result->Status != SpeechRecognitionResultStatus::Success)
                       {
                           PrintWstringToDebugConsole(
                               std::wstring(L"Speech recognition was not successful: ") +
                               result->Status.ToString()->Data() +
                               L"\n"
                               );
                       }

                       // In this example, we look for at least medium confidence in the speech result.
                       if ((result->Confidence == SpeechRecognitionConfidence::High) ||
                           (result->Confidence == SpeechRecognitionConfidence::Medium))
                       {
                           // If the user said a color name anywhere in their phrase, it will be recognized in the
                           // Update loop; then, the cube will change color.
                           m_lastCommand = result->Text;

                           PrintWstringToDebugConsole(
                               std::wstring(L"Speech phrase was: ") +
                               m_lastCommand->Data() +
                               L"\n"
                               );
                       }
                       else
                       {
                           PrintWstringToDebugConsole(
                               std::wstring(L"Recognition confidence not high enough: ") +
                               result->Confidence.ToString()->Data() +
                               L"\n"
                               );
                       }
                   }

音声認識を使用する場合は常に、ユーザーがシステムのプライバシー設定でマイクをオフにしたことを示す例外を監視します。Whenever you use speech recognition, watch for exceptions that could indicate that the user has turned off the microphone in the system privacy settings. これは、初期化または認識中に発生する可能性があります。This can happen during initialization or recognition.

catch (Exception^ exception)
                   {
                       // Note that if you get an "Access is denied" exception, you might need to enable the microphone
                       // privacy setting on the device and/or add the microphone capability to your app manifest.

                       PrintWstringToDebugConsole(
                           std::wstring(L"Speech recognizer error: ") +
                           exception->ToString()->Data() +
                           L"\n"
                           );
                   }
               });

               return true;
           }
           else
           {
               OutputDebugStringW(L"Could not initialize predefined grammar speech engine!\n");

               // Handle errors here.
               return false;
           }
       }
       catch (Exception^ exception)
       {
           // Note that if you get an "Access is denied" exception, you might need to enable the microphone
           // privacy setting on the device and/or add the microphone capability to your app manifest.

           PrintWstringToDebugConsole(
               std::wstring(L"Exception while trying to initialize predefined grammar speech engine:") +
               exception->Message->Data() +
               L"\n"
               );

           // Handle exceptions here.
           return false;
       }
   });

注意

音声認識を最適化するために使用できる定義済みのSpeechRecognitionScenariosがいくつかあります。There are several predefined SpeechRecognitionScenarios that you can use to optimize speech recognition.

  • ディクテーション用に最適化するには、ディクテーションのシナリオを使用します。To optimize for dictation, use the dictation scenario.

    // Compile the dictation topic constraint, which optimizes for speech dictation.
    auto dictationConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::Dictation, "dictation");
    m_speechRecognizer->Constraints->Append(dictationConstraint);
    
  • Speech web 検索の場合は、次の web 固有のシナリオ制約を使用します。For speech web searches, use the following web-specific scenario constraint.

    // Add a web search topic constraint to the recognizer.
    auto webSearchConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::WebSearch, "webSearch");
    speechRecognizer->Constraints->Append(webSearchConstraint);
    
  • フォームを入力するには、フォームの制約を使用します。Use the form constraint to fill out forms. この場合は、フォームを入力するために最適化された独自の文法を適用することをお勧めします。In this case, it's best to apply your own grammar that's optimized for filling out the form.

    // Add a form constraint to the recognizer.
    auto formConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::FormFilling, "formFilling");
    speechRecognizer->Constraints->Append(formConstraint );
    
  • SRGS 形式で独自の文法を提供できます。You can provide your own grammar in the SRGS format.

連続認識を使用するUse continuous recognition

連続ディクテーションのシナリオについては、「 Windows 10 UWP speech コードサンプル」を参照してください。For the continuous-dictation scenario, see the Windows 10 UWP speech code sample.

品質低下を処理するHandle quality degradation

環境の状況によっては、音声認識が妨げられることがあります。Environmental conditions sometimes interfere with speech recognition. たとえば、部屋の雑音が多すぎる場合や、ユーザーの声が大きすぎる場合があります。For example, the room might be too noisy, or the user might speak too loudly. 音声認識 API は、可能な限り品質低下の原因となった状況に関する情報を提供します。Whenever possible, the speech recognition API provides information about the conditions that caused the quality degradation. この情報は、WinRT イベントを使用してアプリにプッシュされます。This information is pushed to your app through a WinRT event. 次の例は、このイベントをサブスクライブする方法を示しています。The following example shows how to subscribe to this event.

m_speechRecognizer->RecognitionQualityDegrading +=
       ref new TypedEventHandler<SpeechRecognizer^, SpeechRecognitionQualityDegradingEventArgs^>(
           std::bind(&HolographicVoiceInputSampleMain::OnSpeechQualityDegraded, this, _1, _2)
           );

このコードサンプルでは、条件情報をデバッグコンソールに書き込みます。In our code sample, we write the conditions information to the debug console. アプリは、UI、音声合成、および別の方法を使用してユーザーにフィードバックを提供することがあります。An app might want to provide feedback to the user through the UI, speech synthesis, and another method. または、品質の一時的な低下によって音声が中断されると、動作が異なる場合があります。Or it might need to behave differently when speech is interrupted by a temporary reduction in quality.

void HolographicSpeechPromptSampleMain::OnSpeechQualityDegraded(SpeechRecognizer^ recognizer, SpeechRecognitionQualityDegradingEventArgs^ args)
   {
       switch (args->Problem)
       {
       case SpeechRecognitionAudioProblem::TooFast:
           OutputDebugStringW(L"The user spoke too quickly.\n");
           break;

       case SpeechRecognitionAudioProblem::TooSlow:
           OutputDebugStringW(L"The user spoke too slowly.\n");
           break;

       case SpeechRecognitionAudioProblem::TooQuiet:
           OutputDebugStringW(L"The user spoke too softly.\n");
           break;

       case SpeechRecognitionAudioProblem::TooLoud:
           OutputDebugStringW(L"The user spoke too loudly.\n");
           break;

       case SpeechRecognitionAudioProblem::TooNoisy:
           OutputDebugStringW(L"There is too much noise in the signal.\n");
           break;

       case SpeechRecognitionAudioProblem::NoSignal:
           OutputDebugStringW(L"There is no signal.\n");
           break;

       case SpeechRecognitionAudioProblem::None:
       default:
           OutputDebugStringW(L"An error was reported with no information.\n");
           break;
       }
   }

参照クラスを使用して DirectX アプリを作成しない場合は、音声認識エンジンをリリースまたは再作成する前に、イベントの登録を解除する必要があります。If you're not using ref classes to create your DirectX app, you must unsubscribe from the event before you release or recreate your speech recognizer. HolographicSpeechPromptSample には、認識を停止し、イベントのサブスクライブを解除するルーチンがあります。The HolographicSpeechPromptSample has a routine to stop recognition and unsubscribe from events.

Concurrency::task<void> HolographicSpeechPromptSampleMain::StopCurrentRecognizerIfExists()
   {
       return create_task([this]()
       {
           if (m_speechRecognizer != nullptr)
           {
               return create_task(m_speechRecognizer->StopRecognitionAsync()).then([this]()
               {
                   m_speechRecognizer->RecognitionQualityDegrading -= m_speechRecognitionQualityDegradedToken;

                   if (m_speechRecognizer->ContinuousRecognitionSession != nullptr)
                   {
                       m_speechRecognizer->ContinuousRecognitionSession->ResultGenerated -= m_speechRecognizerResultEventToken;
                   }
               });
           }
           else
           {
               return create_task([this]() { m_speechRecognizer = nullptr; });
           }
       });
   }

音声合成を使用して音声入力のプロンプトを表示するUse speech synthesis to provide audible prompts

Holographic speech のサンプルでは、音声合成を使用してユーザーに可聴命令を提供します。The holographic speech samples use speech synthesis to provide audible instructions to the user. このセクションでは、合成された音声サンプルを作成し、HRTF audio Api を使用して再生する方法について説明します。This section shows how to create a synthesized voice sample and then play it back through the HRTF audio APIs.

語句入力を要求するときは、独自の音声入力プロンプトを指定する必要があります。You should provide your own speech prompts when you request phrase input. また、プロンプトを使用して、連続認識シナリオで音声コマンドを読み上げるタイミングを示すこともできます。Prompts can also help indicate when speech commands can be spoken for a continuous-recognition scenario. 次の例は、音声シンセサイザーを使用してこれを行う方法を示しています。The following example demonstrates how to use a speech synthesizer to do this. 事前に記録された音声クリップやビジュアル UI を使用することもできます。また、プロンプトが動的でないシナリオでは、その他の意見を示すこともできます。You could also use a pre-recorded voice clip, a visual UI, or another indicator of what to say, for example in scenarios where the prompt is not dynamic.

まず、SpeechSynthesizer オブジェクトを作成します。First, create the SpeechSynthesizer object.

auto speechSynthesizer = ref new Windows::Media::SpeechSynthesis::SpeechSynthesizer();

合成するテキストを含む文字列も必要です。You also need a string that includes the text to synthesize.

// Phrase recognition works best when requesting a phrase or sentence.
   StringReference voicePrompt = L"At the prompt: Say a phrase, asking me to change the cube to a specific color.";

音声は SynthesizeTextToStreamAsync を使用して非同期に合成されます。Speech is synthesized asynchronously through SynthesizeTextToStreamAsync. ここでは、音声を合成する非同期タスクを開始します。Here, we start an async task to synthesize the speech.

create_task(speechSynthesizer->SynthesizeTextToStreamAsync(voicePrompt), task_continuation_context::use_current())
       .then([this, speechSynthesizer](task<Windows::Media::SpeechSynthesis::SpeechSynthesisStream^> synthesisStreamTask)
   {
       try
       {

音声合成は、バイトストリームとして送信されます。The speech synthesis is sent as a byte stream. このバイトストリームを使用して、XAudio2 音声を初期化できます。We can use that byte stream to initialize an XAudio2 voice. Holographic のコードサンプルでは、HRTF オーディオ効果として再生します。For our holographic code samples, we play it back as an HRTF audio effect.

Windows::Media::SpeechSynthesis::SpeechSynthesisStream^ stream = synthesisStreamTask.get();

           auto hr = m_speechSynthesisSound.Initialize(stream, 0);
           if (SUCCEEDED(hr))
           {
               m_speechSynthesisSound.SetEnvironment(HrtfEnvironment::Small);
               m_speechSynthesisSound.Start();

               // Amount of time to pause after the audio prompt is complete, before listening
               // for speech input.
               static const float bufferTime = 0.15f;

               // Wait until the prompt is done before listening.
               m_secondsUntilSoundIsComplete = m_speechSynthesisSound.GetDuration() + bufferTime;
               m_waitingForSpeechPrompt = true;
           }
       }

音声認識と同様に、何らかの問題が発生した場合、音声合成は例外をスローします。As with speech recognition, speech synthesis throws an exception if something goes wrong.

catch (Exception^ exception)
       {
           PrintWstringToDebugConsole(
               std::wstring(L"Exception while trying to synthesize speech: ") +
               exception->Message->Data() +
               L"\n"
               );

           // Handle exceptions here.
       }
   });

関連項目See also