[Windows] Serveur UDP de reconnaissance vocale.

Questions à propos de la partie audio, y compris les problèmes de script s'y rapportant.
Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

[Windows] Serveur UDP de reconnaissance vocale.

Message par ZJP » 04 Mars 2013 17:44

Salut,

Une petite application de mon cru qui permet la reconnaissance vocale à partir d'un fichier grammatical ("grammar.txt" qui devra être dans le même répertoire que le serveur). La latence de transmission est d'une seconde. Difficile de mieux faire.

L'application utilise l'API de Windows. Cela fonctionne sous VISTA 32/64, Win7 32/64 et supérieur . Pour XP, il faudra vraisemblablement installer des librairies complémentaires. Cette solution ne nécessite donc pas Windows 10 et Unity 5.5+ pour la reconnaissance vocale intégrée.

Le serveur est multi-langue. Il utilise par défaut le "langage" installé sur le système. Bien entendu, la grammaire utilisée doit être en adéquation avec celui-ci.


Syntaxe du fichier de configuration/Grammaire.


# >> Pour ajouter un commentaire.
#I >> L'IP du serveur. 127.0.0.1 si le serveur est sur la même machine que le client.
#P >> Port UDP.
#C >> (CLOSE) Mot "magique" qui prononcé arrête le serveur. Bien sur, il est possible de le stopper manuellement. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#S >> (START) Activation de la reconnaissance, donc l'envoi des mots via UDP. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#E >> (END) Désactivation de la reconnaissance. Rien n'est envoyé via UDP. Ce mot doit être présent dans la grammaire (fichier "grammar.txt").
#N >> Ajout d'un "Retour Chariot/New Line" -CHR(13)- à la fin du mot envoyé.
#D >> Display/Affichage de tout le blabla dans la console du serveur.
#V >> Degré de Validation de la reconnaissance. 0 à 100%. 70 est un bon chiffre. A expérimenter en fonction du locuteur.


Exemple de grammar.txt

Code : Tout sélectionner

# comment
#P 26000
#I 127.0.0.1
#C Terminer
#N
#S Ouverture
#E Fermeture
#V 70
#D

Merci
Au revoir
Terminer
zéro
un
deux
trois
quatre
cinq
six
sept
huit
neuf
dix
Patrick
Denis
Albert
Jean
Paul
Antoine
Bonjour
Salut
Il fait beau
Matin
Chien
Cheval
Chat
Cochon
Ordinateur
Il fait beau ce matin
Parfait
Ouverture
Fermeture
Le petit chaperon rouge
Unity
Le ciel est bleu et le soleil brille
Gauche
Droite
Haut
Bas
Saute
Tir
1984
2012
1962
1504
2013
22
33
11
Le source Unity qui permet la récupération du mot détecté. A coller sur un GameObject

Code : Tout sélectionner

// **************************************************************************
//                                                     UDP SPEECH RECOGNITION
// **************************************************************************
using System;
using System.Net;
using System.Text;
using UnityEngine;
using System.Threading;
using System.Net.Sockets;
using System.Collections;

public class UDP_RecoServer : MonoBehaviour 
{
	Thread receiveThread;
	UdpClient client;
	public int port = 26000; // DEFAULT UDP PORT !!!!! THE QUAKE ONE ;)
	string strReceiveUDP = "";

	public void Start()	
	{
		Application.runInBackground = true;
		receiveThread = new Thread( new ThreadStart(ReceiveData));
		receiveThread.IsBackground = true;
		receiveThread.Priority     = System.Threading.ThreadPriority.BelowNormal; // AboveNormal, BelowNormal, Normal, Highest, Lowest, Normal
		receiveThread.Start();
	}

	private  void ReceiveData()	
	{
		client = new UdpClient(port);
		while (true) 
		{
			try	
			{
				IPEndPoint anyIP = new IPEndPoint(IPAddress.Broadcast, port);
				byte[] data = client.Receive(ref anyIP);
				strReceiveUDP = Encoding.UTF8.GetString(data);
				// **********************************************************
				Action(strReceiveUDP);
				// **********************************************************
			}
			catch (Exception err) 
			{
				print(err.ToString());
			}
		}
	}

	public void Action(string recoReceive) 
	{
		Debug.Log(recoReceive);
		if (recoReceive == "bonjour") Debug.Log("J'ai recu un bonjour du serveur");
		// etc etc etc ...
	}

	void OnDisable() 
	{
		if ( receiveThread != null) receiveThread.Abort();
		client.Close();
	}
}
// **************************************************************************
//                                                     UDP SPEECH RECOGNITION
// **************************************************************************
JP

Edit :

Cela fonctionne avec les chiffres. Sympa. 8-)

Edit 2 :

Informations complémentaires.
ZJP a écrit : C'est une application (EXE) qui fonctionne sous Windows. Elle s’appuie sur le module de reconnaissance vocale intégré dans l'OS.
Pour un fonctionnement correct, il faut :

a) Effectuer la phase de configuration sous Windows. Apprentissage etc.....
b) Entrez dans un fichier (grammar.txt) la liste des mots (ou phrases) a reconnaitre. Cette liste peut bien sur être modifiée/corrigée à tout instant.

Une fois cela fait, le programme envoie via UDP (réseau) le mot (ou la phrase) reconnu(e). La réception de ce mot est donc possible sous n'importe quelle application (Unity ou pas) dotée d'une connexion réseau. Bien évidemment, le serveur et l'application de "réception" peuvent être sur la même machine (IP 127.0.0.1).
Tout ce qui est nécessaire au bon fonctionnement est résumé dans ce post.....

Source...

Code : Tout sélectionner

// **************************************************************************************************************************
//                                                                                             RecoServer UDP Version (c) ZJP
// Free Stuff.***************************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Speech.Recognition;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace RecoServeur
{
	class Program
	{
		public static SpeechRecognitionEngine speechRecognitionEngine;

		public static string wordRecognized  = "";

        public static string endApp     = "Terminer";
        public static string startReco  = "Ouverture";
        public static string endReco    = "Fermeture";

        public static string newLine    = "";

		public static string ipServer  = "127.0.0.1";
		public static byte[] data = new byte[512];
		public static int port = 26000;
		public static double validity = 0.70f;

        public static Boolean isReco    = false;
        public static Boolean isDisplay = false;
		
		public static Socket server;
		public static IPEndPoint iep;


		public static void Main(string[] args)
		{

			speechRecognitionEngine = new SpeechRecognitionEngine(SpeechRecognitionEngine.InstalledRecognizers()[0]);
			try
			{
				// create the engine
				// hook to events
			//	speechRecognitionEngine.AudioLevelUpdated += new EventHandler<AudioLevelUpdatedEventArgs>(engine_AudioLevelUpdated);
				speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(engine_SpeechRecognized);

				// load dictionary
				try
				{
					Choices MyVocabulary = new Choices();

					string[] lines = File.ReadAllLines(Environment.CurrentDirectory + "\\grammar.txt");
					foreach (string line in lines)
					{
						
						//reco UDP Port
						if (line.StartsWith("#P"))
						{
							var parts = line.Split(new char[] { ' ' });
							port = Convert.ToInt32(parts[1]);
							Console.WriteLine("Port : " + parts[1]);
							continue;
						}
						// Reco IP server
						if (line.StartsWith("#I"))
						{
							var parts = line.Split(new char[] { ' ' });
							ipServer = parts[1];
							Console.WriteLine("ipServer : " + parts[1]);
							continue;
						}
						
						// Reco endApp
						if (line.StartsWith("#C"))
						{
							var parts = line.Split(new char[] { ' ' });
							endApp = parts[1];
							Console.WriteLine("Close Application Word : " + parts[1]);
							continue;
						}

                        // Reco startReco
                        if (line.StartsWith("#S"))
                        {
                            var parts = line.Split(new char[] { ' ' });
                            startReco = parts[1];
                            Console.WriteLine("Start Recognition Word : " + parts[1]);
                            continue;
                        }

                        // Reco endReco
                        if (line.StartsWith("#E"))
                        {
                            var parts = line.Split(new char[] { ' ' });
                            endReco = parts[1];
                            Console.WriteLine("End Recognition Word : " + parts[1]);
                            continue;
                        }

                        // Reco validity
                        if (line.StartsWith("#V"))
                        {
                            var parts = line.Split(new char[] { ' ' });
                            validity = Convert.ToInt32(parts[1]) / 100.0f;
                            Console.WriteLine("Validity : " + parts[1]);
                            continue;
                        }

                        // Add NewLine Char after the reco word
                        if (line.StartsWith("#N"))
                        {
                            newLine = "\n";
                            Console.WriteLine("Add NewLine On....");
                            continue;
                        }                        
                        
                        // Display Reco
                        if (line.StartsWith("#D"))
                        {
                            isDisplay = true;
                            Console.WriteLine("Display (Verbose) on...");
                            continue;
                        }

						// skip comments and empty lines..
						if (line.StartsWith("#") || line == String.Empty) continue;

                        // the recognition grammar
                        MyVocabulary.Add(line);

                    } // foreach grammar.txt
					Grammar wordsList = new Grammar(new GrammarBuilder(MyVocabulary));
					speechRecognitionEngine.LoadGrammar(wordsList);
				}
				catch (Exception ex)
				{
					throw ex;
					System.Environment.Exit(0);
				}

				// use the system's default microphone
				speechRecognitionEngine.SetInputToDefaultAudioDevice();
				// start listening
				speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);
			}
			catch (Exception ex)
			{
				speechRecognitionEngine.RecognizeAsyncStop();
                speechRecognitionEngine.Dispose();

                System.Windows.Forms.MessageBox.Show( ex.Message + "\n\nSeem we have an error here : \n\na) Do you have connected a MicroPhone ?! \nb) Have you forgot the 'grammar.txt' file ?!!");
                // exit
				System.Environment.Exit(0);
			}
			// UDP init
			server  = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
			iep = new IPEndPoint(IPAddress.Parse(ipServer), port);
			// Ready
			Console.WriteLine("Reco Server Ready.....");

			while (true)
			{
				Thread.Sleep(10);
			}

		} // main
/*
		public static  void engine_AudioLevelUpdated(object sender, AudioLevelUpdatedEventArgs e)
		{
			Console.WriteLine(e.AudioLevel);
		}
*/
		public static void engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
		{
			if (e.Result.Confidence >= validity)
			{
                wordRecognized = e.Result.Text;
                // activate the sending reco.
                if (wordRecognized == startReco)
                {
                    isReco = true;
                    Console.Title = wordRecognized;
                    Console.BackgroundColor = ConsoleColor.Green;
                    Console.WriteLine("** Sending words is ENABLE **");
                    return;
                }
                // de-activate the sending reco.
                if (wordRecognized == endReco)
                {
                    isReco = false;
                    Console.Title = wordRecognized;
                    Console.BackgroundColor = ConsoleColor.Red;
                    Console.WriteLine("** Sending words is DISABLE **");
                    return;
                }
                // Use the word
                if (isReco)
                {
                    Console.Title = wordRecognized;
					data = Encoding.ASCII.GetBytes(wordRecognized + newLine);
					server.SendTo(data, iep);
                    if (isDisplay) Console.WriteLine("Sending this : " + wordRecognized);
					// End of app
                    if (wordRecognized == endApp)
                    {
                        speechRecognitionEngine.RecognizeAsyncStop();
                        speechRecognitionEngine.Dispose();
                        System.Environment.Exit(0);
                    } else return;
                }
			}
		}

	} // Program
} // RecoServeur
// End source
// **************************************************************************************************************************
//                                                                                             RecoServer UDP Version (c) ZJP
// Free Stuff.***************************************************************************************************************
Source du projet (Visual Studio 2010) en pièce jointe.
Le fichier solution (.sln) peut être ouvert et le projet se "compile" sous MonoDevelop sans aucun problème. 8-)

Edit :

SharedMemory version.

Code : Tout sélectionner

// *******************************************************************************************************************************************
//                                                                                             RecoServer Shared Array Version Version (c) ZJP
// Free Stuff.********************************************************************************************************************************
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Speech.Recognition;
using System.Threading;
using System.Diagnostics;
// Share Memory Buffer +++++++++++++++++++
// https://sharedmemory.codeplex.com/
using SharedMemory;
// Share Memory Buffer +++++++++++++++++++

namespace RecoServeur
{
	class Program
	{
		public static SpeechRecognitionEngine speechRecognitionEngine;

		public static string wordRecognized  = "";
		public static string[] ListOfWord;
		public static int nbWord = 0;
		public static bool SendWordIndex = false;

		// Share Memory Buffer +++++++++++++++++++
		public static SharedArray<Byte> serverIPC;
		public static byte[] data = new byte[256];
		// Share Memory Buffer +++++++++++++++++++

		public static void Main(string[] args)	{

			speechRecognitionEngine = new SpeechRecognitionEngine(SpeechRecognitionEngine.InstalledRecognizers()[0]);
			try	{
				// create the engine and  hook to events
				speechRecognitionEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(engine_SpeechRecognized);

				// load dictionary
				try	{
					Choices MyVocabulary = new Choices();
					ListOfWord = new string[256];
					string[] lines = File.ReadAllLines(Environment.CurrentDirectory + "\\grammar.txt");
					foreach (string line in lines) {
						if (line.StartsWith("#INDEX")){
							SendWordIndex = true; 
							continue;
						}
						if (line.StartsWith("#") || line == String.Empty) continue;

						// the recognition grammar
						MyVocabulary.Add(line);
						ListOfWord[nbWord] = line;
						nbWord++;

					} // foreach grammar.txt
					Grammar wordsList = new Grammar(new GrammarBuilder(MyVocabulary));
					speechRecognitionEngine.LoadGrammar(wordsList);
				}
				catch (Exception ex){
					throw ex;
					System.Environment.Exit(0);
				}

				// use the system's default microphone
				speechRecognitionEngine.SetInputToDefaultAudioDevice();
				// start listening
				speechRecognitionEngine.RecognizeAsync(RecognizeMode.Multiple);
			}
			catch (Exception ex) {
				speechRecognitionEngine.RecognizeAsyncStop();
				speechRecognitionEngine.Dispose();

				System.Windows.Forms.MessageBox.Show( ex.Message + "\n\nSeem we have an error here : \n\na) Do you have connected a MicroPhone ?! \nb) Have you forgot the 'grammar.txt' file ?!!");
				// exit
				System.Environment.Exit(0);
			}

			// Share Memory Buffer +++++++++++++++++++++++++++++++++++
			serverIPC = new SharedArray<byte>("WordSharedArray", 256);
			serverIPC[0] = 0; // No Word in the buffer !!!
			// Share Memory Buffer +++++++++++++++++++++++++++++++++++

			// Ready
			Console.BackgroundColor = ConsoleColor.Red;
			Console.WriteLine("Reco Server Ready.....");
			Console.Title = "Reco Server Ready.....";
			Console.BackgroundColor = ConsoleColor.Black;

			while (true) {
				Thread.Sleep(10);
			}

		} // main

		public static void engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) {
			if (e.Result.Confidence >= 0.70f) {
				wordRecognized = e.Result.Text;
				Console.WriteLine ("Sending : " + wordRecognized);
				Console.Title = wordRecognized;
				if (SendWordIndex) {
					// Put the Word index in the Shared array ++++++++++++++++++++++++++++++++++++++++++
					serverIPC[0] = 0;
					for (int i = 0; i < nbWord; i++) {	
						if (ListOfWord[i] == wordRecognized)
						{
							serverIPC[0] = (Byte)(i + 1); // New Word index in the Buffer !!!
							return;
						}
					}
					// Put the Word index in the Shared array ++++++++++++++++++++++++++++++++++++++++++
				} else {
					// Put the Word in the Shared array ++++++++++++++++++++++++++++++++++++++++++
					data = Encoding.ASCII.GetBytes(wordRecognized);
					for (int i = 0; i < data.Length; i++) {	
						serverIPC [i + 2] = data[i];
					}
					serverIPC[1] = (Byte)data.Length; 
					serverIPC[0] = 1; // New Word in the Buffer !!!
					// Put the Word in the Shared array ++++++++++++++++++++++++++++++++++++++++++
				}

			}
		}

	} // Program
} // RecoServeur
// End source
// *******************************************************************************************************************************************
//                                                                                             RecoServer Shared Array Version Version (c) ZJP
// Free Stuff.********************************************************************************************************************************

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

// Share Memory Buffer ++++++++++++++++++++++
// https://sharedmemory.codeplex.com/
// Add 'SharedMemory.dll' in a Plugins folder
using SharedMemory;
// Share Memory Buffer ++++++++++++++++++++++

public class WordShared : MonoBehaviour {

	SharedArray<byte> clientIPC;
	private bool sArray;
	public bool WordIndexMode = false;


	void Start () {
		
		Debug.Log("SharedMemory Client");
		sArray = true;
		try  {
			clientIPC = new SharedArray<byte>("WordSharedArray"); // ouverture du buffer
        }
        catch (FileNotFoundException ex) {
			sArray = false;
        }

	}

	void FixedUpdate()
	{
		if (!sArray) return;
		if (!clientIPC.ShuttingDown) 
		{

			if (WordIndexMode) {
				if (clientIPC[0] > 0) // New Index Word in the Buffer ???
				{
					Debug.Log("New Index Word is coming !!! : " + clientIPC[0] );
					clientIPC[0] = 0; // I got the Index Word. Put a new one.
					return;
				}
			} else {
				if (clientIPC[0] == 1) // New Word in the Buffer ???
				{
					// Yes
					string response = string.Empty;
					for (int i = 0; i < clientIPC[1]; i++) {	
						response += (char)clientIPC[i + 2];
					}
					clientIPC[0] = 0; // I got the Word. Put a new one.
					Debug.Log("New Word is coming !!! : " + response );
					return;
				}				
			}

		}
	}
}

Pièces jointes
RecoServeur_project.rar
(45.08 Kio) Téléchargé 253 fois
Dernière édition par ZJP le 30 Mai 2017 20:53, édité 25 fois.

Avatar de l’utilisateur
Freelax
Messages : 1595
Inscription : 30 Déc 2009 23:02
Localisation : Niort
Contact :

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par Freelax » 04 Mars 2013 19:07

Excellent! :D

Je test ça ce soir :D
Image


Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par ZJP » 07 Mars 2013 21:05

Non, avec ..déc..ibels. Ça fonctionne mieux. ;)
Heu, pour le Japonnais, j'ai un doute. :mrgreen:

pimouss
Messages : 5
Inscription : 12 Juin 2013 10:46

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par pimouss » 12 Juin 2013 15:03

bonjour,

j'aimerais savoir comment se fait la connexion entre le fichier grammar.txt et le code source d'unity?
Dernière édition par pimouss le 12 Juin 2013 16:06, édité 1 fois.

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par ZJP » 12 Juin 2013 15:13

Salut,

Le fichier "grammar.txt" est ouvert par l'application serveur. D’où son placement dans le même répertoire que celui-ci.
Liaison du serveur et Unity via une connexion UDP.
Dernière édition par ZJP le 23 Mars 2017 15:44, édité 2 fois.

Avatar de l’utilisateur
Freelax
Messages : 1595
Inscription : 30 Déc 2009 23:02
Localisation : Niort
Contact :

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par Freelax » 12 Juin 2013 21:13

J'ai testé ton truc, c'est marrant :D Je voi bien un login à reco vocal perso :lol:
Image

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par ZJP » 12 Juin 2013 22:58

Freelax a écrit :J'ai testé ton truc, c'est marrant :D Je voi bien un login à reco vocal perso :lol:
Merci. Je reste bluffé par la qualité du moteur de Windows.
Je pense utiliser ce projet pour Moon : Le HUD risque d'être surchargé. :?

pimouss
Messages : 5
Inscription : 12 Juin 2013 10:46

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par pimouss » 13 Juin 2013 09:35

Merci ZJP pour ces informations.
Je comprends mieux comment se passe la connexion entre les deux.
Mais ça n'a pas résolut mon problème, je suis débutant en programmation et j'ai passé plusieurs jours la dessus mais sans succès.
J'aimerai avec la reconnaissance vocale faire une action précise quand le mot récupéré est jean, et faire une autre action pour chaque mot de la liste. Quelqu'un aurait une idée pour faire cela?

Avatar de l’utilisateur
ZJP
Messages : 5745
Inscription : 15 Déc 2009 06:00

Re: [Windows] Serveur UDP de reconnaissance vocale.

Message par ZJP » 13 Juin 2013 18:21

Le mot reconnu est placé dans la variable

Code : Tout sélectionner

strReceiveUDP
dans le source Unity. La suite est une...suite de décisions a prendre en fonction de ce mot, soit :
a) Une cascade de "if" ou "case" décisionnels.
b) Déclarer la variable "Public" et l'exploiter dans un autre process (?)
c) Utiliser un 'SendMessage'
d) etc...
pimouss a écrit :Mais ça n'a pas résolut mon problème, je suis débutant en programmation...
:oops: C'est presque demander à quelqu’un de te faire ton application, car la liste de solutions précédemment énumérées reste le B.A. BA.
Je veux dire que l'unique but (il s'en acquitte presque que parfaitement) de cet "outil" est de fournir une information, une variable. Si tu ne sais pas comment utiliser celle ci dans ton projet, c'est....la cata!!!
pimouss a écrit :...et faire une autre action pour chaque mot de la liste. Quelqu'un aurait une idée pour faire cela?
Bouger un cube? changer une couleur? ouvrir une porte? lancer une animation? jouer un son?..etc.. Bref, si tu ne sais pas "coder l'action" que tu désires, reconnaissance vocale ou pas le problème reste entier car ton "ordre" pourrait tout aussi bien provenir d'une saisie au clavier.

Répondre

Revenir vers « Audio, musique et sons »