Spraakinvoer in DirectX

Notitie

Dit artikel heeft betrekking op de verouderde, native WinRT-API's. Voor nieuwe native app-projecten raden we u aan de OpenXR-API te gebruiken.

In dit artikel wordt uitgelegd hoe u spraakopdrachten plus kleine woordgroepen en zinsherkenning implementeert in een DirectX-app voor Windows Mixed Reality.

Notitie

De codefragmenten in dit artikel maken gebruik van C++/CX in plaats van C++17-compatibele C++/WinRT, die wordt gebruikt in de C++-holographic-projectsjabloon. De concepten zijn gelijk aan een C++/WinRT-project, maar u moet de code vertalen.

SpeechRecognizer gebruiken voor continue spraakherkenning

In deze sectie wordt beschreven hoe u continue spraakherkenning gebruikt om spraakopdrachten in uw app in te stellen. In dit voorbeeld wordt code uit het HolographicVoiceInput-voorbeeld gebruikt. Wanneer het voorbeeld wordt uitgevoerd, spreekt u de naam van een van de geregistreerde kleuropdrachten om de kleur van de draaiende kubus te wijzigen.

Maak eerst een nieuw exemplaar Windows::Media::SpeechRecognition::SpeechRecognizer.

Vanuit HolographicVoiceInputSampleMain::CreateSpeechConstraintsForCurrentState:

m_speechRecognizer = ref new SpeechRecognizer();

Maak een lijst met spraakopdrachten waar de herkenning naar luistert. Hier maken we een set opdrachten om de kleur van een hologram te wijzigen. Voor het gemak maken we ook de gegevens die we later gaan gebruiken voor de opdrachten.

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

U kunt gebruik maken van woorden die mogelijk niet in een woordenlijst staan om opdrachten op te geven.

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

Gebruik een SpeechRecognitionListConstraint-object om de lijst met opdrachten in de lijst met beperkingen voor de spraakherkenning te laden.

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

Abonneer u op de gebeurtenis ResultGenerated op de SpeechContinuousRecognitionSession van de spraakherkenningser. Deze gebeurtenis waarschuwt uw app wanneer een van uw opdrachten is herkend.

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

De gebeurtenis-handler OnResultGenerated ontvangt gebeurtenisgegevens in een exemplaar van SpeechContinuousRecognitionResultGeneratedEventArgs . Als de betrouwbaarheid groter is dan de drempelwaarde die u hebt gedefinieerd, moet uw app zien dat de gebeurtenis is gebeurd. Sla de gebeurtenisgegevens op zodat u deze in een latere updatelus kunt gebruiken.

Vanuit 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 onze voorbeeldcode wijzigen we de kleur van de draaiende hologramkubus volgens de opdracht van de gebruiker.

Vanuit 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;
       }
   }

Een herkenning in één keer gebruiken

U kunt een spraakherkenning configureren om te luisteren naar zinnen of zinnen die de gebruiker spreekt. In dit geval passen we een SpeechRecognitionTopicConstraint toe die de spraakherkenning vertelt welk type invoer kan worden verwacht. Hier is een app-werkstroom voor dit scenario:

  1. Uw app maakt de SpeechRecognizer, geeft ui-prompts en begint te luisteren naar een gesproken opdracht.
  2. De gebruiker spreekt een woordgroep of zin uit.
  3. Herkenning van de spraak van de gebruiker vindt plaats en er wordt een resultaat geretourneerd naar de app. Op dit moment moet uw app een ui-prompt geven om aan te geven dat er herkenning is opgetreden.
  4. Afhankelijk van het betrouwbaarheidsniveau dat u wilt reageren en het betrouwbaarheidsniveau van het spraakherkenningsresultaat, kan uw app het resultaat verwerken en waar nodig reageren.

In deze sectie wordt beschreven hoe u een SpeechRecognizer maakt, de beperking compileert en luistert naar spraakinvoer.

De volgende code compileert de onderwerpbeperking, die in dit geval is geoptimaliseerd voor zoeken op internet.

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

Als de compilatie slaagt, kunnen we doorgaan met spraakherkenning.

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

Het resultaat wordt vervolgens geretourneerd naar de app. Als we voldoende vertrouwen hebben in het resultaat, kunnen we de opdracht verwerken. In dit codevoorbeeld worden resultaten met ten minste gemiddelde betrouwbaarheid verwerkt.

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

Wanneer u spraakherkenning gebruikt, moet u op uitzonderingen letten die erop kunnen wijzen dat de gebruiker de microfoon heeft uitgeschakeld in de privacy-instellingen van het systeem. Dit kan gebeuren tijdens de initialisatie of herkenning.

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

Notitie

Er zijn verschillende vooraf gedefinieerde SpeechRecognitionScenario's die u kunt gebruiken om spraakherkenning te optimaliseren.

  • Als u wilt optimaliseren voor dicteren, gebruikt u het dicteerscenario.

    // Compile the dictation topic constraint, which optimizes for speech dictation.
    auto dictationConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::Dictation, "dictation");
    m_speechRecognizer->Constraints->Append(dictationConstraint);
    
  • Gebruik voor zoekopdrachten op spraakweb de volgende webspecifieke scenariobeperking.

    // Add a web search topic constraint to the recognizer.
    auto webSearchConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::WebSearch, "webSearch");
    speechRecognizer->Constraints->Append(webSearchConstraint);
    
  • Gebruik de formulierbeperking om formulieren in te vullen. In dit geval kunt u het beste uw eigen grammatica toepassen die is geoptimaliseerd voor het invullen van het formulier.

    // Add a form constraint to the recognizer.
    auto formConstraint = ref new SpeechRecognitionTopicConstraint(SpeechRecognitionScenario::FormFilling, "formFilling");
    speechRecognizer->Constraints->Append(formConstraint );
    
  • U kunt uw eigen grammatica in de SRGS-indeling gebruiken.

Continue herkenning gebruiken

Zie het voorbeeld Windows 10 UWP-spraakcode voor het scenario met continue dicteren.

Kwaliteitsdegradatie afhandelen

Omgevingsomstandigheden verstoren soms spraakherkenning. De ruimte kan bijvoorbeeld te veel ruis hebben of de gebruiker kan te hard praten. Indien mogelijk biedt de spraakherkennings-API informatie over de omstandigheden die de kwaliteitsvermindering hebben veroorzaakt. Deze informatie wordt via een WinRT-gebeurtenis naar uw app pushen. In het volgende voorbeeld ziet u hoe u zich kunt abonneren op deze gebeurtenis.

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

In ons codevoorbeeld schrijven we de voorwaardengegevens naar de foutopsporingsconsole. Een app kan feedback geven aan de gebruiker via de gebruikersinterface, spraaksynthese en een andere methode. Of het moet zich mogelijk anders gedragen wanneer spraak wordt onderbroken door een tijdelijke vermindering van de kwaliteit.

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

Als u geen refklassen gebruikt om uw DirectX-app te maken, moet u zich afmelden voor de gebeurtenis voordat u de spraakherkenning vrijgavet of opnieuw maakt. HolographicSpeechPromptSample heeft een routine om de herkenning te stoppen en u af te melden voor gebeurtenissen.

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

Spraaksynthese gebruiken om akoestische prompts te geven

In de holographic speech-voorbeelden wordt spraaksynthese gebruikt om de gebruiker akoestische instructies te geven. In deze sectie ziet u hoe u een voorbeeld van een gesynthetiseerde spraak maakt en vervolgens via de HRTF-audio-API's afstemt.

U wordt aangeraden uw eigen spraakprompts op te geven wanneer u woordgroepen invoert. Prompts kunnen ook helpen om aan te geven wanneer spraakopdrachten kunnen worden uitgesproken voor een scenario voor continue herkenning. In het volgende voorbeeld wordt gedemonstreerd hoe u dit doet met een spraak-logo. U kunt ook een vooraf opgenomen spraakclip, een visuele gebruikersinterface of een andere indicator van wat u moet zeggen gebruiken, bijvoorbeeld in scenario's waarin de prompt niet dynamisch is.

Maak eerst het object SpeechSynthesizer.

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

U hebt ook een tekenreeks nodig die de tekst bevat die moet worden gesynthetiseerd.

// 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.";

Spraak wordt asynchroon gesynthetiseerd via SynthesizeTextToStreamAsync. Hier starten we een asynsynthetische taak om de spraak te synthetiseren.

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

De spraaksynthese wordt verzonden als een bytestroom. We kunnen die bytestroom gebruiken om een XAudio2-stem te initialiseren. Voor onze holografische codevoorbeelden afspelen we deze terug als een 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;
           }
       }

Net als bij spraakherkenning wordt bij spraaksynthese een uitzondering in het verkeerde handen als er iets misgaat.

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

           // Handle exceptions here.
       }
   });

Zie ook