Голосовой ввод в DirectXVoice input in DirectX

Примечание

Эта статья связана с устаревшими собственными API-интерфейсами WinRT.This article relates to the legacy WinRT native APIs. Для новых проектов собственных приложений рекомендуется использовать API опенкср.For new native app projects, we recommend using the OpenXR API.

В этой статье объясняется, как реализовать голосовые команды , а также распознавание строчных фраз и предложений в приложении DirectX для Windows Mixed Reality.This article explains how to implement voice commands plus small-phrase and sentence recognition in a DirectX app for Windows Mixed Reality.

Примечание

В фрагментах кода в этой статье используется C++/CX вместо C + +17, совместимого с C++/WinRT, который используется в шаблоне проекта C++ holographic.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. Понятия эквивалентны для проекта C++/WinRT, но необходимо преобразовать код.The concepts are equivalent for a C++/WinRT project, but you need to translate the code.

Использование Спичрекогнизер для непрерывного распознавания речиUse SpeechRecognizer for continuous speech recognition

В этом разделе описывается использование непрерывного распознавания речи для включения голосовых команд в приложении.This section describes how to use continuous speech recognition to enable voice commands in your app. В этом пошаговом руководстве используется код из примера холографиквоицеинпут .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:: спичрекогнитион:: спичрекогнизер .First, create a new Windows::Media::SpeechRecognition::SpeechRecognizer instance.

Из холографиквоицеинпутсамплемаин:: креатеспичконстраинтсфоркуррентстате: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));

Чтобы загрузить список команд в список ограничений для распознавателя речи, используйте объект спичрекогнитионлистконстраинт .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.
       }
   });

Подпишитесь на событие ресултженератед в спичконтинуаусрекогнитионсессионраспознавателя речи.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)
           );

Обработчик событий онресултженератед получает данные события в экземпляре спичконтинуаусрекогнитионресултженератедевентаргс .Your OnResultGenerated event handler receives event data in a SpeechContinuousRecognitionResultGeneratedEventArgs instance. Если достоверность превышает заданное вами пороговое значение, приложение должно отметить, что событие произошло.If the confidence is greater than the threshold you defined, your app should note that the event happened. Сохраните данные события, чтобы их можно было использовать в более позднем цикле обновления.Save the event data so that you can use it in a later update loop.

Из холографиквоицеинпутсамплемаин. cpp: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.

Из холографиквоицеинпутсамплемаин:: 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. В этом случае мы применяем спичрекогнитионтопикконстраинт , который сообщает распознавателю распознавания речи, какой тип входных данных следует рассчитывать.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. Приложение создает Спичрекогнизер, предоставляет запросы пользовательского интерфейса и начинает прослушивание произнесенной команды.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. На этом этапе приложение должно предоставить запрос пользовательского интерфейса, чтобы указать, что произошло распознавание.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.

В этом разделе описывается создание Спичрекогнизер, компиляция ограничения и прослушивание речевого ввода.This section describes how to create a SpeechRecognizer, compile the constraint, and listen for speech input.

Следующий код компилирует ограничение раздела, которое в этом случае оптимизировано для поиска в Интернете.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 continue 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;
       }
   });

Примечание

Существует несколько предопределенных спичрекогнитионсценариос , которые можно использовать для оптимизации распознавания речи.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);
    
  • Для поиска в Интернете через речь используйте следующее ограничение для конкретного веб-сценария.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.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. Приложение может захотеть предоставить отзыв пользователю с помощью пользовательского интерфейса, синтеза речи и другого метода.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. В Холографикспичпромптсампле есть подпрограммы для прекращения распознавания и отмены подписки на события.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 речь используется синтез речи для предоставления пользователю инструкций.The holographic speech samples use speech synthesis to provide audible instructions to the user. В этом разделе показано, как создать пример синтезированного голоса, а затем воспроизвести его с помощью API аудио ХРТФ.This section shows how to create a synthesized voice sample and then play it back through the HRTF audio APIs.

При запросе ввода фразы рекомендуется предоставлять собственные голосовые запросы.We recommend providing 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. Можно также использовать предварительно записанный голосовый ролик, визуальный пользовательский интерфейс или другой индикатор того, что следует сказать, например в сценариях, где запрос не является динамическим.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 isn't dynamic.

Сначала создайте объект Спичсинсесизер.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.";

Речь создается асинхронно через Синсесизетексттостреамасинк.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. Для наших примеров кода мы воспроизводим его как ХРТФ Audio.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