Spraakinvoer in DirectX
Opmerking
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 kleine woordgroeps- en zinsherkenning implementeert in een DirectX-app voor Windows Mixed Reality.
Opmerking
De codefragmenten in dit artikel maken gebruik van C++/CX in plaats van C++17-compatibele C++/WinRT, die wordt gebruikt in de holografische projectsjabloon C++. 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 te schakelen in uw app. Deze walk-through maakt gebruik 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 nieuwe instantie 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));
Gebruik het object SpeechRecognitionListConstraint om de lijst met opdrachten te laden in de lijst met beperkingen voor de spraakherkenning.
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 is opgetreden. Sla de gebeurtenisgegevens op zodat u deze in een latere updatelus kunt gebruiken.
Vanaf 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 zinnen of zinnen die de gebruiker spreekt. In dit geval passen we een SpeechRecognitionTopicConstraint toe die de spraakherkenningsserver vertelt welk type invoer moet worden verwacht. Hier volgt een app-werkstroom voor dit scenario:
- Uw app maakt de SpeechRecognizer, biedt ui-prompts en begint te luisteren naar een gesproken opdracht.
- De gebruiker spreekt een woordgroep of zin uit.
- 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.
- 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 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 minimaal een 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;
}
});
Opmerking
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 de volgende webspecifieke scenariobeperking voor spraakzoekopdrachten.
// 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 de Windows 10 UWP-spraakcode voor het scenario voor doorlopend dicteren.
Kwaliteitsdegradatie verwerken
Omgevingsomstandigheden verstoren soms spraakherkenning. De ruimte is bijvoorbeeld te luidruchtig of de gebruiker spreekt te hard. Waar mogelijk biedt de spraakherkenning-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 op deze gebeurtenis kunt abonneren.
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 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 de 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 verw-klassen gebruikt om uw DirectX-app te maken, moet u zich afmelden voor de gebeurtenis voordat u uw spraakherkenningsprogramma vrijgeeft of opnieuw maakt. De 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 hoorbare aanwijzingen te geven
De holografische spraakvoorbeelden maken gebruik van spraaksynthese om de gebruiker hoorbare instructies te geven. In deze sectie ziet u hoe u een gesynthetiseerd spraakvoorbeeld maakt en dit vervolgens afspeelt via de HRTF-audio-API's.
We raden u aan uw eigen spraakprompts op te geven wanneer u woordgroepinvoer aanvraagt. Prompts kunt ook aangeven wanneer spraakopdrachten kunnen worden gesproken voor een scenario voor continue herkenning. In het volgende voorbeeld ziet u hoe u hiervoor een spraaksynthesizer gebruikt. U kunt ook een vooraf opgenomen spraakfragment, 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 om te 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 bytestroom 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.
}
});