using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Speech;
using System.Speech.Recognition;
using System.Speech.Synthesis;
namespace Talk
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private SpeechRecognitionEngine Engine = new SpeechRecognitionEngine();
//GrammarBuilder per costruire la grammatica
private GrammarBuilder GrammarBuilder = new GrammarBuilder();
//Oggetto Grammar che rappresenta la grammatica
private Grammar Grammar;
//Questo dizionario associa ad ogni parola il
//corrispondente valore numerico (one=1)
private Dictionary<string, Int32> TextNumber;
//Questo array già inizializzato contiene l'elenco di
//tutte le parole che l'engine può rilevare
private string[] Numbers = new string[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fiftheen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninty", "hundred", "thousand", "reset" };
//L'ultima parola, reset, serve per porre a 0 il
//conteggio, nel caso si volesse ripetere
//Prev ricorda l'ultimo numero immesso
private Int32 Prev;
//Result contiene il numero finale
private Int32 Result;
private void Form2_Load(object sender, EventArgs e)
{
//All'avvio del form, si imposta l'input dell'engine sul
//normale microfono (che deve essere collegato al computer).
//Anche in questo caso si usa un thread, per lo stesso
//motivo citato nel capitolo precedente
System.Threading.Thread T = new System.Threading.Thread(Engine.SetInputToDefaultAudioDevice);
T.Start();
T.Join();
//Poi si genera il dizionario che associa le parole ai
//valori numerici veri e propri. Dato che l'array
//Numbers contiene i numeri in ordine, sfruttermo
//qualche for per riempire il dizionario in poche
//righe di codice
TextNumber = new Dictionary<string, Int32>();
//I primi 20 numeri sono in ordine crescente,
//da 1 a 20. Perciò basta aggiungere 1
//all'indice I per ottenere il numero che la
//parola indica
for (Int16 I = 0; I <= 19; I++)
{
TextNumber.Add(Numbers[I], I + 1);
}
//I successivi sette numeri sono tutti i multipli
//di 10, da 30 a 90. Con la formula:
//(I-19)*10 + 20
//è come se I andasse da 1 a 7 e quindi
//otteniamo tutte le decine da 20+10 a 20+70
for (Int16 I = 20; I <= 26; I++)
{
TextNumber.Add(Numbers[I], (I - 19) * 10 + 20);
}
//Infine si aggiungono centinaia e migliaia a parte
TextNumber.Add("hundred", 100);
TextNumber.Add("thousand", 1000);
//Aggiunge tutte le parole-numero al GrammarBuilder
GrammarBuilder.Append(new Choices(Numbers));
//Imposta la lingua a inglese
GrammarBuilder.Culture = System.Globalization.CultureInfo.GetCultureInfo("en-US");
//Costruisce la nuova "grammatica" con il GrammarBuilder
Grammar = new Grammar(GrammarBuilder);
//Questo metodo serve per eliminare tutte le grammatiche
//già presenti. Anche se quasi sicuramente non ci
//sarà nessun grammatica precaricata, è sempre
//meglio farlo prima di aggiungerne di nuove
Engine.UnloadAllGrammars();
//Quindi carica la grammatica Grammar. Ora Engine è in
//grado di riconoscere le parole dell'array Numbers
Engine.LoadGrammar(Grammar);
//Parte importantissima: aggiunge l'handler di evento per
//l'evento SpeechRecognized, che viene lanciato quando
//l'engine ha ascoltato la voce, l'ha analizzata e ha
//trovato una corrispondenza valida nella sua grammatica
Engine.SpeechRecognized += Speech_Recognized;
}
private void btnStart_Click(object sender, EventArgs e)
{
//Fa partire il riconoscimento vocale. Il metodo è asincrono,
//quindi viene eseguito su un altro thread e non blocca il form
//chiamante. L'argomento Multiple indica che si effetteranno più
//riconoscimenti e non uno solo
Engine.RecognizeAsync(RecognizeMode.Multiple);
//Disabilita Start e abilita Stop
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
//Termina il riconoscimento asincrono
Engine.RecognizeAsyncCancel();
//Abilita Start e disabilita Stop
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void Speech_Recognized(object sender, SpeechRecognizedEventArgs e)
{
Int32 N = 0;
//Ottiene il testo, ossia la parola pronunciata
string Text = e.Result.Text;
//Se il testo è "reset", annulla tutto
if (Text == "reset")
{
Result = 0;
}
//Se il testo è contenuto nel dizionario, allora
//è un numero valido
if (TextNumber.ContainsKey(Text))
{
//Ottiene il numero
N = TextNumber[Text];
//Se è 100, significa che si è pronunciato
//"hundred". Hundred indica le centinaia e perciò
//sicuramente non si può dire "twenty hundred", né
//"one thousand hundred": l'unico caso in cui si può
//usare hundred è dopo una singola cifra, ad esempio
//"one hundred" o "nine hundred". Quindi controlla che il
//numero precedente sia compreso tra 1 e 9
if ((N == 100) & (Prev > 0 & Prev < 10))
{
//Toglie l'unità
Result -= Prev;
//E la trasforma in centinaia
Result += Prev * 100;
}
//Parimenti, si può usare "thousand" solo dopo un
//numero minore di mille. Anche se lecito, nessuno direbbe
//"a thousand thousand", ma piuttosto "a million"
if ((N == 1000) & (Result < 1000))
{
Result *= 1000;
}
//Se il numero è minore di 100, semplicemente lo
//aggiunge. Se quindi si pronunciano "twenty" e "thirty"
//di seguito, si otterà 50. Non chiedetemi perchè
//l'ho fatto così...
if (N < 100)
{
Result += N;
}
}
else
{
N = 0;
}
Prev = N;
//Imposta il testo della label
lblNumber.Text = string.Format("{0:N0}", Result);
}
}
}