La reconnaissance vocale en C#

Le C# offre la possibilité de créer facilement un système de reconnaissance vocale à l'aide de l'objet SpeechRecognitionEngine. Ce système pouvant être rapidement intégré à des projets plus complexes. L'objet SpeechRecognitionEngine est particulièrement complet. Et cette publication bien que, non exhaustive vous permettra d'utiliser facilement et efficacement la reconnaissance vocale dans vos projets en C#.

SpeechRecognitionEngine et norme SISR

L'objet SpeechRecognitionEngine utilise, les standards W3C (SISR).  Ce système de règle sémantique est extrêmement riche, complet et complexe.

Mais il est parfaitement possible de structurer des règles complexes permettant de contextualiser la reconnaissance vocale.

Intégration de la référence System.Speech

Pour profiter de la classe SpeechRecognitionEngine, il faut en première étape incorporer la référence System.Speech.

Articulation de l'objet SpeechRecognitionEngine

  1. Définition de la langue à utiliser pour la reconnaissance vocale.
  2. Paramétrage de l'objet.
  3. Définition de la source audio à utiliser.
  4. Création des règles qui définiront la sémantique de la grammaire.
  5. Alimentation de la grammaire à utiliser pour réaliser la reconnaissance vocale.
  6. Création et assignation des différents événements de la reconnaissance vocale (détection, échec, succès).
  7. Initialisation de la reconnaissance vocale.
  8. Démarrage du thread (synchrone ou asynchrone de traitement).
  9. Arrêt du thread

La définition de la langue à utiliser pour la reconnaissance vocale en C#

La définition de la langue à utiliser s'appuie sur l'objet CultureInfo qui attend deux paramètres, un format de code de culture (dans notre cas pour une reconnaissance en Français : fr-FR) et un booléen qui servira à forcer la réécriture de la langue alors que le système d'exploitation en utilise (possiblement) une autre.

SpeechRecognitionEngine sre = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("fr-FR"));

Le paramétrage de l'objet SpeechRecognitionEngine

Pour réaliser le paramétrage de la langue, 5 propriétés sont à prendre en considération :

MaxAlternates : qui sert à déclarer le nombre d'interprétations alternatives que proposera le moteur de reconnaissance vocale.

InitialSilenceTimeout : cette propriété de l'objet SpeechRecognitionEngine sert à définir le délai entre une parole et un silence avant de finaliser la reconnaissance vocale.

EndSilenceTimeout : cette propriété permet de définir le délai de silence avant lequel l'opération de reconnaissance vocale valide l'interprétation.

EndSilenceTimeoutAmbiguous : pour déclarer le délai de silence en cas de détection ambiguë avant de valider une interprétation.

BabbleTimeout : délais de bruit blanc autorisé avant de finaliser une reconnaissance vocale.

Dans l'exemple suivant, nous ne souhaitons qu'un seul résultat, et nous définissons des délais d'attente d'environs 350ms pour garantir une réactivité maximum à notre reconnaissance vocale.

sre.MaxAlternates = 1;
sre.EndSilenceTimeout = new TimeSpan(0, 0, 0, 0, 355);
sre.EndSilenceTimeoutAmbiguous = new TimeSpan(0, 0, 0, 0, 350);
sre.InitialSilenceTimeout = new TimeSpan(0, 0, 0, 0, 2000);

Définition de la source audio à utiliser

Pour définir le flux audio à analyser, il existe plusieurs méthodes. La première conciste à utiliser le flux du périphérique de capture audio par défaut (le micro) avec la méthode SetInputToDefaultAudioDevice. La seconde, est d'analyser un fichier wav via SetInputToWaveFile et la dernière l'utilisation directe d'un flux tierce grâce à la méthode SetInputToAudioStream.

sre.SetInputToDefaultAudioDevice();

Création des règles qui définiront la sémantique de la grammaire.

Pour créer un système répondant à la problématique la plus commune à savoir, une ou plusieurs phrases sont égales à une commande. Dans l'exemple suivant nous allons créer deux commandes "navigateur" et "internet" qui retournerons la commande "cmd_browser". En les affiliants à la règle sémantique "rule".

SrgsDocument commands = new SrgsDocument();
commands.PhoneticAlphabet = SrgsPhoneticAlphabet.Ipa;
commands.Mode = SrgsGrammarMode.Voice;
commands.Culture = this._culture_info;

//Génère la commande racine
SrgsRule master_rule = new SrgsRule("rule");
master_rule.Scope = SrgsRuleScope.Public;
master_rule.Add(SrgsRuleRef.Garbage);

SrgsOneOf master_altenates = new SrgsOneOf();

//Génère les phrases altérnatives pour l'ordre cmd_browser
List<string> list_phrases = new List<string>(){ "navigateur","internet" };
string script = String.Format("out.rule={{}}; out.rule._value={1}{0}{1};", "cmd_browser", (char)34);
foreach (string order in list_phrases)
{
	SrgsItem srgs_item = new SrgsItem(text);
	srgs_item.Add(new SrgsSemanticInterpretationTag(script));
	master_altenates.Add(srgs_item);
}

master_rule.Add(master_altenates);

//Définition de la règle de référence
commands.Rules.Add(master_rule);
commands.Root = master_rule;


//Assigne la grammaire spécifique
Grammar grm = new Grammar(commands);
grm.Name = "mon_contexte";

//Charge la grammaire 
sre.LoadGrammarAsync(grm);
//Rajoute la grammaire native du système
sre.LoadGrammar(new DictationGrammar());
string srgsDocumentFile = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "srgsDocumentFile.xml");
System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(srgsDocumentFile);
commands.WriteSrgs(writer);
writer.Close();
Usage synchrone de la reconnaissance vocale avec recognize

Il est possible de définir une reconnaissance vocale synchrone grâce à la méthode recognize. Cette méthode bloque le flux d'appel du thread, tant que l'interprétation n'est pas terminée par un appel à l'événement de succès ou d'échec. Cette méthode est recommandée pour un usage de traitement de document à analyser dans une file d'attente.

sre.Recognize(RecognizeMode.Single);
Utilisation asynchrone de la reconnaissance vocale avec RecognizeAsynch

L'objet SpeechRecognitionEngine offre également la possibilité d'initialiser une reconnaissance vocale asynchrone grâce à la méthode RecognizeAsynch. Cette méthode est recommandée pour utiliser la reconnaissance vocale en qualité d'interface homme-machine et permettre une détection continue sans bloquer l'application.

Dans les deux cas (Recognize et RecognizeAsynch), le système de reconnaissance vocale attend au moins un paramètre d'entrée une valeur de l'énumération RecognizeMode.

Si défini à RecognizeMode.Single, l'objet SpeechRecognitionEngine déclenche la reconnaissance vocale de manière unitaire. Ce qui aura pour finalité d'arrêter automatiquement le traitement lors de la première interprétation (ou de son échec).

sre.RecognizeAsync(RecognizeMode.Single);

Si défini à RecognizeMode.Multiple, l'objet SpeechRecognitionEngine initialise une reconnaissance vocale de manière multiple. Ce paramétrage permet d'effectuer des analyses continues, les unes à la suite des autres, sans arrêter le traitement.

sre.RecognizeAsync(RecognizeMode.Multiple);
Gestion des événements de reconnaissance vocale

Les événements sont au nombre de trois SpeechDetected, SpeechRecognitionRejected et SpeechRecognized.

//Association des événements 
sre.SpeechDetected += speech_detected;
sre.SpeechRecognitionRejected += speech_rejected;
sre.SpeechRecognized += speech_recognized;

//Démarrage de la reconnaissance vocale 
sre.RecognizeAsync(RecognizeMode.Multiple);
SpeechDetected - détéction d'une parole

Le premier événement, SpeechDetected est déclenchée lors de la détection d'une parole (hors bruit blanc). Dans le cadre d'une interface homme-machine, cet événement est intéressant, et il est parfaitement envisageable de concevoir un overlay qui viendrait prévenir l'utilisateur que la reconnaissance vocale à débuté.

private void speech_detected(object sender, SpeechDetectedEventArgs e)
{

}
SpeechRecognitionRejected - interprétation impossible

Le second événement, SpeechRecognitionRejected est déclenchée lors d'une impossibilité à interpréter la phrase prononcée par rapport aux règles de grammaire sémantiques fournies lors de l'initialisation de l'objet SpeechRecognitionEngine.

 private void speech_rejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
	try
	{
		//RecognizedAudio audio = e.Result.Audio;
	}
	catch (Exception)
	{
		throw;
	}
}
SpeechRecognized - interprétation réussie

Le dernier événement, SpeechRecognized est appelé lors d'une réussite d'interprétation de la phrase prononcée, en tenant compte des règles de grammaire sémantiques. Le paramètre SpeechRecognizedEventArgs contient plusieurs informations très utiles pour la suite. La liste des résultats d'interprétations, accessibles via leurs index.

Pour savoir si le résultat d'interprétation d'une règle sémantique existe : e.Result.Semantics.ContainsKey("rule")

Pour collecter la commande lié au résultat d'interprétation de cette même règle : e.Result.Semantics["rule"].Value.ToString()

Pour obtenir le résultat d'interprétation : e.Result.Text

Pour connaître le niveau de certitude dans la détection : e.Result.Confidence

private void speech_recognized(object sender, SpeechRecognizedEventArgs e)
{
	try
	{
		//Si internet ou navigateur 
		string phrase = in_event.Result.Text;
		
		//Si bien prononcé entre 0.5 et 0.98 sinons inférieur à 0.5
		float confidence = in_event.Result.Confidence;
		
		//Si correspondant on peu s'attendre à "cmd_browser"
		String key = in_event.Result.Semantics.ContainsKey("rule") ? in_event.Result.Semantics["rule"].Value.ToString() : String.Empty;
	
		//Faire quelque chose avec cette commande... 
	}
	catch (Exception ex)
	{
		throw; 
	}
}
Arrêt d'un traitement asynchrone avec RecognizeAsynchStop

Pour arrêter un traitement asynchrone de reconnaissance vocale initialisée en mode multiple, il suffira de compléter avec là méthode RecognizeAsynchStop.

sre.RecognizeAsyncStop();