JavascriptProva

Visualizzazione post con etichetta Visual Basic. Mostra tutti i post
Visualizzazione post con etichetta Visual Basic. Mostra tutti i post

mercoledì 18 luglio 2018

Individuare la posizione di tutti gli spazi di una stringa (ma va bene per qualunque altro carattere o sottostringa)

Una piccola sfida propostami da mio figlio: individuare tutte le parole una per una in una stringa. Per cominciare, ho provato a individuare la posizione degli spazi fra le parole.
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim pos As Integer = -1
        Dim start As Integer = 1
        Dim stringa As String = "gongolo mammolo cucciolo eolo dotto pisolo brontolo"
        Dim stringhetta As String = " "

        While pos <> 0
            If pos <> -1 Then Debug.Print(pos)
            pos = InStr(start, stringa, stringhetta)

            start = pos + 1
        End While
    End Sub
End Class
Risultato:
8
16
25
30
36
43
Ma non è ancora raggiunto lo scopo: vuole che la parola venga colorata durante la digitazione se viene riconosciuta come una particolare parola.
Intanto, deve usare una richTextBox, se ricordo bene... e poi... vedremo.

domenica 24 giugno 2018

Immagine spostabile su video

Creare un controllo immagine in vb, come si fa?
C'è la picturebox.
Studiamola...

La proprietà SizeMode impostata su AutoSize mi sembra la scelta migliore.
Ora devo studiare come renderla mobile. Iniziamo quindi a studiarne le coordinate.

Il principio per rendere mobile un'immagine parte dalla conoscenza delle coordinate del puntatore. Come si conoscono in VB?
Ecco: ho realizzato abbastanza agevolmente una PictureBox spostabile con il puntatore del mouse (ed eventualmente con il dito su tablet)
Public Class Form1
    Dim initX, initY As Integer
    Dim deltaX, deltaY As Integer
    Dim pressed As Boolean = False

    Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
        initX = e.X
        initY = e.Y
        pressed = True
    End Sub

    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        If pressed Then
            deltaX = e.X - initX
            deltaY = e.Y - initY
            PictureBox1.Left += deltaX
            PictureBox1.Top += deltaY
        End If
    End Sub

    Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
        pressed = False
    End Sub
End Class

domenica 29 ottobre 2017

VB.NET: giocando con le matrici per scomporre un numero nelle sue cifre.

Rispolvero il VB.
L'idea è raccogliere i numeri derivati dalla scomposizione di un numero in unità, decine, centinaia eccetera, in una matrice, per poi scriverli comodamente ognuno in una label.
Vediamo...

Per ridimensionare le matrici dinamiche in VB ho costruito questo codice:
If (matrice(0) <> Nothing) Then ReDim Preserve matrice(UBound(matrice) + 1)
che dovrebbe funzionare.
Ora metto dei numeri consecutivi da 1 a 10 in una matrice dinamica che inizia con lunghezza 1 (uBound = 0) e si allunga progressivamente a seconda della quantità di elementi che possiederà alla fine.

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim matrice(0) As Integer

        For n = 1 To 10
            If matrice(0) <> Nothing Then ReDim Preserve matrice(matrice.Length)
            matrice(UBound(matrice)) = n
        Next

        For n = 0 To UBound(matrice)
            Debug.Print(matrice(n))
        Next

    End Sub
End Class
1
2
3
4
5
6
7
8
9
10
Posso cambiare liberamente anche la quantità dei dati da immettere nella matrice:
Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim matrice(0) As Integer

        For n = 1 To 15
            If matrice(0) <> Nothing Then ReDim Preserve matrice(matrice.Length)
            matrice(UBound(matrice)) = n
        Next

        For n = 0 To UBound(matrice)
            Debug.Print(matrice(n))
        Next

    End Sub
End Class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Il codice dice che se la voce 0 non è pari a nulla la matrice va ridimensionata a un indice superiore di 1 all'ultimo indice già presente (e quindi uguale alla lunghezza della matrice), quindi il numero va scritto all'ultimo indice presente.
Molto semplice.

Ora posso scomporre il mio numero.
Ecco il codice che ho elaborato, che mi mette in una matrice le cifre di un numero, dopo aver eliminato l'eventuale virgola:
Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load


        Dim numero As Double = 3453653
        Dim stringa As String = numero.ToString.Replace(",", "")
        numero = Convert.ToDouble(stringa)
        Debug.Print(numero)
        Dim quoziente As Integer
        Dim resto As Integer
        Dim matrice(0) As Double

        Do While numero > 0
            quoziente = numero \ 10
            resto = numero Mod 10
            If matrice(0) <> Nothing Then ReDim Preserve matrice(matrice.Length)
            matrice(UBound(matrice)) = resto
            numero = quoziente
        Loop

        For n = UBound(matrice) To 0 Step -1
            Debug.Print(matrice(n))
        Next
    End Sub
End Class
3453653
3
4
5
3
6
5
3
(la matrice va letta al contrario)

giovedì 31 marzo 2016

La mia vecchia libreria jacSpeech: la classe per il riconoscimento vocale.

Ed ecco un bel codice che ho creato un paio di anni fa in VB.NET e che devo ristudiare...

Imports System.Threading
Public Class jacRecognizer
    Dim WithEvents motore As New SpeechRecognitionEngine(New Globalization.CultureInfo("it-IT"))
    Dim costruttore As GrammarBuilder
    Dim grammatica As Grammar

    Public Event riconoscimento(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)
    Public Event noise(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs)
    Public lista As New ArrayList
    Public matrice() As String

    Sub New()
        motore.SetInputToDefaultAudioDevice()
        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")
        Dim scelte As New Choices("u")
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
    Sub New(ByVal nomeFile As String)
        motore.SetInputToDefaultAudioDevice()

        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")

        Dim str As String = ""


        FileOpen(1, nomeFile, OpenMode.Input)
        Do Until EOF(1)
            str = LineInput(1)
            lista.Add(str)
        Loop
        FileClose(1)

        ReDim matrice(lista.Count - 1)
        lista.CopyTo(matrice)

        Dim scelte As New Choices(matrice)
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
    Public Sub recognizing(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles motore.SpeechRecognized
        RaiseEvent riconoscimento(sender, e)
    End Sub
    Public Sub rumore(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs) Handles motore.SpeechDetected
        RaiseEvent noise(sender, e)
    End Sub
End Class



Public Class jacSpeaker
    Public sintetizzatore As New SpeechSynthesizer
    Sub New()
        sintetizzatore.SetOutputToDefaultAudioDevice()
        sintetizzatore.SelectVoice("Microsoft Server Speech Text to Speech Voice (it-IT, Lucia)")
        sintetizzatore.Volume = 100
    End Sub
    Sub parla(ByVal parola As String)
        sintetizzatore.Speak(parola)
    End Sub
End Class


Public Class jacEngRecognizer
    Dim WithEvents motore As New SpeechRecognitionEngine(New Globalization.CultureInfo("en-US"))
    Dim costruttore As GrammarBuilder
    Dim grammatica As Grammar

    Public Event riconoscimento(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)

    Public lista As New ArrayList
    Public matrice() As String


    Sub New(ByVal nomeFile As String)
        motore.SetInputToDefaultAudioDevice()

        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("en-US")

        Dim str As String = ""


        FileOpen(1, nomeFile, OpenMode.Input)
        Do Until EOF(1)
            str = LineInput(1)
            lista.Add(str)
        Loop
        FileClose(1)

        ReDim matrice(lista.Count - 1)
        lista.CopyTo(matrice)

        Dim scelte As New Choices(matrice)
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
    Public Sub recognizing(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles motore.SpeechRecognized
        RaiseEvent riconoscimento(sender, e)
    End Sub

End Class


Public Class jacRecorder
    Declare Function mciSendString Lib "winmm" Alias "mciSendStringA" (ByVal messaggio As String, ByVal retmessage As String, ByVal valore As Integer, ByVal handle As Integer) As Integer

    Public path As String
    Sub record(ByVal tempo As Integer)
        mciSendString("open new type waveaudio alias suono", 0, 0, 0)
        mciSendString("record suono", 0, 0, 0)
        Dim sw As New Stopwatch
        sw.Start()
        Thread.Sleep(tempo)
        sw.Stop()
        mciSendString("save suono " + path, 0, 0, 0)
        mciSendString("close suono", "", 0, 0)
    End Sub
    Sub play()
        mciSendString("open " + path + " alias suono", 0, 0, 0)
        mciSendString("play suono wait", 0, 0, 0)
        mciSendString("close suono", 0, 0, 0)

    End Sub
End Class

Bene. Ci sono due classi. Comincio a studiarmi la prima...
Public Class jacRecognizer
    Dim WithEvents motore As New SpeechRecognitionEngine(New Globalization.CultureInfo("it-IT"))
    Dim costruttore As GrammarBuilder
    Dim grammatica As Grammar

    Public Event riconoscimento(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)
    Public Event noise(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs)
    Public lista As New ArrayList
    Public matrice() As String

    Sub New()
        motore.SetInputToDefaultAudioDevice()
        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")
        Dim scelte As New Choices("u")
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
    Sub New(ByVal nomeFile As String)
        motore.SetInputToDefaultAudioDevice()

        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")

        Dim str As String = ""


        FileOpen(1, nomeFile, OpenMode.Input)
        Do Until EOF(1)
            str = LineInput(1)
            lista.Add(str)
        Loop
        FileClose(1)

        ReDim matrice(lista.Count - 1)
        lista.CopyTo(matrice)

        Dim scelte As New Choices(matrice)
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
    Public Sub recognizing(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles motore.SpeechRecognized
        RaiseEvent riconoscimento(sender, e)
    End Sub
    Public Sub rumore(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs) Handles motore.SpeechDetected
        RaiseEvent noise(sender, e)
    End Sub
End Class
Dunque... innanzitutto vengono dichiarate delle variabili:
  • SpeechRecognitionEngine
  • GrammarBuilder
  • Grammar
E poi altre variabili di tipo Event eccetera... che vedrò dopo...

Intanto, nel costruttore di JacRecognizer si eseguono alcune istruzioni:
Viene chiamato il metodo
motore.SetInputToDefaultAudioDevice()
che probabilmente setta l'input per il riconoscitore al microfono del dispositivo.

Quindi viene fatto "qualcosa" a carico del GrammarBuilder (che io con una scelta infelice ho chiamato "costruttore" generando facile confusione con il costruttore della classe).
        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")
        Dim scelte As New Choices("u")
        costruttore.Append(scelte)
Per prima cosa viene istanziato l'oggetto della classe GrammarBuilder
costruttore = New GrammarBuilder


Viene attribuita la lingua a questo oggetto GrammarBuilder chiamato "costruttore":
costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")


Vengono create delle "scelte" (oggetti Choices) e "appese" al costruttore di tipo GrammarBuilder:
Dim scelte As New Choices("u")
        costruttore.Append(scelte)
Il significato di quella "u" mi sfugge completamente.

Ah, ecco! In pratica, costruiamo l'oggetto costruttore (GrammarBuilder) e gli attribuiamo due cose:
  • la proprietà Culture, ossia la lingua;
  • Le scelte, ossia le parole che comprenderà la "grammatica".
La grammatica verrà costruita semplicemente ponendo il costruttore come parametro nel suo costruttore (che brutta denominazione che ho scelto! Confusiva al massimo!)
        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")
        Dim scelte As New Choices("u")
        costruttore.Append(scelte)
e poi:
grammatica = New Grammar(costruttore)

...quindi il motore si "carica" la grammatica:
motore.LoadGrammar(grammatica)
Resta da studiare l'ultimo metodo del motore, RecognizeAsync...

Ecco: sarebbe mettere il motore in condizioni di eseguire il riconoscimento.
motore.RecognizeAsync(RecognizeMode.Multiple)
Il "Multiple" starebbe per "multiple operazioni di riconoscimento.


Nel mio jacRecognizer ho overloadato il costruttore, però, avendone anche un altro con un parametro:
    Sub New(ByVal nomeFile As String)
        motore.SetInputToDefaultAudioDevice()

        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")

        Dim str As String = ""


        FileOpen(1, nomeFile, OpenMode.Input)
        Do Until EOF(1)
            str = LineInput(1)
            lista.Add(str)
        Loop
        FileClose(1)

        ReDim matrice(lista.Count - 1)
        lista.CopyTo(matrice)

        Dim scelte As New Choices(matrice)
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub
Ecco: il parametro fornito a questo costruttore è una stringa contenente il nome di un file.
Questo file viene aperto e le righe vengono lette e caricate in una ArrayList (quella che viene dichiarata e istanziata inizialmente nella dichiarazione della classe); quindi dalla ArrayList vengono poste in una matrice.
    Sub New(ByVal nomeFile As String)
        motore.SetInputToDefaultAudioDevice()

        costruttore = New GrammarBuilder
        costruttore.Culture = Globalization.CultureInfo.GetCultureInfo("it-IT")

        Dim str As String = ""


        FileOpen(1, nomeFile, OpenMode.Input)
        Do Until EOF(1)
            str = LineInput(1)
            lista.Add(str)
        Loop
        FileClose(1)

        ReDim matrice(lista.Count - 1)
        lista.CopyTo(matrice)
(in celeste, le operazioni di lettura del file il cui indirizzo è stato passato come parametro, in rosso la copiatura dell'ArrayList nella matrice)

Quindi questa matrice viene usata per creare delle scelte (Choices) e "appesa" al costruttore, col quale verrà costruita la grammatica, che sarà quindi caricata dal motore, come prima, quindi il motore si mette in ascolto:
        Dim scelte As New Choices(matrice)
        costruttore.Append(scelte)
        grammatica = New Grammar(costruttore)
        motore.LoadGrammar(grammatica)
        motore.RecognizeAsync(RecognizeMode.Multiple)
    End Sub

Restano le subroutines di elevazione degli eventi:
    Public Sub recognizing(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles motore.SpeechRecognized
        RaiseEvent riconoscimento(sender, e)
    End Sub
    Public Sub rumore(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs) Handles motore.SpeechDetected
        RaiseEvent noise(sender, e)
    End Sub
End Class
Questi eventi erano stati dichiarati inizialmente:
    Public Event riconoscimento(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)
    Public Event noise(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs)
E' importante, nelle subroutines che evocano gli eventi, la parte Handles:
       Public Sub recognizing(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs) Handles motore.SpeechRecognized
        RaiseEvent riconoscimento(sender, e)
    End Sub
    Public Sub rumore(ByVal sender As Object, ByVal e As SpeechDetectedEventArgs) Handles motore.SpeechDetected
        RaiseEvent noise(sender, e)
    End Sub

Bene.
Adesso apro il programma che usa questo oggetto jacRecognizer...

E ho trovato la via spianata per la costruzione di tutto quello che voglio! Verso l'infinito e oltre!!!

venerdì 26 febbraio 2016

Approccio VBA a un documento

Veniamo al VBA...

Devo elaborare un file di risposte di pazienti a un'intervista.
Lo avevo già fatto, ma dal momento che rimuovo attivamente memorie connesse a questa attività che detesto, rimuovo anche i codici.
Così è meglio che metta tutto per iscritto.
Mi rianalizzo un po' il codice.
Sub main()
For n = 1 To 100
Sheets("Risposte").Cells(n, 1).Formula = n
Sheets("Risposte").Cells(n, 2).Formula = Sheets("Questionario").Cells(1, n).Formula
Next n
End Sub
In italiano, significa che nel foglio chiamato "Risposte", su 100 righe nella prima colonna mettiamo il numero di riga, mentre nella seconda mettiamo il contenuto delle celle su 100 colonne progressive della prima riga del foglio "Questionario".

Creo un nuovo foglio chiamato "Risposte" per vedere come funziona senza peraltro combinare danni.
Ecco applicata la macro:

Foglio "Questionario":


Foglio "Risposte":


Era come ho previsto io.

Ma ora sono a un punto morto: come ho fatto a ottenere i SI NO? Da quali dati?

Cerchiamo di decifrare altri files...

Ho dimenticato tutto.
Riprendo il file originale e me lo ristudio con calma...



Ecco, qui sono presentati in modo molto confuso. L'unico riferimento è il numero che sta sulla colonna Q.
Dal momento che devo fare calcoli mi conviene avere le colonne in formato numerico.

Fatto! Strumenti->Opzioni->Generale->Stile di riferimento R1C1.

Fatto questo, mi vorrei separare le varie interviste. Il punto di riferimento è il numero nella colonna Q, che ora diventa colonna 17! (E infatti contando sulle ditine ho verificato che la Q è la 17esima lettera dell'alfabeto inglese... GUH! GUH!)

Separarle potrebbe significare mettere delle righe vuote per separare ciascuna intervista dall'altra.
O anche, più elegantemente e funzionalmente, ricopiare ognuna su un foglio separato!
Studierei una macro in tal senso...

Contare le righe che presentano il numero 1 sulla colonna 17...
Sub suddividi()
Dim contatore As Integer
contatore = 0
Dim linea As Integer
linea = 174

Do Until Cells(linea, 17).Formula <> 3
linea = linea + 1
contatore = contatore + 1
Loop
Debug.Print linea & " " & contatore
End Sub
Cambiando il numero di linea iniziale e il numero da ricercare nella colonna 17 ottengo sempre lo stesso numero.
88 86
174 86
260 86

Ora, su questa base, costruisco un codice in cui copio ogni singolo troncone di 86 linee su un nuovo foglio di Excel.
Separo, praticamente, le interviste, ognuna su un nuovo foglio---

giovedì 10 ottobre 2013

Metodi di lettura di uno stream.

Non capisco.
Dunque, riepiloghiamo: uno stream può essere letto con metodi diversi:
  • Read, che ha bisogno di un buffer;
  • ReadByte, che legge un byte alla volta;
  • Per mezzo di un Reader, che è un oggetto a parte.
Sparo di aver capito... La cosa mi è un po' ostica!

Lettura in un buffer di un file wav mediante il metodo Read

Ecco, con questo codice leggo una parte di un file WAV. E ottengo la conferma che si tratta di un file WAV in quanto ne riconosco l'header:
Imports System.IO
Module Module1
    Dim corrente As New FileStream("c:\users\antonello\desktop\voce.wav", FileMode.Open)

    Dim destinazione(&H100) As Byte
    Sub Main()
        
        corrente.Read(destinazione, 0, destinazione.Length)

        For n = 0 To destinazione.Length - 1
            Console.Write(Chr(destinazione(n)))
        Next

        Console.ReadKey()
    End Sub

End Module
RIFFD☻☺ WAVEfmt ►   ☺ ☺ ◄+  ◄+  ☺ data ☻☺ ????⌂???????????????????⌂??????????⌂⌂⌂
????⌂???????????????????⌂??⌂???????⌂???⌂?⌂?????⌂??????⌂????????⌂⌂???????????⌂???
????????????⌂????⌂⌂???⌂?⌂???⌂??????????????????????????????????⌂???????????⌂???⌂
⌂????⌂??????⌂⌂?


Lettura di un file wav in un buffer mediante il metodo .Read

Ecco, con questo codice leggo una parte di un file WAV. E ottengo la conferma che si tratta di un file WAV in quanto ne riconosco l'header:
Imports System.IO
Module Module1
    Dim corrente As New FileStream("c:\users\antonello\desktop\voce.wav", FileMode.Open)

    Dim destinazione(&H100) As Byte
    Sub Main()
        
        corrente.Read(destinazione, 0, destinazione.Length)

        For n = 0 To destinazione.Length - 1
            Console.Write(Chr(destinazione(n)))
        Next

        Console.ReadKey()
    End Sub

End Module
RIFFD☻☺ WAVEfmt ►   ☺ ☺ ◄+  ◄+  ☺ data ☻☺ ????⌂???????????????????⌂??????????⌂⌂⌂
????⌂???????????????????⌂??⌂???????⌂???⌂?⌂?????⌂??????⌂????????⌂⌂???????????⌂???
????????????⌂????⌂⌂???⌂?⌂???⌂??????????????????????????????????⌂???????????⌂???⌂
⌂????⌂??????⌂⌂?


Ancora lettura e scrittura da MemoryStream

Imports System.IO
Module Module1
    Dim corrente As New MemoryStream
    Dim sorgente() As Byte = {1, 4, 65, 3, 7}
    Dim destinazione(5) As Byte
    Sub Main()
        corrente.Write(sorgente, 0, sorgente.Length)
        corrente.Position = 0
        corrente.Read(destinazione, 0, sorgente.Length)

        For n = 0 To sorgente.Length - 1
            Console.WriteLine(destinazione(n))
        Next
        Console.ReadKey()
    End Sub

End Module
Ecco come scrivo con Write e leggo con Read.

WriteByte e ReadByte, invece, servono per leggere singoli bytes.

mercoledì 9 ottobre 2013

Lettura e scrittura da MemoryStream

Sempre per leggere e scrivere dagli streams.
Uso un MemoryStream.

Imports System.IO
Module Module1
    Dim corrente As New MemoryStream
    Dim sorgente() As Byte = {1, 2, 3, 4, 5}
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As Integer
        corrente.Position = 1
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub

End Module
Ho scritto sullo stream prelevando da una matrice di bytes.
In blocco. Quindi ho usato Write.
Write accetta come parametri la matrice da cui leggere, la posizione iniziale e la quantità di bytes. Legge solo da una matrice di bytes.

Per la lettura ho usato ReadByte che legge un byte alla volta.
Se invece avessi voluto leggere in blocco dentro una matrice di bytes, avrei dovuto usare Read.

Seguendo un esempio visto in rete, ho usato il tipo Integer per la variabile result in cui leggere il byte.
Ma potrei usare anche un tipo Byte?

Imports System.IO
Module Module1
    Dim corrente As New MemoryStream
    Dim sorgente() As Byte = {1, 2, 3, 4, 5}
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As Byte
        corrente.Position = 1
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub

End Module
Sì, ottengo sempre risultati pertinenti.

Ho ottenuto un errore, prima, usando il tipo Byte in questo modo:
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As Byte
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub
Il tipo di errore era questo:
Eccezione first-chance di tipo 'System.OverflowException' in Streams.exe
che, usando un tipo Integar, non veniva più segnalato:
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As Integer
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub
ottenendo però questo risultato:
-1


Il problema era che non avevo reimpostato la posizione di lettura dell'oggetto MemoryStream, per cui la posizione, una volta effettuata la scrittura, restava impostata sull'ultimo byte, e il valore successivo era -1, che non può essere rappresentato in un tipo Byte, che è senza segno.
Invece il tipo Integer può rappresentare i numeri negativi:
1111 1111 1111 1111 1111 1111 1111 1111
dovrebbe essere la rappresentazione di -1 in un tipo Integer.
Usando un tipo che non può essere con segno, invece, ottengo un errore.
La riprova di questo la ottengo usando un tipo Integer senza segno:
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As UInt32
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub
Ed ottengo sempre:
Eccezione first-chance di tipo 'System.OverflowException' in Streams.exe
come volevasi dimostrare.

Il fatto che ottengo -1 è dovuto al fatto che non ho resettato la posizione.
Rimedio subito e posso usare anche Byte (o anche Uint32):
    Sub Main()
        corrente.Write(sorgente, 0, 3)
        Dim result As Byte
        corrente.Position = 1
        result = corrente.ReadByte()
        Console.WriteLine(result)
        Console.ReadKey()
    End Sub
Ed ecco:
2


Okay!

martedì 8 ottobre 2013

Lettura e scrittura di bytes su uno stream

Ho creato un oggetto MemoryStream.
Imports System.IO
Public Class Form1
    Dim memoria As Stream
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        memoria = New MemoryStream


    End Sub
End Class
Ora devo vedere come si scrive e si legge da questo stream...

        memoria = New MemoryStream
        memoria.WriteByte(12)
Come si legge dallo stream?

        memoria = New MemoryStream
        memoria.WriteByte(12)

        Dim risultato As Integer
        memoria.Position = 0
        risultato = memoria.ReadByte()
        MsgBox(risultato)
E ottengo 12.

Scrivo due bytes.
        memoria = New MemoryStream
        memoria.WriteByte(12)
        memoria.WriteByte(4)
Leggo il byte in posizione 1.
                memoria = New MemoryStream
        memoria.WriteByte(12)
        memoria.WriteByte(4)

        Dim risultato As Integer
        memoria.Position = 1
        risultato = memoria.ReadByte()
        MsgBox(risultato)
E ottengo 4.

E finora ho capito come "funziona"!

martedì 1 ottobre 2013

BitsPerSample, BlockAlign, SampleRate, BytesPerSecond

1760:0100  52 49 46 46 05 2A 00 00-57 41 56 45 66 6D 74 20   RIFF.*..WAVEfmt
1760:0110  10 00 00 00 01 00 01 00-11 2B 00 00 11 2B 00 00   .........+...+..
1760:0120  01 00 08 00 64 61 74 61-E1 29 00 00 80 80 7F 80   ....data.)......
1760:0130  80 80 80 7F 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0140  80 80 7F 80 80 80 80 80-80 80 80 80 81 80 7F 80   ................
1760:0150  80 80 80 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0160  80 80 7F 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0170  81 80 80 80 80 80 80 80-81 80 80 80 81 81 80 80   ................
Queste sono le voci dell'header del file WAV che esprimono rispettivamente:
11 2B 00 00 sample rate
11 2B 00 00 bytes per secondo
01 00 block align (bytes per campione) 
08 00 averageBitsPerSample (bits per campione per canale)
Le ultime due voci sono strettamente correlate: i bits per campione per canale, ridotti a bytes e moltiplicati per il numero dei canali, sono la quantità di informazione che deve essere creata per ogni campionamento. Moltiplicata per la frequenza di campionamento (Sample rate, in arancio, esprime i bytes per secondo (la voce in rosso).
Tutto qui.

In questo caso, essendoci 2B11H (11025) campioni al secondo e 2B11H (11025) bytes al secondo, è ovvio che per ogni campione ci sarà un byte, e quindi il numero di canali è 1 e il Block ALign è 1, essendo BitsPerSample 8, come risulta dall'header.

lunedì 30 settembre 2013

Altri appunti sul file WAV

-d
1760:0100  52 49 46 46 05 2A 00 00-57 41 56 45 66 6D 74 20   RIFF.*..WAVEfmt
1760:0110  10 00 00 00 01 00 01 00-11 2B 00 00 11 2B 00 00   .........+...+..
1760:0120  01 00 08 00 64 61 74 61-E1 29 00 00 80 80 7F 80   ....data.)......
1760:0130  80 80 80 7F 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0140  80 80 7F 80 80 80 80 80-80 80 80 80 81 80 7F 80   ................
1760:0150  80 80 80 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0160  80 80 7F 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0170  81 80 80 80 80 80 80 80-81 80 80 80 81 81 80 80   ................
-
57 41 56 45 = WAVE

66 6D 74 20 = fmt 

10 00 00 00 dovrebbe essere la grandezza di ogni chunk... dovrebbe essere sempre 16 tranne in casi che al momento sfuggono alla mia comprensione.

01 00 = compression code. In questo caso sarebbe 1 quindi "uncompressed".

01 00 = number of channels. Avrebbe quindi un solo canale.

11 2B 00 00 = sample rate: in questo caso è 11025, se non sbaglio.

11 2B 00 00 = average bytes per second, bytes medi al secondo. E' uguale al sample rate.

Basta così.
Adesso dobbiamo vedere bene cosa si intende per sample rate, channels e bytes per second.

Iniziamo a studiare i files WAV

Iniziamo a smontare pezzo-pezzo un file wav...

C:\Users\Antonello\Downloads>debug ciccio.wav
-d
1760:0100  52 49 46 46 05 2A 00 00-57 41 56 45 66 6D 74 20   RIFF.*..WAVEfmt
1760:0110  10 00 00 00 01 00 01 00-11 2B 00 00 11 2B 00 00   .........+...+..
1760:0120  01 00 08 00 64 61 74 61-E1 29 00 00 80 80 7F 80   ....data.)......
1760:0130  80 80 80 7F 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0140  80 80 7F 80 80 80 80 80-80 80 80 80 81 80 7F 80   ................
1760:0150  80 80 80 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0160  80 80 7F 80 80 80 80 80-80 80 80 80 80 80 80 80   ................
1760:0170  81 80 80 80 80 80 80 80-81 80 80 80 81 81 80 80   ................
-
In relazione a questa guida abbiamo queste parti:
52 49 46 46 = i caratteri ASCII per RIFF

05 2A 00 00 = la grandezza del file meno gli otto bytes di questa voce e della precedente.
00002A05 a quanto corrisponde? Mano alla calcolatrice!
10757.

Verifichiamo le dimensioni del file:
Clicco col destro sul file, e ottengo le proprietà:
10,5 KB (10.765 byte)
che corrisponde alla perfezione con la grandezza del file. 10757 + 8 bytes = 10765.
Grande!!!

Inizio a usare DirectSound.

Procediamo, come al solito con linquaggio da ignorante, a cercare di capire qualcosa su come si usa DirectSound.

Dunque, io creo un Device. Non ho ancora capito bene che accidenti sia, ma lo creo ugualmente, toh!

Imports Microsoft.DirectX
Imports Microsoft.DirectX.DirectSound
Public Class Form1
    Dim _dev As Device
    Dim _buffer As SecondaryBuffer
Eccolo dichiarato.
Dichiaro anche un buffer.

Vediamo come si istanzia questo Device.

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        _dev = New Device
        _dev.SetCooperativeLevel(Me.Handle, CooperativeLevel.Priority)
Semplicemente con New Device. Il costruttore del Device non ha parametri.

Bene, ora che abbiamo dato vita a un Device, impostiamo il Cooperative Level.
Che accidenti è, per la precisione, questo Cooperative Level?

Credo che abbia a che fare con le altre applicazioni, ossia con la competizione con altre applicazioni per qualcosa, come le periferiche... ma non ne sono molto sicuro.

In ogni caso, sintetizziamo e andiamo avanti: Si dichiara e si istanzia un Device, che ha un semplice costruttore senza parametri, e quindi si imposta il Cooperative Level del Device stesso.
Quindi, dichiarato il buffer, si istanzia. Questo ha nel costruttore due parametri, uno che specifica il file, e l'altro che specifica il Device.
Forse si tratta di un discorso del tipo: "Creo un buffer nel quale immagazzino i dati del file e lo associo al tale Device.

Bene... con un linguaggio da caprone inizio a capire la cosa. Poi con calma cercherò di affinare sia la comprensione sia il linguaggio.
Se aspetto di comprendere tutto, non vado più avanti.

lunedì 16 settembre 2013

VB.NET: Sintassi di Declare per la dichiarazione delle API di Windows.

Cerchiamo di fissare bene la sintassi di Declare.

Ho trovato uno schema: Declare Function (function name) Lib (library) (arguments)
Proviamo a seguirlo...
Public Class Form1
    Declare Function Bippa Lib "kernel32" Alias "Beep" (ByVal dwFreq As Integer, ByVal dwDuration As Integer) As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Bippa(440, 2000)
        Bippa(800, 2000)
    End Sub
End Class
Ecco la funzione Beep della libreria "kernel32.dll", che ho rinominato alla buona "Bippa".
Dopo la specifica della libreria e prima degli argomenti va inserito l'Alias sotto forma di stringa, ossia il nome con cui la funzione figura nella libreria.

Proviamo con MessageBox.
Public Class Form1
    Declare Function Messaggio Lib "user32" Alias "MessageBoxA" (ByVal hwnd As Integer, ByVal message As String, ByVal capt As String, ByVal uType As Integer) As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Messaggio(0, "Ciao, ciccio", "Messaggio", 0)
    End Sub

End Class
...che funziona, ovviamente!

venerdì 13 settembre 2013

StopWatch

Che cosa è StopWatch?

Ecco un codice, ricopiato pari pari da un esempio in rete:
        Dim sw As New Stopwatch
        sw.Start()
        Thread.Sleep(2000)
        sw.Stop()
        MsgBox("tempooooo!")
Dopo due secondi appare la MessageBox con scritto "tempooooo!".
Funziona.
L'ho applicata al mio tentativo di realizzare un' "eco" con VB.NET, e la cosa è riuscita.

martedì 10 settembre 2013

Gestione compilazione di un progetto VB.NET per il tipo di CPU

Ecco dove devo andare per impostare il tipo di CPU per il quale programmare.
Questa CPU è a 64 bit, e nel preparare le classi di riconoscimento e sintesi vocale ho incontrato problemi con il settaggio del dispositivo di input che si sono risolti impostando la compliazione a 64 bit.
Ora ho impostato "any CPU" e pare che vada bene lo stesso.
Bisogna vedere quando metterò questo programma su un sistema a 32 bit...

Questa è la schermata:


Per impostare le opzioni si apre dal menu:


che dà questa schermata:


Questo mi valga come promemoria!

Libreria jacSpeech: le mie classi personalizzate di riconoscimento e sintesi vocale.

Bene.
Sono riuscito a creare una jacSpeech.dll con le mie classi di riconoscimento e sintesi vocale, e a linkarla con un qualsiasi codice che istanzi le classi.
Ecco un codice che istanzia le classi jacRecognizer e jacSpeaker.
Public Class Form1
    Dim mioRecognizer As jacRecognizer
    Dim mioSpeaker As jacSpeaker
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mioRecognizer = New jacRecognizer("C:\users\antonello\desktop\saluti.txt")
        mioSpeaker = New jacSpeaker
        AddHandler mioRecognizer.riconoscimento, AddressOf gestione
    End Sub
    Sub gestione(ByVal sender As Object, ByVal e As SpeechRecognizedEventArgs)
        mioSpeaker.parla(e.Result.Text)
    End Sub
End Class
Funziona egregiamente, direi!

lunedì 9 settembre 2013

Codice per scrivere files ad accesso casuale.

Per scrivere files ad accesso casuale (due TextBoxes e un Button sul form...)
Option Strict Off
Structure Record
     Public suono As String
     Public nome As String
End Structure

Public Class Form1
    Dim recNum As Integer

    Dim mioRecord As New Record


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        mioRecord.suono = TextBox1.Text
        mioRecord.nome = TextBox2.Text
        If System.IO.File.Exists("C:\users\antonello\desktop\file") Then
            recNum = CInt((FileLen("C:\users\antonello\desktop\file") / Len(mioRecord)))
        Else
            recNum = 0
        End If

        FileOpen(1, "c:\users\antonello\desktop\file", OpenMode.Random, , , Len(mioRecord))
        FilePut(1, mioRecord, recNum + 1)
        FileClose(1)
    End Sub
End Class