Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Tell me how much - Form2.vb

Form2.vb

Caricato da: Totem
Scarica il programma completo

  1. Imports System.Speech
  2. Imports System.Speech.Recognition
  3. Imports System.Speech.Synthesis
  4.  
  5. Public Class Form2
  6.     'Nuovo Engine di riconoscimento vocale
  7.     Private Engine As New SpeechRecognitionEngine
  8.     'GrammarBuilder per costruire la grammatica
  9.     Private GrammarBuilder As New GrammarBuilder
  10.     'Oggetto Grammar che rappresenta la grammatica
  11.     Private Grammar As Grammar
  12.  
  13.     'Questo dizionario associa ad ogni parola il
  14.     'corrispondente valore numerico (one=1)
  15.     Private TextNumber As Dictionary(Of String, Int32)
  16.     'Questo array già inizializzato contiene l'elenco di
  17.     'tutte le parole che l'engine può rilevare
  18.     Private Numbers As String() = _
  19.         New String() {"one", "two", "three", "four", _
  20.         "five", "six", "seven", "eight", "nine", "ten", _
  21.         "eleven", "twelve", "thirteen", "fourteen", _
  22.         "fiftheen", "sixteen", "seventeen", "eighteen", _
  23.         "nineteen", "twenty", "thirty", "fourty", "fifty", _
  24.         "sixty", "seventy", "eighty", "ninty", "hundred", _
  25.         "thousand", "reset"}
  26.     'L'ultima parola, reset, serve per porre a 0 il
  27.     'conteggio, nel caso si volesse ripetere
  28.  
  29.     'Delegato che servirà dopo
  30.     Private Delegate Sub SetLabel(ByVal Res As RecognitionResult)
  31.     'Prev ricorda l'ultimo numero immesso
  32.     Private Prev As Int32
  33.     'Result contiene il numero finale
  34.     Private Result As Int32
  35.  
  36.     Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  37.         'All'avvio del form, si imposta l'input dell'engine sul
  38.         'normale microfono (che deve essere collegato al computer).
  39.         'Anche in questo caso si usa un thread, per lo stesso
  40.         'motivo citato nel capitolo precedente
  41.         Dim T As New Threading.Thread(AddressOf Engine.SetInputToDefaultAudioDevice)
  42.         T.Start()
  43.         T.Join()
  44.  
  45.         'Poi si genera il dizionario che associa le parole ai
  46.         'valori numerici veri e propri. Dato che l'array
  47.         'Numbers contiene i numeri in ordine, sfruttermo
  48.         'qualche for per riempire il dizionario in poche
  49.         'righe di codice
  50.         TextNumber = New Dictionary(Of String, Int32)
  51.         With TextNumber
  52.             'I primi 20 numeri sono in ordine crescente,
  53.             'da 1 a 20. Perciò basta aggiungere 1
  54.             'all'indice I per ottenere il numero che la
  55.             'parola indica
  56.             For I As Int16 = 0 To 19
  57.                 .Add(Numbers(I), I + 1)
  58.             Next
  59.             'I successivi sette numeri sono tutti i multipli
  60.             'di 10, da 30 a 90. Con la formula:
  61.             '(I-19)*10 + 20
  62.             '` come se I andasse da 1 a 7 e quindi
  63.             'otteniamo tutte le decine da 20+10 a 20+70
  64.             For I As Int16 = 20 To 26
  65.                 .Add(Numbers(I), (I - 19) * 10 + 20)
  66.             Next
  67.             'Infine si aggiungono centinaia e migliaia a parte
  68.             .Add("hundred", 100)
  69.             .Add("thousand", 1000)
  70.         End With
  71.  
  72.         'Aggiunge tutte le parole-numero al GrammarBuilder
  73.         GrammarBuilder.Append(New Choices(Numbers))
  74.         'Imposta la lingua a inglese
  75.         GrammarBuilder.Culture = Globalization.CultureInfo.GetCultureInfo("en-US")
  76.         'Costruisce la nuova "grammatica" con il GrammarBuilder
  77.         Grammar = New Grammar(GrammarBuilder)
  78.  
  79.         'Questo metodo serve per eliminare tutte le grammatiche
  80.         'già presenti. Anche se quasi sicuramente non ci
  81.         'sarà nessun grammatica precaricata, è sempre
  82.         'meglio farlo prima di aggiungerne di nuove
  83.         Engine.UnloadAllGrammars()
  84.         'Quindi carica la grammatica Grammar. Ora Engine è in
  85.         'grado di riconoscere le parole dell'array Numbers
  86.         Engine.LoadGrammar(Grammar)
  87.         'Parte importantissima: aggiunge l'handler di evento per
  88.         'l'evento SpeechRecognized, che viene lanciato quando
  89.         'l'engine ha ascoltato la voce, l'ha analizzata e ha
  90.         'trovato una corrispondenza valida nella sua grammatica
  91.         AddHandler Engine.SpeechRecognized, AddressOf Speech_Recognized
  92.     End Sub
  93.  
  94.     Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
  95.         'Fa partire il riconoscimento vocale. Il metodo è asincrono,
  96.         'quindi viene eseguito su un altro thread e non blocca il form
  97.         'chiamante. L'argomento Multiple indica che si effetteranno più
  98.         'riconoscimenti e non uno solo
  99.         Engine.RecognizeAsync(RecognizeMode.Multiple)
  100.  
  101.         'Disabilita Start e abilita Stop
  102.         btnStart.Enabled = False
  103.         btnStop.Enabled = True
  104.     End Sub
  105.  
  106.     Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
  107.         'Termina il riconoscimento asincrono
  108.         Engine.RecognizeAsyncCancel()
  109.  
  110.         'Abilita Start e disabilita Stop
  111.         btnStart.Enabled = True
  112.         btnStop.Enabled = False
  113.     End Sub
  114.  
  115.     Private Sub Speech_Recognized(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)
  116.         'Può capitare che dopo l'esecuzione di questo evento,
  117.         'sia generata un'eccezione TargetInvocationException, causata
  118.         'dall'engine, il quale lancia un evento uguale prima che
  119.         'questo sia terminato. Usando un thread risolviamo tutto
  120.         Dim T As New Threading.Thread(AddressOf InvokeSetLabel)
  121.         T.Start(e.Result)
  122.     End Sub
  123.  
  124.     Private Sub InvokeSetLabel(ByVal Res As RecognitionResult)
  125.         'Ovviamente questi stupido tipo di errori ci fa usare
  126.         'una via alternativa sprecando molto codice in più.
  127.         'Dato che, come sapete, non si può accedere ai
  128.         'controlli di un form da un thread differente da quello
  129.         'in cui sono stati creati, dobbiamo usare Invoke
  130.         'per far eseguire lo stesso compito al thread principale
  131.         'partendo da questo thread secondario.
  132.         'Per chi non si ricorda i delegate, Invoke permette di
  133.         'far correre un metodo nel thread dell'oggetto da cui è
  134.         'richiamato (Me, ossia il form). In questo caso usiamo
  135.         'il delegato di tipo SetLabel che punta ad AnalyuzeText
  136.         'e gli passiamo dierettamente Res come parametro
  137.         Me.Invoke(New SetLabel(AddressOf AnalyzeText), New Object() {Res})
  138.     End Sub
  139.  
  140.     Private Sub AnalyzeText(ByVal Res As RecognitionResult)
  141.         Dim N As Int32
  142.         'Ottiene il testo, ossia la parola pronunciata
  143.         Dim Text As String = Res.Text
  144.  
  145.         'Se il testo è "reset", annulla tutto
  146.         If Text = "reset" Then
  147.             Result = 0
  148.         End If
  149.  
  150.         'Se il testo è contenuto nel dizionario, allora
  151.         'è un numero valido
  152.         If TextNumber.ContainsKey(Text) Then
  153.             'Ottiene il numero
  154.             N = TextNumber(Text)
  155.             'Se è 100, significa che si è pronunciato
  156.             '"hundred". Hundred indica le centinaia e perciò
  157.             'sicuramente non si può dire "twenty hundred", né
  158.             '"one thousand hundred": l'unico caso in cui si può
  159.             'usare hundred è dopo una singola cifra, ad esempio
  160.             '"one hundred" o "nine hundred". Quindi controlla che il
  161.             'numero precedente sia compreso tra 1 e 9
  162.             If (N = 100) And (Prev > 0 And Prev < 10) Then
  163.                 'Togli l'unità
  164.                 Result -= Prev
  165.                 'E la trasforma in centinaia
  166.                 Result += Prev * 100
  167.             End If
  168.             'Parimenti, si può usare "thousand" solo dopo un
  169.             'numero minore di mille. Anche se lecito, nessuno direbbe
  170.             '"a thousand thousand", ma piuttosto "a million"
  171.             If (N = 1000) And (Result < 1000) Then
  172.                 Result *= 1000
  173.             End If
  174.             'Se il numero è minore di 100, semplicemente lo
  175.             'aggiunge. Se quindi si pronunciano "twenty" e "thirty"
  176.             'di seguito, si otterà 50. Non chiedetemi perchè
  177.             'l'ho fatto così...
  178.             If (N < 100) Then
  179.                 Result += N
  180.             End If
  181.         Else
  182.             N = 0
  183.         End If
  184.  
  185.         Prev = N
  186.  
  187.         'Imposta il testo della label
  188.         lblNumber.Text = String.Format("{0:N0}", Result)
  189.     End Sub
  190. End Class