DirectX での音声入力Voice input in DirectX

このトピックでは、Windows Mixed Reality の DirectX アプリで音声コマンドを実装する方法と、小さなフレーズと文の認識を実装する方法について説明します。This topic explains how to implement voice commands, and 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 currently demonstrate use of C++/CX rather than C++17-compliant C++/WinRT as used in the C++ holographic project template. これらの概念は、プロジェクトC++の場合と同じですが、コードを変換する必要があります。The concepts are equivalent for a C++/WinRT project, though you will need to translate the code.

音声コマンドを継続的に認識するために SpeechRecognizer を使用するUse a SpeechRecognizer for continuous recognition of voice commands

このセクションでは、音声認識を使用してアプリで音声コマンドを有効にする方法について説明します。In this section, we describe how to use continuous speech recognition to enable voice commands in your app. このチュートリアルでは、 HolographicVoiceInputサンプルのコードを使用します。This walkthrough 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();

レコグナイザーがリッスンする音声コマンドのリストを作成する必要があります。You'll need to 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 the sake of convenience, we also create the data that we'll use for the commands later on.

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));

コマンドは、辞書に含まれていない可能性のある発音の単語を使用して指定できます。Commands can be specified using phonetic words that might not be in a dictionary:

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

コマンドの一覧が、音声認識エンジンの制約の一覧に読み込まれます。The list of commands is loaded into the list of constraints for the speech recognizer. これを行うには、 SpeechRecognitionListConstraintオブジェクトを使用します。This is done by using 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 you have defined, your app should note that the event happened. 後続の更新ループで使用できるように、イベントデータを保存します。Save the event data so that you can make use of 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;
       }
   }

アプリのシナリオに適用されるデータを使用します。Make use of the data however applicable to your app scenario. このコード例では、ユーザーのコマンドに従って、回転したホログラムキューブの色を変更します。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 dictation for one-shot recognition of speech phrases and sentences

ユーザーが読み上げる語句や文をリッスンするように音声認識エンジンを構成できます。You can configure a speech recognizer to listen for phrases or sentences spoken by the user. この例では、必要な入力の種類を音声認識エンジンに伝える SpeechRecognitionTopicConstraint を適用します。In this case, we apply a SpeechRecognitionTopicConstraint that tells the speech recognizer what type of input to expect. この種類のユースケースでは、アプリのワークフローは次のようになります。The app workflow is as follows, for this type of use case:

  1. アプリによって SpeechRecognizer が作成され、UI プロンプトが表示され、すぐに読み上げるコマンドのリッスンが開始されます。Your app creates the SpeechRecognizer, provides UI prompts, and starts listening for a command to be spoken immediately.
  2. ユーザーは、語句または文を読み上げます。The user speaks a phrase, or sentence.
  3. ユーザーの音声認識が実行され、結果がアプリに返されます。Recognition of the user's speech is performed, and a result is returned to the app. この時点で、アプリは認識が発生したことを示す UI プロンプトを提供する必要があります。At this point, your app should provide a UI prompt indicating that recognition has occurred.
  4. 応答する信頼レベルと音声認識の結果の信頼レベルに応じて、アプリは結果を処理し、必要に応じて応答することができます。Depending on the confidence level 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 are 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, you should watch for exceptions that could indicate the user has turned off the microphone in the system privacy settings. これは、初期化中、または認識中に発生する可能性があります。This can happen during initialization, or during 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が用意されています。NOTE: There are several predefined SpeechRecognitionScenarios available for optimizing speech recognition.

  • ディクテーション用に最適化する場合は、ディクテーションのシナリオを使用します。If you want 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);
  • 音声を使用して Web 検索を実行する場合は、次のように Web 固有のシナリオ制約を使用できます。When using speech to perform a Web search, you can use a Web-specific scenario constraint as follows:
// 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 is best to apply your own grammar that is optimized for filling out your 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 using the SRGS format.

連続した自由形式の音声ディクテーションを使用するUse continuous, freeform speech dictation

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

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

環境内の条件によっては、音声認識の動作が妨げられることがあります。Conditions in the environment can sometimes prevent speech recognition from working. たとえば、部屋の雑音が多すぎる場合や、ユーザーが音量を大きくしすぎる場合などです。For example, the room might be too noisy or the user might speak at too high a volume. 音声認識 API は、品質の低下の原因となった条件について、可能な限り情報を提供します。The speech recognition API provides info, where possible, about conditions that have caused a degradation in quality.

この情報は、WinRT イベントを使用してアプリにプッシュされます。This information is pushed to your app using a WinRT event. このイベントをサブスクライブする方法の例を次に示します。Here is an example of 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 choose to write the conditions info to the debug console. アプリでは、UI や音声合成などを使用してユーザーにフィードバックを提供することができます。または、品質の一時的な低下によって音声が中断された場合に、動作が異なる場合があります。An app might want to provide feedback to the user via UI, speech synthesis, and so on, 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 are not using ref classes to create your DirectX app, you must unsubscribe from the event before releasing or recreating your speech recognizer. HolographicSpeechPromptSample には、認識を停止し、次のようなイベントのサブスクリプションを解除するルーチンがあります。The HolographicSpeechPromptSample has a routine to stop recognition, and unsubscribe from events like so:

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 voice prompts

Holographic speech のサンプルでは、音声合成を使用してユーザーに可聴命令を提供します。The holographic speech samples use speech synthesis to provide audible instructions to the user. このトピックでは、合成された音声サンプルを作成し、HRTF audio Api を使用して再生するプロセスについて説明します。This topic walks through the process of creating a synthesized voice sample, and playing it back using the HRTF audio APIs.

語句入力を要求するときは、独自の音声入力プロンプトを指定する必要があります。You should provide your own speech prompts when requesting phrase input. これは、音声コマンドをいつでも認識できるようにする場合にも役立ちます。This can also be helpful for indicating when speech commands can be spoken, for a continuous recognition scenario. 音声シンセサイザーを使用してこれを行う方法の例を次に示します。また、メッセージが動的でない場合などに、事前に記録された音声クリップ、ビジュアル UI、またはその他の意見を示すインジケーターを使用することもできます。Here is an example of how to do that with a speech synthesizer; note that you could also use a pre-recorded voice clip, a visual UI, or other 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 with the text to be synthesized:

// 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 using SynthesizeTextToStreamAsync. ここでは、音声を合成する非同期タスクを開始します。Here, we kick off 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 音声を初期化できます。holographic のコードサンプルでは、HRTF オーディオ効果として再生します。We can initialize an XAudio2 voice using that byte stream; 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 will throw 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