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

Da Gambas-it.org - Wikipedia.
(Creata pagina con 'Vediamo un esempio molto semplice per ricevere dati grezzi Midi attraverso il sibsistema '''RawMidi''' di Alsa. Library "libasound:2" <Font color=gray>' ''nt snd_rawmidi_o...')
 
Riga 1: Riga 1:
Vediamo un esempio molto semplice per ricevere dati grezzi Midi attraverso il sibsistema '''RawMidi''' di Alsa.
+
Alsa consente all'utente di ricevere da un dispositivo Midi esterno (ad esempio una tastiera) dati Midi grezzi, ossia semplicemente strutturati secondo il protocollo Midi, attraverso il subsistema ''RawMidi''.
 +
 
 +
Nella elaborazione del codice bisognerà, ovviamente, richiamare la [[Extern:_richiamare_funzioni_esterne_a_Gambas|libreria estrena]] di Alsa, e conseguentemente dichiarare attraverso la parola ''Extern'' le funzioni di Alsa necessarie.
 +
<BR>L'operazione essenziale e basilare, che deve essere svolta, è quella di aprire la connessione con l'interfaccia ''RawMidi'' di Alsa attraverso un ''handle'', (''maniglia''), per poter successivamente instaurare ogni altro rapporto.
 +
<BR>La funzione esterna adatta per la creazione di questo ''handle'' è:
 +
''int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)''
 +
laddove:
 +
* ''**in_rmidi'': è una variabile di tipo ''puntatore'' che rappresenta l'<I>handle</i> del subsistema ''RawMidi'' per la lettura dei dati Midi in entrata;
 +
* ''**out_rmidi'': è una variabile di tipo ''puntatore'' che rappresenta l'<I>handle</i> del subsistema ''RawMidi'' per la scrittura dei dati Midi in uscita (che nel presente caso trattandosi di ricezione, quindi di ''entrata'', di dati, è posto a ''Null'');
 +
* ''*name'': è una variabile di tipo ''stringa'' che rappresenta l'identificativo della scheda audio (''Card''), del dispositivo Midi (''Device'') e del sottodispositivo (''Subdevice''), ad esempio: ''hw:2,0,0''. L'individuazione esatta di questa stringa potrà essere effettuata agevolmente, dopo aver connesso il dispositivo Midi esterno al calcolatore, osservando la denominazione del file-device ''/dev/snd/midiCnDn'', dove ''Cn'' è il numero identificativo della Scheda audio e ''Cn'' è il numero identificativo del dispositivo virtuale;
 +
* ''mode'': è un ''flag''.  |[[#Note|1]]|
 +
<BR>Questa funzione basilare in Gambas potrà essere così dichiarata:
 +
Private Extern snd_rawmidi_open(in_rmidi As Pointer, out_rmidi As Pointer, name As String, mode As Integer) As Integer
 +
 
 +
L'altra funzione sarà quella di essere in grado di leggere i dati Midi grezzi 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
 +
 
 +
 
 +
===Esempi===
 +
Vediamo un paio di esempio semplici per ricevere dati grezzi Midi attraverso il sibsistema ''RawMidi'' di Alsa.
 +
 
 +
====Esempio base====
 
  Library "libasound:2"
 
  Library "libasound:2"
 
   
 
   
  <Font color=gray>' ''nt snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Apre una nuova connessione al'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
 
   
 
   
Riga 15: Riga 39:
 
   
 
   
 
   Dim err As Integer
 
   Dim err As Integer
  Dim SND_RAWMIDI_SYNC As Integer = 4  <Font color=gray>' ''0x0004 -> Flag per la modalità di apertura: "Write sync mode"''</font>
 
 
   Dim EAGAIN As Integer = 11            <Font color=gray>' ''Try again''</font>
 
   Dim EAGAIN As Integer = 11            <Font color=gray>' ''Try again''</font>
 
   Dim midiin, buffer, status As Pointer
 
   Dim midiin, buffer, status As Pointer
Riga 22: Riga 45:
 
   Dim dato As Byte
 
   Dim dato As Byte
 
    
 
    
   err = snd_rawmidi_open(VarPtr(midiin), Null, nome_porta, SND_RAWMIDI_SYNC)
+
   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 34: Riga 57:
 
       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''
 +
' ''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 45: Riga 70:
 
  '''End'''
 
  '''End'''
  
 +
 +
====Esempio più complesso====
 +
Library "libasound:2"
 +
 +
'''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
 +
 +
<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
 +
 +
<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
 +
 +
<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 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>
 +
'''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 As Integer
 +
  Dim midin, pfds, revents, buf As Pointer
 +
  Dim dato As Byte
 +
  Dim ignore_active_sensing As Byte = 254
 +
  Dim bufS As Stream
 +
 +
 
 +
<Font color=gray>' ''Algoritmo per individuare automaticamente nome dell'handle dell'interfaccia "RawMidi":''</font>
 +
    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_read(midin, Null, 0)
 +
 +
    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))   
 +
   
 +
   
 +
  While True
 +
     
 +
      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
 +
 +
  Wend
 +
 +
'''End'''
  
  
  
<FONT color=red><B>Pagina in costruzione !</b></font>
+
=Note=
 +
[1] Oltre al valore zero, ne sono previsti anche altri più specifici, così spiegati dalla documentazione tratta da internet (Craig Stuart Sapp):
 +
<BR>« ''Using SND_RAWMIDI_NONBLOCK flag for snd_rawmidi_open() or snd_rawmidi_open_lconf() instruct device driver to return the -EBUSY error when device is already occupied with another application. This flag also changes behaviour of snd_rawmidi_write() and snd_rawmidi_read() returning -EAGAIN when no more bytes can be processed.''
 +
<BR>''Using SND_RAWMIDI_APPEND flag (output only) instruct device driver to append contents of written buffer - passed by snd_rawmidi_write() - atomically to output ring buffer in the kernel space. This flag also means that the device is not opened exclusively, so more applications can share given rawmidi device. Note that applications must send the whole MIDI message including the running status, because another writting application might break the MIDI message in the output buffer.''
 +
<BR>''Using SND_RAWMIDI_SYNC flag (output only) assures that the contents of output buffer specified using snd_rawmidi_write() is always drained before the function exits. This behaviour is the same as snd_rawmidi_write() followed immediately by snd_rawmidi_drain().'' »

Versione delle 10:37, 13 lug 2013

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

Nella elaborazione del codice bisognerà, ovviamente, richiamare la libreria estrena di Alsa, e conseguentemente dichiarare attraverso la parola Extern le funzioni di Alsa necessarie.
L'operazione essenziale e basilare, che deve essere svolta, è quella di aprire la connessione con l'interfaccia RawMidi di Alsa attraverso un handle, (maniglia), per poter successivamente instaurare ogni altro rapporto.
La funzione esterna adatta per la creazione di questo handle è:

int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)

laddove:

  • **in_rmidi: è una variabile di tipo puntatore che rappresenta l'handle del subsistema RawMidi per la lettura dei dati Midi in entrata;
  • **out_rmidi: è una variabile di tipo puntatore che rappresenta l'handle del subsistema RawMidi per la scrittura dei dati Midi in uscita (che nel presente caso trattandosi di ricezione, quindi di entrata, di dati, è posto a Null);
  • *name: è una variabile di tipo stringa che rappresenta l'identificativo della scheda audio (Card), del dispositivo Midi (Device) e del sottodispositivo (Subdevice), ad esempio: hw:2,0,0. L'individuazione esatta di questa stringa potrà essere effettuata agevolmente, dopo aver connesso il dispositivo Midi esterno al calcolatore, osservando la denominazione del file-device /dev/snd/midiCnDn, dove Cn è il numero identificativo della Scheda audio e Cn è il numero identificativo del dispositivo virtuale;
  • mode: è un flag. |1|


Questa funzione basilare in Gambas potrà essere così dichiarata:

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

L'altra funzione sarà quella di essere in grado di leggere i dati Midi grezzi 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


Esempi

Vediamo un paio di esempio semplici per ricevere dati grezzi Midi attraverso il sibsistema RawMidi di Alsa.

Esempio base

Library "libasound:2"

' 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 EAGAIN As Integer = 11            ' Try again
 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 (err <> - EAGAIN)
      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 più complesso

Library "libasound:2"

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 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 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_read(midin, Null, 0)

   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))    
   
   
  While True
     
     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

  Wend

End


Note

[1] Oltre al valore zero, ne sono previsti anche altri più specifici, così spiegati dalla documentazione tratta da internet (Craig Stuart Sapp):
« Using SND_RAWMIDI_NONBLOCK flag for snd_rawmidi_open() or snd_rawmidi_open_lconf() instruct device driver to return the -EBUSY error when device is already occupied with another application. This flag also changes behaviour of snd_rawmidi_write() and snd_rawmidi_read() returning -EAGAIN when no more bytes can be processed.
Using SND_RAWMIDI_APPEND flag (output only) instruct device driver to append contents of written buffer - passed by snd_rawmidi_write() - atomically to output ring buffer in the kernel space. This flag also means that the device is not opened exclusively, so more applications can share given rawmidi device. Note that applications must send the whole MIDI message including the running status, because another writting application might break the MIDI message in the output buffer.
Using SND_RAWMIDI_SYNC flag (output only) assures that the contents of output buffer specified using snd_rawmidi_write() is always drained before the function exits. This behaviour is the same as snd_rawmidi_write() followed immediately by snd_rawmidi_drain(). »