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

Da Gambas-it.org - Wikipedia.
(13 versioni intermedie di uno stesso utente non sono mostrate)
Riga 2: Riga 2:
 
Il sistema Alsa consente di inviare dati Midi grezzi ad un dispositivo Midi esterno mediante il suo subsistema ''RawMidi''.
 
Il sistema Alsa consente di inviare dati Midi grezzi ad un dispositivo Midi esterno mediante il suo subsistema ''RawMidi''.
  
Nella elaborazione del codice bisognerà, ovviamente, richiamare la [[Extern:_richiamare_funzioni_esterne_a_Gambas|libreria estrena]] di Alsa, attualmente ''libasound.so.2.0.0'', che in Gambas richiameremo così:
 
Library "libasound:2"
 
e conseguentemente dichiarare attraverso la parola ''Extern'' le funzioni di Alsa necessarie.
 
  
Per scrivere dati MIDI, è necessario innanzitutto chiamare la funzione
+
==Scrittura dei dati in uscita==
  ''int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)''
+
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 lettura come segue:
passandogli così il nome dell'hardware della scheda, del dispositivo e del sub-dispositivo desiderato. Quella funzione restituirà un ''handle'' (maniglia) che è possibile utilizzare per chiamare le successive funzioni esterne necessarie di Alsa.
+
  err =  snd_rawmidi_open(0, h_midiOut, nome_handle, 0) As Integer
<BR>Detta funzione in Gambas sarà così dichiarata:
+
l'altra funzione essenziale è quella che ci permetterà di scrivere i dati nel ''device'' del Midi output, ossia di inviare dati al dispositivo esterno:
  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_write(snd_rawmidi_t * rawmidi, const void * buffer, size_t size)''
laddove il parametro ''in_rmidi'', trattandosi in questo caso di <SPAN style="text-decoration:underline">inviare</span> dati Midi, sarà posto a zero.
+
che in Gambas sarà dichiarata così:
 +
  Private Extern snd_rawmidi_write(out_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer
 +
A questa funzione esterna si passa l'<I>handle</i>, ricevuto dalla funzione ''snd_rawmidi_open ()'', l'indirizzo di un buffer contenente alcuni dati MIDI, e la quantità di dati da inviare ogni volta.
  
  
L'altra funzione esterna essenziale è quella che consentirà di inviare i dati grezzi ad un dispositivo Midi esterno:
+
Potrebbe sussitere un limite alla quantità di dati che questa funzione è capace di inviare. È possibile determinare quale sia la dimensione dell'output del buffer del driver chiamando la funzione esterna
  ''ssize_t snd_rawmidi_write(snd_rawmidi_t * rawmidi, const void * buffer, size_t size)''
+
  ''size_t snd_rawmidi_params_get_buffer_size (const snd_rawmidi_params_t * params)''
che in Gambas sarà dichiarata così:
+
la quale ritorna apputno la dimensione in byte disponibile del buffer di entrata e di uscita del subsistema ''RawMidi''.
  Private Extern snd_rawmidi_write(in_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer
+
Volendo, sarà possibile cambiare quella quantità di byte, chiamando la funzione
A questa funzione esterna si passa l'<I>handle</i>, ricevuto dalla funzione ''snd_rawmidi_open'', l'indirizzo di un buffer contenente alcuni dati MIDI, e la quantità di dati da inviare ogni volta.
+
  ''int snd_rawmidi_params_set_buffer_size (snd_rawmidi_t * rawmidi, snd_rawmidi_params_t * params, size_t val)''
  
  
 
===Modalità Blocking e Non-Blocking===
 
===Modalità Blocking e Non-Blocking===
 +
Di norma, un uscita Midi viene aperta in modalità bloccante (''Blocking''). Ciò significa che, quando vengono passati dei dati Midi alla funzione esterna ''snd_rawmidi_write()'', la stessa non ritornerà alcun valore sino a che quei dati non saranno stati inviati attraverso la porta output.
  
  
 +
In alternativa è possibile impostare la modalità di apertura non bloccante (''Non-Blocking'') attraverso la funzione:
 +
  ''int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)''
 +
che in Gambas dichiareremo così:
 +
Private Extern snd_rawmidi_nonblock(midiOut As Pointer, nonblock As Integer) as Integer
 +
e che in codice richiameremo così:
 +
err = snd_rawmidi_nonblock(handleOut, <FONT color=#B22222>1</font>)
 +
Nella modalità non bloccante la funzione ''snd_rawmidi_write()'' scrive nel driver output i dati presenti nel buffer imediatamente, consentendo così al programma di svolgere altre funzioni.
  
===Esempio===
+
Una cosa da tener presente, quando si imposta la modalità ''Non-Blocking'', è che se viene chiamata la funzione ''snd_rawmidi_close ()'' per chiudere una porta output del subsitema ''RawMidi'', immediatamente dopo aver utilizzato la funzione ''snd_rawmidi_write ()'', potrebbero perdersi alcuni dati ancora presenti nel driver.
 +
<BR>Per ovviare a questo problema è opportuno chiamare la funzione esterna:
 +
''int snd_rawmidi_drain (snd_rawmidi_t *rmidi)''
  
  
 +
===Chiudere il dispositivo Output===
 +
Per chiudere la porta di uscita dell'interfaccia ''RawMidi'', si utilizza semplicemente la funzione esterna
 +
''int snd_rawmidi_close (snd_rawmidi_t *rmidi)''
 +
che in Gambas dichiareremo così:
 +
Private Extern snd_rawmidi_close(midiOut As Pointer) as Integer
 +
e che in codice richiameremo così:
 +
err = snd_rawmidi_close(handleOut)
  
  
  
<FONT color=Red><B>Pagina in costruzione</b></font>
+
===Esempio===
 +
Di seguito un semplice esempio di invio di due Messaggi Midi: un ''Note-On'' ed un ''Note-Off'' al device output Midi dell'interfaccia ''RawMidi'' di Alsa:
 +
Library "libasound:2"
 +
 +
<FONT color=Gray>' ''int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Opens a New Connection To the RawMidi interface''</font>
 +
'''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_write (snd_rawmidi_t *rmidi, const void *buffer, size_t size)  --> Write MIDI bytes To MIDI stream''</font>
 +
'''Private''' Extern snd_rawmidi_write(rmidi As Pointer, buffer As Stream, size As Integer) As Integer
 +
 +
<FONT color=Gray>' ''const char * snd_strerror (int errnum)  --> Returns the message For an Error code''</font>
 +
'''Private''' Extern snd_strerror(errnum As Integer) As String
 +
 +
<FONT color=Gray>' ''int snd_rawmidi_close (snd_rawmidi_t *rmidi)  --> Close RawMidi handle''</font>
 +
'''Private''' Extern snd_rawmidi_close(rmidi As Pointer) As Integer
 +
 +
 +
'''Public''' Sub Form_Open()
 +
 +
  Dim posMid, err As Integer
 +
  Dim SND_RAWMIDI_SYNC As Byte = 4
 +
  Dim midiout, noteon, noteoff As Pointer
 +
  Dim nome_porta As String
 +
  Dim strOn, strOff As Stream
 +
 +
 +
<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]
 +
  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(0, VarPtr(midiout), nome_porta, SND_RAWMIDI_SYNC)
 +
    If err < 0 Then Error.Raise("Impossibile aprire la porta d'uscita del subsistema RawMidi: " & snd_strerror())
 +
   
 +
<FONT color=Gray>' ''Come mero esempio invieremo tramite il Midi output solo due Messaggi Midi: un NoteOn ed un NoteOff.''
 +
' ''Bisognerà inviare tre byte di dati per volta alla funzione "snd_rawmidi_write ()".''
 +
' ''Poiché è previsto un Pointer, per riempirlo con i tre byte, dovremo creare un'area allocata di memoria,''
 +
' ''e riempirla mediante la trasformazione dei Pointer in variabili di tipo "Stream", che passeremo alla predetta funzione:''</font>
 +
    noteon = Alloc(3)
 +
    noteoff = Alloc(3)
 +
   
 +
    strOn = Memory noteon For Write
 +
    strOff = Memory noteoff For Write
 +
   
 +
<FONT color=Gray>' ''Scriviamo nella memoria allocata, puntata ora da una variabile di tipo "Stream", un Messaggio "Note-On":''</font>
 +
      Write #strOn, 144 As Byte
 +
      Write #strOn, 60 As Byte
 +
      Write #strOn, 100 As Byte
 +
   
 +
<FONT color=Gray>' ''Il valore 3 sta a significare che saranno scritti nel dispositivo Midi output 3 byte fra quelli presenti nella variabile "stream",''
 +
' ''ossia i tre valori costitutivi del Messaggio Note On:''</font>
 +
    err = snd_rawmidi_write(midiout, strOn, <FONT color=#B22222>3</font>)
 +
    If err < 0 Then Error.Raise("Impossibile la scrittura al Midi output: " & snd_strerror(err))
 +
 +
<FONT color=Gray>' ''Attendiamo che la nota suoni per 1 secondo:''</font>
 +
    Wait 1
 +
 +
<FONT color=Gray>' ''Scriviamo nella memoria allocata, puntata ora da una variabile di tipo "Stream", un Messaggio "Note-Off":''</font>
 +
      Write #strOff, 128 As Byte
 +
      Write #strOff, 60 As Byte
 +
      Write #strOff, 0 As Byte
 +
 +
    err = snd_rawmidi_write(midiout, strOn, 3)
 +
    If err < 0 Then Error.Raise("Impossibile la scrittura al Midi output: " & snd_strerror(err))
 +
   
 +
 +
<FONT color=Gray>' ''Alla fine chiudiamo l'output Midi:''</font>
 +
    snd_rawmidi_close(midiout)
 +
   
 +
'''End'''

Versione delle 17:57, 15 giu 2014

Premessa

Il sistema Alsa consente di inviare dati Midi grezzi ad un dispositivo Midi esterno mediante il suo subsistema RawMidi.


Scrittura dei dati in uscita

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

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

l'altra funzione essenziale è quella che ci permetterà di scrivere i dati nel device del Midi output, ossia di inviare dati al dispositivo esterno:

ssize_t snd_rawmidi_write(snd_rawmidi_t * rawmidi, const void * buffer, size_t size)

che in Gambas sarà dichiarata così:

Private Extern snd_rawmidi_write(out_rmidi As Pointer, buffer As Pointer, size As Integer) As Integer

A questa funzione esterna si passa l'handle, ricevuto dalla funzione snd_rawmidi_open (), l'indirizzo di un buffer contenente alcuni dati MIDI, e la quantità di dati da inviare ogni volta.


Potrebbe sussitere un limite alla quantità di dati che questa funzione è capace di inviare. È possibile determinare quale sia la dimensione dell'output del buffer del driver chiamando la funzione esterna

size_t snd_rawmidi_params_get_buffer_size (const snd_rawmidi_params_t * params)

la quale ritorna apputno la dimensione in byte disponibile del buffer di entrata e di uscita del subsistema RawMidi. Volendo, sarà possibile cambiare quella quantità di byte, chiamando la funzione

int snd_rawmidi_params_set_buffer_size (snd_rawmidi_t * rawmidi, snd_rawmidi_params_t * params, size_t val)


Modalità Blocking e Non-Blocking

Di norma, un uscita Midi viene aperta in modalità bloccante (Blocking). Ciò significa che, quando vengono passati dei dati Midi alla funzione esterna snd_rawmidi_write(), la stessa non ritornerà alcun valore sino a che quei dati non saranno stati inviati attraverso la porta output.


In alternativa è possibile impostare la modalità di apertura non bloccante (Non-Blocking) attraverso la funzione:

 int snd_rawmidi_nonblock (snd_rawmidi_t *rmidi, int nonblock)

che in Gambas dichiareremo così:

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

e che in codice richiameremo così:

err = snd_rawmidi_nonblock(handleOut, 1)

Nella modalità non bloccante la funzione snd_rawmidi_write() scrive nel driver output i dati presenti nel buffer imediatamente, consentendo così al programma di svolgere altre funzioni.

Una cosa da tener presente, quando si imposta la modalità Non-Blocking, è che se viene chiamata la funzione snd_rawmidi_close () per chiudere una porta output del subsitema RawMidi, immediatamente dopo aver utilizzato la funzione snd_rawmidi_write (), potrebbero perdersi alcuni dati ancora presenti nel driver.
Per ovviare a questo problema è opportuno chiamare la funzione esterna:

int snd_rawmidi_drain (snd_rawmidi_t *rmidi)


Chiudere il dispositivo Output

Per chiudere la porta di uscita dell'interfaccia RawMidi, si utilizza semplicemente la funzione esterna

int snd_rawmidi_close (snd_rawmidi_t *rmidi)

che in Gambas dichiareremo così:

Private Extern snd_rawmidi_close(midiOut As Pointer) as Integer

e che in codice richiameremo così:

err = snd_rawmidi_close(handleOut)


Esempio

Di seguito un semplice esempio di invio di due Messaggi Midi: un Note-On ed un Note-Off al device output Midi dell'interfaccia RawMidi di Alsa:

Library "libasound:2"

' int snd_rawmidi_open (snd_rawmidi_t **in_rmidi, snd_rawmidi_t **out_rmidi, const char *name, int mode)  --> Opens a New Connection To the RawMidi interface
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_write (snd_rawmidi_t *rmidi, const void *buffer, size_t size)  --> Write MIDI bytes To MIDI stream
Private Extern snd_rawmidi_write(rmidi As Pointer, buffer As Stream, size As Integer) As Integer

' const char * snd_strerror (int errnum)  --> Returns the message For an Error code 
Private Extern snd_strerror(errnum As Integer) As String

' int snd_rawmidi_close (snd_rawmidi_t *rmidi)  --> Close RawMidi handle
Private Extern snd_rawmidi_close(rmidi As Pointer) As Integer


Public Sub Form_Open()

 Dim posMid, err As Integer
 Dim SND_RAWMIDI_SYNC As Byte = 4
 Dim midiout, noteon, noteoff As Pointer
 Dim nome_porta As String
 Dim strOn, strOff 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(0, VarPtr(midiout), nome_porta, SND_RAWMIDI_SYNC)
   If err < 0 Then Error.Raise("Impossibile aprire la porta d'uscita del subsistema RawMidi: " & snd_strerror())
   
' Come mero esempio invieremo tramite il Midi output solo due Messaggi Midi: un NoteOn ed un NoteOff.
' Bisognerà inviare tre byte di dati per volta alla funzione "snd_rawmidi_write ()".
' Poiché è previsto un Pointer, per riempirlo con i tre byte, dovremo creare un'area allocata di memoria,
' e riempirla mediante la trasformazione dei Pointer in variabili di tipo "Stream", che passeremo alla predetta funzione:
   noteon = Alloc(3)
   noteoff = Alloc(3)
   
   strOn = Memory noteon For Write
   strOff = Memory noteoff For Write
   
' Scriviamo nella memoria allocata, puntata ora da una variabile di tipo "Stream", un Messaggio "Note-On":
     Write #strOn, 144 As Byte
     Write #strOn, 60 As Byte
     Write #strOn, 100 As Byte
   
' Il valore 3 sta a significare che saranno scritti nel dispositivo Midi output 3 byte fra quelli presenti nella variabile "stream",
' ossia i tre valori costitutivi del Messaggio Note On:
   err = snd_rawmidi_write(midiout, strOn, 3)
   If err < 0 Then Error.Raise("Impossibile la scrittura al Midi output: " & snd_strerror(err))

' Attendiamo che la nota suoni per 1 secondo:
   Wait 1

' Scriviamo nella memoria allocata, puntata ora da una variabile di tipo "Stream", un Messaggio "Note-Off":
     Write #strOff, 128 As Byte
     Write #strOff, 60 As Byte
     Write #strOff, 0 As Byte

   err = snd_rawmidi_write(midiout, strOn, 3)
   If err < 0 Then Error.Raise("Impossibile la scrittura al Midi output: " & snd_strerror(err))
   

' Alla fine chiudiamo l'output Midi:
   snd_rawmidi_close(midiout)
   
End