Differenze tra le versioni di "Ricevere dati grezzi Midi attraverso il subsistema RawMidi"

Da Gambas-it.org - Wikipedia.
 
(3 versioni intermedie di uno stesso utente non sono mostrate)
Riga 4: Riga 4:
  
 
==Lettura dei dati in entrata==
 
==Lettura dei dati in entrata==
Dopo la [[Introduzione_al_subsistema_RawMidi|dichiarazione della Libreria di Alsa e l'apertura del subsistema ''RawMidi'']] l'altra funzione essenziale è quella che ci permetterà di leggere i dati in ''entrata'' provenienti da un dispositivo Midi esterno:
+
Dopo la [[Introduzione_al_subsistema_RawMidi|dichiarazione della Libreria di Alsa e l'apertura del subsistema ''RawMidi'']] mediante la funzione esterna che in routine potrà essere richiamata in scrittura come segue:
 +
  err =  snd_rawmidi_open(h_midiIn, 0, nome_handle, 0) As Integer
 +
l'altra funzione essenziale è quella che ci permetterà di leggere i dati in ''entrata'' provenienti da un dispositivo Midi esterno:
 
  ''ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)
 
  ''ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)
 
alla quale si dovrà passare una variabile di tipo puntatore, che rappresenta una quantità di area di memoria allocata pari ad un byte, e che sarà riempita con un dato grezzo Midi. Per leggere il dato passato da questa funzione esterna mediante la predetta variabile ''pointer'', bisognerà dereferenziare tale variabile dopo essere stata creata una variabile di tipo ''Stream'' mediante l'uso della funzione ''Memory Stream''.
 
alla quale si dovrà passare una variabile di tipo puntatore, che rappresenta una quantità di area di memoria allocata pari ad un byte, e che sarà riempita con un dato grezzo Midi. Per leggere il dato passato da questa funzione esterna mediante la predetta variabile ''pointer'', bisognerà dereferenziare tale variabile dopo essere stata creata una variabile di tipo ''Stream'' mediante l'uso della funzione ''Memory Stream''.
Riga 31: Riga 33:
 
====Esempio base in modalità bloccante====
 
====Esempio base in modalità bloccante====
 
Vediamo di seguito un semplice esempio per la ricezione dei dati Midi con modalità normale ''Blocking'':
 
Vediamo di seguito un semplice esempio per la ricezione dei dati Midi con modalità normale ''Blocking'':
  Library "libasound:2"
+
  Library "libasound:2.0.0"
 
   
 
   
 
  <Font color=gray>' ''int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Apre una nuova connessione all'interfaccia "RawMidi"''</font>
 
  <Font color=gray>' ''int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Apre una nuova connessione all'interfaccia "RawMidi"''</font>
  '''Private''' Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
+
  Private Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
 
   
 
   
 
  <Font color=gray>' ''ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)  --> Legge dati Midi grezzi da un flusso Midi''</font>
 
  <Font color=gray>' ''ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)  --> Legge dati Midi grezzi da un flusso Midi''</font>
Riga 43: Riga 45:
 
   
 
   
 
   
 
   
  '''Public''' Sub Form_Open()
+
  Public Sub Form_Open()
 +
 +
  Dim err As Integer
 +
  Dim midiin, buffer, status As Pointer
 +
  Dim nome_porta As String = "hw:2,0,0"
 +
  Dim bufStr As Stream
 +
  Dim dato As Byte
 
   
 
   
  Dim err As Integer
 
  Dim midiin, buffer, status As Pointer
 
  Dim nome_porta As String = "hw:2,0,0"
 
  Dim bufStr As Stream
 
  Dim dato As Byte
 
 
 
 
   err = snd_rawmidi_open(VarPtr(midiin), 0, nome_porta, 0)
 
   err = snd_rawmidi_open(VarPtr(midiin), 0, nome_porta, 0)
 
   If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))
 
   If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))
Riga 63: Riga 65:
 
       Else
 
       Else
 
         If err >= 0 Then
 
         If err >= 0 Then
  <Font color=gray>' ''Poiché la funzione "snd_rawmidi_read" passa solo un byte utile (cioè il dato Midi grezzo), posto nel primo byte dell'area allocata''
+
  <Font color=gray>' ''Poiché la funzione "snd_rawmidi_read" passa solo un byte utile (cioè il dato Midi grezzo), posto nel primo byte dell'area allocata ogni volta bisognerà dereferenziare la variabile di tipo ''stream'' leggendo <SPAN style="text-decoration:underline">solo</span> il primo byte dell'area di memoria riservata:''</font>
' ''ogni volta bisognerà dereferenziare la variabile di tipo ''stream'' leggendo <SPAN style="text-decoration:underline">solo</span> il primo byte dell'area di memoria riservata:''</font>
 
 
           Seek #bufStr, 0
 
           Seek #bufStr, 0
 
           Read #bufStr, dato
 
           Read #bufStr, dato
Riga 74: Riga 75:
 
     Wend
 
     Wend
 
   
 
   
  '''End'''
+
  End
  
  
 
====Esempio con modalità non bloccante====
 
====Esempio con modalità non bloccante====
 
Il seguente esempio mostra un semplice esempio con apertura del Midi input invece in modalità ''Non-Blocking'' e conseguente utilizzo della funzione ''Poll'':
 
Il seguente esempio mostra un semplice esempio con apertura del Midi input invece in modalità ''Non-Blocking'' e conseguente utilizzo della funzione ''Poll'':
  Library "libasound:2"
+
  Library "libasound:2.0.0"
 
   
 
   
  '''Private''' Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
+
  Private Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
  '''Private''' Extern snd_rawmidi_read(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer
+
  Private Extern snd_rawmidi_read(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer
 
   
 
   
 
  <Font color=gray>' ''int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)  --> set nonblock mode''</font>
 
  <Font color=gray>' ''int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)  --> set nonblock mode''</font>
  '''Private''' Extern snd_rawmidi_nonblock(in_rmidi As Pointer, nonblock As Integer) As Integer
+
  Private Extern snd_rawmidi_nonblock(in_rmidi As Pointer, nonblock As Integer) As Integer
 
   
 
   
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors_count (snd_rawmidi_t *rmidi)  --> get count Of poll descriptors For RawMidi handle''</font>
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors_count (snd_rawmidi_t *rmidi)  --> get count Of poll descriptors For RawMidi handle''</font>
  '''Private''' Extern snd_rawmidi_poll_descriptors_count(in_rmidi As Pointer) As Integer
+
  Private Extern snd_rawmidi_poll_descriptors_count(in_rmidi As Pointer) As Integer
 
   
 
   
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors (snd_rawmidi_t *rmidi, struct pollfd *pfds, unsigned int space)  --> get poll descriptors''</font>
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors (snd_rawmidi_t *rmidi, struct pollfd *pfds, unsigned int space)  --> get poll descriptors''</font>
  '''Private''' Extern snd_rawmidi_poll_descriptors(in_rmidi As Pointer, pfds As Pointer, SpaceInt As Integer) As Integer
+
  Private Extern snd_rawmidi_poll_descriptors(in_rmidi As Pointer, pfds As Pointer, SpaceInt As Integer) As Integer
 
   
 
   
  '''Private''' Extern poll(a As Pointer, b As Integer, c As Integer) As Integer In "libc:6"
+
  Private Extern poll(a As Pointer, b As Integer, c As Integer) As Integer In "libc:6"
 
   
 
   
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors_revents (snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revent)  --> get returned events From poll descriptors''</font>
 
  <Font color=gray>' ''int snd_rawmidi_poll_descriptors_revents (snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revent)  --> get returned events From poll descriptors''</font>
  '''Private''' Extern snd_rawmidi_poll_descriptors_revents(in_rmidi As Pointer, pfds As Pointer, nfP As Integer, revSh As Pointer) As Integer
+
  Private Extern snd_rawmidi_poll_descriptors_revents(in_rmidi As Pointer, pfds As Pointer, nfP As Integer, revSh As Pointer) As Integer
 
   
 
   
  '''Private''' Extern snd_strerror(errore As Integer) As String
+
  Private Extern snd_strerror(errore As Integer) As String
 
   
 
   
 
   
 
   
  '''Public''' Sub Form_Open()
+
  Public Sub Form_Open()
 
   
 
   
  Dim posMid, nome_porta As String
+
  Dim posMid, nome_porta As String
  Dim err, npfds, tempus As Integer
+
  Dim err, npfds, tempus, timeout As Integer
  Dim midin, pfds, revents, buf As Pointer
+
  Dim midin, pfds, revents, buf As Pointer
  Dim dato As Byte
+
  Dim dato As Byte
  Dim ignore_active_sensing As Byte = 254
+
  Dim ignore_active_sensing As Byte = 254
  Dim bufS As Stream
+
  Dim bufS As Stream
+
 
 
 
 
  <Font color=gray>' ''Algoritmo per individuare automaticamente il nome dell'handle dell'interfaccia "RawMidi":''</font>
 
  <Font color=gray>' ''Algoritmo per individuare automaticamente il nome dell'handle dell'interfaccia "RawMidi":''</font>
    Print "File-device = "; Dir("/dev/snd/", "midiC*", gb.Device)[0]
+
  Print "File-device = "; Dir("/dev/snd/", "midiC*", gb.Device)[0]
    posMid = Mid(Dir("/dev/snd/", "midiC*", gb.Device)[0], 6, 1)
+
  posMid = Mid(Dir("/dev/snd/", "midiC*", gb.Device)[0], 6, 1)
 
    
 
    
    nome_porta = "hw:" & posMid & ",0,0"
+
  nome_porta = "hw:" & posMid & ",0,0"
    Print "Nome del dispositivo Midi di Alsa: "; nome_porta
+
  Print "Nome del dispositivo Midi di Alsa: "; nome_porta
   
 
 
   
 
   
    err = snd_rawmidi_open(VarPtr(midin), 0, nome_porta, 0)
+
  err = snd_rawmidi_open(VarPtr(midin), 0, nome_porta, 0)
    If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))
+
  If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))
 
 
    snd_rawmidi_read(midin, Null, 0)
 
 
   
 
   
    snd_rawmidi_nonblock(midin, 1)
+
  snd_rawmidi_nonblock(midin, 1)
 
      
 
      
    npfds = snd_rawmidi_poll_descriptors_count(midin)
+
  npfds = snd_rawmidi_poll_descriptors_count(midin)
 
      
 
      
    pfds = Alloc(npfds * SizeOf(gb.Pointer))
+
  pfds = Alloc(npfds * SizeOf(gb.Pointer))
 
      
 
      
    err = snd_rawmidi_poll_descriptors(midin, pfds, npfds)
+
  err = snd_rawmidi_poll_descriptors(midin, pfds, npfds)
 
   
 
   
    buf = Alloc(SizeOf(gb.Byte))     
+
  buf = Alloc(SizeOf(gb.Byte))     
 
      
 
      
   
+
   Do
   While True
+
    err = poll(pfds, npfds, 200)
     
+
    If err < 0 Then Error("Funzione 'poll' fallita !")
      err = poll(pfds, npfds, 200)
+
    If err = 0 Then
      If err < 0 Then Error("Funzione 'poll' fallita !")
+
      tempus += 200
     
+
      If timeout And tempus >= timeout Then Break
      If err = 0 Then
+
      Continue
        tempus += 200
+
    Endif
        If timeout And tempus >= timeout Then Break
+
    err = snd_rawmidi_poll_descriptors_revents(midin, pfds, npfds, VarPtr(revents))
        Continue
+
    If err < 0 Then Error("Impossibile ottenere eventi 'poll': " & snd_strerror(err))
      Endif
+
    err = snd_rawmidi_read(midin, buf, SizeOf(gb.Byte))
     
+
    If err < 0 Then Error("Impossibile leggere dalla porta \\" & nome_porta & "\\: " & snd_strerror(err))
      err = snd_rawmidi_poll_descriptors_revents(midin, pfds, npfds, VarPtr(revents))
+
    bufS = Memory buf For Read
      If err < 0 Then Error("Impossibile ottenere eventi 'poll': " & snd_strerror(err))
+
    Seek #bufS, 0
+
    Read #bufS, dato
      err = snd_rawmidi_read(midin, buf, SizeOf(gb.Byte))
+
    If dato <> ignore_active_sensing Then Print dato
      If err < 0 Then Error("Impossibile leggere dalla porta \\" & nome_porta & "\\: " & snd_strerror(err))
+
   Loop
 
      bufS = Memory buf For Read
 
                   
 
          Seek #bufS, 0
 
          Read #bufS, dato
 
          If dato <> ignore_active_sensing Then Print dato
 
 
   Wend
 
 
   
 
   
  '''End'''
+
  End

Versione attuale delle 14:54, 19 giu 2024

Premessa

Alsa consente all'utente di ricevere da un dispositivo Midi esterno (ad esempio una tastiera) dati Midi grezzi attraverso il subsistema RawMidi.


Lettura dei dati in entrata

Dopo la dichiarazione della Libreria di Alsa e l'apertura del subsistema RawMidi mediante la funzione esterna che in routine potrà essere richiamata in scrittura come segue:

 err =  snd_rawmidi_open(h_midiIn, 0, nome_handle, 0) As Integer

l'altra funzione essenziale è quella che ci permetterà di leggere i dati in entrata provenienti da un dispositivo Midi esterno:

ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)

alla quale si dovrà passare una variabile di tipo puntatore, che rappresenta una quantità di area di memoria allocata pari ad un byte, e che sarà riempita con un dato grezzo Midi. Per leggere il dato passato da questa funzione esterna mediante la predetta variabile pointer, bisognerà dereferenziare tale variabile dopo essere stata creata una variabile di tipo Stream mediante l'uso della funzione Memory Stream. Questa funzione in Gambas potrà essere così dichiarata:

Private Extern snd_rawmidi_read(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer

Modalità Blocking e Non-Blocking

Normalmente un'entrata Midi è aperta in modalità Blocking. Questa modalità di apertura del Midi input fa sì che la funzione snd_rawmidi_read() non ritorni dati Midi sino a quando non abbia ricevuto il numero di dati stabilito. Così ad esempio, se si è stabilito che debba ritornare una quantità di tre dati:

err = snd_rawmidi_read(midiIn, buffer, 3)

Nel momento in cui al Midi input giunge il numero indicato di dati, essi vengono copiati nel buffer di memoria.

E' possibile, però, scegliere la modalità non bloccante (Non-Blocking) che consente di copiare i dati nel buffer appena giungono al Midi input.
Per attivare la modalità non bloccante, si utilizza una specifica funzione esterna:

int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)

che in Gambas dichiareremo così:

Private Extern snd_rawmidi_nonblock(midiIn As Pointer, nonblock As Integer) as Integer

e che in codice richiameremo così:

err = snd_rawmidi_nonblock(handleIn, 1)

Poiché la funzione snd_rawmidi_read non attende in modalità non bloccante l'arrivo di un numero dati prestabilito, restituisce il valore 0 se non ci sono dati Midi da ritornare. Questa circostanza determina il consumo eccessivo di risorse della CPU, girando inutilmente il programma intorno alla funzione snd_rawmidi_read. Per ovviare a ciò, è opportuno porre un attesa di alcuni millisecondi ad esempio mediante la funzione Poll di C.


Esempi

Vediamo un paio di esempio semplici, uno in modalità Blocking, l'altro in modalità Non-Blocking, per ricevere dati grezzi Midi attraverso il sibsistema RawMidi di Alsa.

Esempio base in modalità bloccante

Vediamo di seguito un semplice esempio per la ricezione dei dati Midi con modalità normale Blocking:

Library "libasound:2.0.0"

' int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Apre una nuova connessione all'interfaccia "RawMidi"
Private Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer

' ssize_t snd_rawmidi_read (snd_rawmidi_t *rmidi, void *buffer, size_t size)  --> Legge dati Midi grezzi da un flusso Midi
Private Extern snd_rawmidi_read(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer

' const char * snd_strerror (int errnum)  --> Ritorna il messaggio per un codice Errore
Private Extern snd_strerror(errore As Integer) As String


Public Sub Form_Open()

  Dim err As Integer
  Dim midiin, buffer, status As Pointer
  Dim nome_porta As String = "hw:2,0,0"
  Dim bufStr As Stream
  Dim dato As Byte

  err = snd_rawmidi_open(VarPtr(midiin), 0, nome_porta, 0)
  If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))

  buffer = Alloc(SizeOf(gb.Byte))
  bufStr = Memory buffer For Read

    While (True)
      err = snd_rawmidi_read(midiin, buffer, 1)
      If err < 0 Then
        Error("Impossibile leggere dal MIDI input: %s", snd_strerror(err))
      Else
        If err >= 0 Then
' Poiché la funzione "snd_rawmidi_read" passa solo un byte utile (cioè il dato Midi grezzo), posto nel primo byte dell'area allocata ogni volta bisognerà dereferenziare la variabile di tipo stream leggendo solo il primo byte dell'area di memoria riservata:
          Seek #bufStr, 0
          Read #bufStr, dato
' Vediamo in console i dati Midi grezzi ricevuti (compreso in questo caso il dato relativo all'evento "Active Sensing":
          Print dato
        Endif
      Endif

    Wend

End


Esempio con modalità non bloccante

Il seguente esempio mostra un semplice esempio con apertura del Midi input invece in modalità Non-Blocking e conseguente utilizzo della funzione Poll:

Library "libasound:2.0.0"

Private Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
Private Extern snd_rawmidi_read(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer

' int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)  --> set nonblock mode
Private Extern snd_rawmidi_nonblock(in_rmidi As Pointer, nonblock As Integer) As Integer

' int snd_rawmidi_poll_descriptors_count (snd_rawmidi_t *rmidi)  --> get count Of poll descriptors For RawMidi handle
Private Extern snd_rawmidi_poll_descriptors_count(in_rmidi As Pointer) As Integer

' int snd_rawmidi_poll_descriptors (snd_rawmidi_t *rmidi, struct pollfd *pfds, unsigned int space)  --> get poll descriptors
Private Extern snd_rawmidi_poll_descriptors(in_rmidi As Pointer, pfds As Pointer, SpaceInt As Integer) As Integer

Private Extern poll(a As Pointer, b As Integer, c As Integer) As Integer In "libc:6"

' int snd_rawmidi_poll_descriptors_revents (snd_rawmidi_t *rawmidi, struct pollfd *pfds, unsigned int nfds, unsigned short *revent)  --> get returned events From poll descriptors
Private Extern snd_rawmidi_poll_descriptors_revents(in_rmidi As Pointer, pfds As Pointer, nfP As Integer, revSh As Pointer) As Integer

Private Extern snd_strerror(errore As Integer) As String


Public Sub Form_Open()

  Dim posMid, nome_porta As String
  Dim err, npfds, tempus, timeout As Integer
  Dim midin, pfds, revents, buf As Pointer
  Dim dato As Byte
  Dim ignore_active_sensing As Byte = 254
  Dim bufS As Stream
  
' Algoritmo per individuare automaticamente il nome dell'handle dell'interfaccia "RawMidi":
  Print "File-device = "; Dir("/dev/snd/", "midiC*", gb.Device)[0]
  posMid = Mid(Dir("/dev/snd/", "midiC*", gb.Device)[0], 6, 1)
 
  nome_porta = "hw:" & posMid & ",0,0"
  Print "Nome del dispositivo Midi di Alsa: "; nome_porta

  err = snd_rawmidi_open(VarPtr(midin), 0, nome_porta, 0)
  If err < 0 Then Error("Impossibile aprire il MIDI input: %s", snd_strerror(err))

  snd_rawmidi_nonblock(midin, 1)
   
  npfds = snd_rawmidi_poll_descriptors_count(midin)
   
  pfds = Alloc(npfds * SizeOf(gb.Pointer))
   
  err = snd_rawmidi_poll_descriptors(midin, pfds, npfds)

  buf = Alloc(SizeOf(gb.Byte))    
   
  Do
    err = poll(pfds, npfds, 200)
    If err < 0 Then Error("Funzione 'poll' fallita !")
    If err = 0 Then
      tempus += 200
      If timeout And tempus >= timeout Then Break
      Continue
    Endif
    err = snd_rawmidi_poll_descriptors_revents(midin, pfds, npfds, VarPtr(revents))
    If err < 0 Then Error("Impossibile ottenere eventi 'poll': " & snd_strerror(err))
    err = snd_rawmidi_read(midin, buf, SizeOf(gb.Byte))
    If err < 0 Then Error("Impossibile leggere dalla porta \\" & nome_porta & "\\: " & snd_strerror(err))
    bufS = Memory buf For Read
    Seek #bufS, 0
    Read #bufS, dato
    If dato <> ignore_active_sensing Then Print dato
  Loop

End