Spraakinvoer in DirectX

Notitie

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

In dit artikel wordt uitgelegd hoe u spraakopdrachten plus herkenning van kleine woordgroepen en zinnen 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-compatibel C++/WinRT, dat wordt gebruikt in de C++-holografische projectsjabloon. De concepten zijn gelijkwaardig voor 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 schakelen. In dit overzicht wordt gebruikgemaakt van code uit het HolographicVoiceInput-voorbeeld . Wanneer het voorbeeld wordt uitgevoerd, spreekt u de naam uit van een van de geregistreerde kleuropdrachten om de kleur van de draaiende kubus te wijzigen.

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

Vanuit HolographicVoiceInputSampleMain::CreateSpeechConstraintsForCurrentState:

m_speechRecognizer = ref new SpeechRecognizer();

Maak een lijst met spraakopdrachten voor de herkenningsserver om naar te luisteren. 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 voor de opdrachten gebruiken.

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 fonetische woorden gebruiken 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));

Als u de lijst met opdrachten wilt laden in de lijst met beperkingen voor de spraakherkenning, gebruikt u een 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.
       }
   });

Abonneer u op de gebeurtenis ResultGenerated op de SpeechContinuousRecognitionSession van de spraakherkenningsserver. Met deze gebeurtenis wordt uw app gewaarschuwd 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 SpeechContinuousRecognitionResultGeneratedEventArgs-exemplaar . Als de betrouwbaarheid groter is dan de drempelwaarde die u hebt gedefinieerd, moet uw app er rekening mee houden dat de gebeurtenis heeft plaatsgevonden. 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;
       }
   }

One-shot-herkenning gebruiken

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

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

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

Met de volgende code wordt de onderwerpbeperking gecompileerd, die in dit geval is geoptimaliseerd voor zoeken op het web.

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, watch op uitzonderingen die erop kunnen wijzen dat de gebruiker de microfoon heeft uitgeschakeld in de privacyinstellingen van het systeem. Dit kan gebeuren tijdens 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 het dicteren wilt optimaliseren, 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 webzoekopdrachten voor spraak 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 opgeven in de SRGS-indeling.

Continue herkenning gebruiken

Zie het voorbeeld van Windows 10 uwp-spraakcode voor het scenario voor doorlopend dicteren.

Kwaliteitsvermindering verwerken

Omgevingscondities verstoren soms spraakherkenning. De ruimte is bijvoorbeeld te luidruchtig of de gebruiker spreekt te hard. Indien mogelijk biedt de spraakherkennings-API informatie over de omstandigheden die de kwaliteitsvermindering hebben veroorzaakt. Deze informatie wordt naar uw app gepusht via een WinRT-gebeurtenis. 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 informatie over de voorwaarden naar de console voor foutopsporing. Een app wil de gebruiker mogelijk feedback geven via de gebruikersinterface, spraaksynthese en een andere methode. Het kan ook nodig zijn om zich anders te gedragen wanneer spraak wordt onderbroken door een tijdelijke kwaliteitsvermindering.

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 verwijzingsklassen gebruikt om uw DirectX-app te maken, moet u zich afmelden voor de gebeurtenis voordat u de spraakherkenning vrijgeeft of opnieuw maakt. HolographicSpeechPromptSample heeft een routine om 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 hoorbare aanwijzingen te geven

De holografische spraakvoorbeelden gebruiken spraaksynthese om de gebruiker hoorbare instructies te geven. In deze sectie wordt beschreven hoe u een gesynthetiseerd spraakvoorbeeld maakt en dit vervolgens afspeelt via de HRTF-audio-API's.

U wordt aangeraden uw eigen spraakprompts op te geven wanneer u zinsinvoer aanvraagt. Prompts kunnen ook aangeven wanneer spraakopdrachten kunnen worden gesproken voor een scenario met continue herkenning. In het volgende voorbeeld ziet u hoe u hiervoor een spraaksynthesizer gebruikt. 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 SpeechSynthesizer-object.

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

U hebt ook een tekenreeks nodig die de tekst bevat die u wilt synthetiseren.

// 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 asynchrone 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 bytestream gebruiken om een XAudio2-stem te initialiseren. Voor onze holografische codevoorbeelden spelen we deze af 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 genereert spraaksynthese een uitzondering 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