Differenze tra le versioni di "Alsa e Gambas: Invio dei dati senza connessione della porta del programma con il Softsynth"

Da Gambas-it.org - Wikipedia.
Riga 1: Riga 1:
Per inviare utilmente dati Midi ad altro ''Client'' di ALSA, non è necessario connettere i due ''Client'' (l'applicativo Gambas ed il ''Softsynth'') mediante la funzione ''snd_seq_connect_to()'', purché si presti attenzione ad alcuni elementi che integrano due casi.
+
Per inviare utilmente dati Midi ad altro ''Client'' di ALSA, non è necessario connettere i due ''Client'' (l'applicativo Gambas ed il ''Softsynth'') mediante la funzione esterna di ALSA "snd_seq_connect_to()", purché si presti attenzione ad alcuni elementi che integrano due casi.
  
  
 
===1° caso===
 
===1° caso===
 
Nel primo caso il codice dovrà prevedere:
 
Nel primo caso il codice dovrà prevedere:
* la presenza della funzione di ALSA ''snd_seq_alloc_queue()'';
+
* la presenza della funzione di ALSA "snd_seq_alloc_queue()", la quale restituisce l'identificativo della coda (''queue'' )degli ''Eventi Midi ALSA'' da assegnarsi al membro "queue" della Struttura ''[https://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__event__t.html snd_seq_event_t]'';
* il membro ''.queue'' della Struttura relativa agli eventi Midi dovrà essere posto a zero;
+
* al membro ''dest_client'' e a quello ''dest_port'' della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del ''Client'' (''Softsynth''), al quale l'applicativo Gambas dovrà inviare i dati Midi.
* al membro ''.dest_id'' e a quello ''.dest_port'' della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del ''Client'' (''Softsynth''), al quale l'applicativo Gambas dovrà inviare i dati Midi.
+
Il dispositivo destinatario degli ''Eventi Midi ALSA'' sarà individuato, dunque, esclusivamente attraverso il suo numero identificativo e il numero della sua porta quale Client di ALSA. 
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
Private sndseq As Pointer
+
  Private Const <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> As Byte = 128   <FONT Color=gray>' ''Solitamente l'identificativo è 128''</font>
  Private Const cl_dest As Byte = 128
+
  Private Const <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> As Byte = 0
  Private Const po_dest As Byte = 0
 
 
   
 
   
 
   
 
   
  Library "libasound:2"
+
  Library "libasound:2.0.0"
 
   
 
   
 
  Public Struct snd_seq_event_t
 
  Public Struct snd_seq_event_t
Riga 21: Riga 20:
 
   tag As Byte
 
   tag As Byte
 
   queue As Byte
 
   queue As Byte
   tick_o_Tv_sec As Integer
+
   tick_o_tv_sec As Integer
   Tv_nsec As Integer
+
   tv_nsec As Integer
 
   source_client As Byte
 
   source_client As Byte
 
   source_port As Byte
 
   source_port As Byte
Riga 48: Riga 47:
 
  ' ''Returns the message for an error code.''</font>
 
  ' ''Returns the message for an error code.''</font>
 
  Private Extern snd_strerror(err As Integer) As Pointer
 
  Private Extern snd_strerror(err As Integer) As Pointer
 +
 +
<FONT Color=gray>' ''int snd_seq_client_id (snd_seq_t * seq)''
 +
' ''Get the client id.''</font>
 +
Private Extern snd_seq_client_id(seq As Pointer) As Integer
 
   
 
   
 
  <FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)''
 
  <FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)''
Riga 55: Riga 58:
 
  <FONT Color=gray>' ''int snd_seq_alloc_queue (snd_seq_t *handle)''
 
  <FONT Color=gray>' ''int snd_seq_alloc_queue (snd_seq_t *handle)''
 
  ' ''Allocate a queue.''</font>
 
  ' ''Allocate a queue.''</font>
  Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
+
  Private Extern <FONT Color=darkorange><B>snd_seq_alloc_queue</b></font>(handle As Pointer) As Integer
 
    
 
    
 
  <FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
 
  <FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
Riga 71: Riga 74:
 
   
 
   
 
  '''Public''' Sub Main()
 
  '''Public''' Sub Main()
    
+
 +
   Dim handle As Pointer
 +
  Dim rit As Integer
 
   Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 
   Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
   Dim porta_source, b As Byte
+
   Dim id, porta, que, b As Byte
 
   Dim ev As New Snd_seq_event_t
 
   Dim ev As New Snd_seq_event_t
    
+
   porta_source = Connessione()
+
   rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
+
   If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 +
 +
  id = snd_seq_client_id(handle)
 +
  If id < 0 Then Error.Raise("Errore: " & String@(snd_strerror(rit)))
 +
 +
  porta = snd_seq_create_simple_port(handle, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
 +
  If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")
 +
 +
  <FONT Color=darkorange><B>que</b></font> = <FONT Color=darkorange><B>snd_seq_alloc_queue</b></font>(handle)
 +
 
   With ev
 
   With ev
     <FONT Color=#B22222>.queue = 0</font>
+
     .queue = <FONT Color=darkorange><B>que</b></font>
     .source_client = 0
+
     .source_client = id
     .source_port = porta_source
+
     .source_port = porta
     <FONT Color=#B22222>.dest_client = cl_dest</font>
+
     .dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font>
     <FONT Color=#B22222>.dest_port = po_dest</font>
+
     .dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font>
 
     .channel = 0
 
     .channel = 0
 
   End With
 
   End With
       
+
     
   program_change(ev, 48)
+
   program_change(handle, ev, 48)
   
+
 
 
   For b = 0 To note.Max
 
   For b = 0 To note.Max
     Note_On(ev, note[b])
+
     Note_On(handle, ev, note[b])
 +
<FONT Color=gray>' ''Imposta la durata dell'esecuzione della nota.''
 +
' ''Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".''
 +
' ''Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.</font>
 
     Wait 1
 
     Wait 1
     Note_Off(ev, note[b])
+
     Note_Off(handle, ev, note[b])
 
   Next
 
   Next
   
+
 
   snd_seq_close(sndseq)
+
   snd_seq_close(handle)
 
 
'''End'''
 
 
   
 
   
 
'''Private''' Function Connessione() As Byte
 
 
 
  Dim rit, porta As Integer
 
 
 
  rit = snd_seq_open(VarPtr(sndseq), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
  If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 
   
 
  porta = snd_seq_create_simple_port(sndseq, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
 
  If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")
 
     
 
  <FONT Color=#B22222>snd_seq_alloc_queue(sndseq)</font>
 
 
 
  Return porta
 
 
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure program_change(p As Pointer, ev_prch As Snd_seq_event_t, strum As Integer)
 
   
 
   
'''Private''' Procedure program_change(ev_prch As Snd_seq_event_t, strum As Integer)
 
 
 
 
   With ev_prch
 
   With ev_prch
 
     .type = SND_SEQ_EVENT_PGMCHANGE
 
     .type = SND_SEQ_EVENT_PGMCHANGE
 
     .value = strum
 
     .value = strum
 
   End With
 
   End With
   
+
   InviaEvento(ev_prch)
+
   InviaEvento(p, ev_prch)
 
+
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure Note_On(p As Pointer, ev_nton As Snd_seq_event_t, nota As Byte)
 
   
 
   
'''Private''' Procedure Note_On(ev_nton As Snd_seq_event_t, nota As Byte)
 
 
 
 
   With ev_nton
 
   With ev_nton
 
     .type = SND_SEQ_EVENT_NOTEON
 
     .type = SND_SEQ_EVENT_NOTEON
Riga 136: Riga 134:
 
     .velocity = 64
 
     .velocity = 64
 
   End With
 
   End With
 
+
   InviaEvento(ev_nton)
+
   InviaEvento(p, ev_nton)
 
+
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure Note_Off(p As Pointer, ev_ntoff As Snd_seq_event_t, nota As Byte)
 
   
 
   
'''Private''' Procedure Note_Off(ev_ntoff As Snd_seq_event_t, nota As Byte)
 
 
 
 
   With ev_ntoff
 
   With ev_ntoff
 
     .type = SND_SEQ_EVENT_NOTEOFF
 
     .type = SND_SEQ_EVENT_NOTEOFF
Riga 149: Riga 146:
 
     .velocity = 0
 
     .velocity = 0
 
   End With
 
   End With
 
+
   InviaEvento(ev_ntoff)
+
   InviaEvento(p, ev_ntoff)
 
+
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure InviaEvento(p As Pointer, evento As Snd_seq_event_t)
 
   
 
   
'''Private''' Procedure InviaEvento(evento As Snd_seq_event_t)
+
   snd_seq_event_output(p, evento)
 
 
   snd_seq_event_output(sndseq, evento)
 
 
 
  snd_seq_drain_output(sndseq)
 
 
    
 
    
 +
  snd_seq_drain_output(p)
 +
 
  '''End'''
 
  '''End'''
 
  
  
 
===2° caso===
 
===2° caso===
 
Nel secondo caso si dovrà tenere conto di quanto segue:
 
Nel secondo caso si dovrà tenere conto di quanto segue:
* viene eliminata la funzione esterna specifica di Alsa per la creazione della porta del Client applicativo;
+
* non viene utilizzata la funzione esterna (usata invece nel caso precedente) specifica di ALSA per la creazione della porta del Client applicativo;
* al membro ''.queue'' della Struttura relativa agli eventi Midi dovrà essere assegnato il valore della Costante Alsa "''SND_SEQ_QUEUE_DIRECT''" (253);
+
* al membro ''queue'' della Struttura relativa agli eventi Midi dovrà essere assegnato il valore della Costante Alsa "SND_SEQ_QUEUE_DIRECT" (253);
* al membro ''.dest_id'' e a quello ''.dest_port'' della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del ''Client'' (''Softsynth''), al quale l'applicativo Gambas dovrà inviare i dati Midi.
+
* al membro ''dest_id'' e a quello ''dest_port'' della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del ''Client'' (''Softsynth''), al quale l'applicativo Gambas dovrà inviare i dati Midi.
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
  Library "libasound:2"
+
Private Const <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> As Byte = 128  <FONT Color=gray>' ''Solitamente l'identificativo è 128''</font>
 +
Private Const <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> As Byte = 0
 +
 +
 +
  Library "libasound:2.0.0"
 
   
 
   
 
  Public Struct snd_seq_event_t
 
  Public Struct snd_seq_event_t
Riga 179: Riga 178:
 
   tag As Byte
 
   tag As Byte
 
   queue As Byte
 
   queue As Byte
   tick_o_Tv_sec As Integer
+
   tick_o_tv_sec As Integer
   Tv_nsec As Integer
+
   tv_nsec As Integer
 
   source_client As Byte
 
   source_client As Byte
 
   source_port As Byte
 
   source_port As Byte
Riga 192: Riga 191:
 
   value As Integer
 
   value As Integer
 
  End Struct
 
  End Struct
 
+
 
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
 
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
  Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
+
  Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
 +
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
 +
Private Const <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> As Byte = 253
 +
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE
 
    
 
    
Riga 204: Riga 206:
 
  ' ''Returns the message for an error code.''</font>
 
  ' ''Returns the message for an error code.''</font>
 
  Private Extern snd_strerror(err As Integer) As Pointer
 
  Private Extern snd_strerror(err As Integer) As Pointer
   
+
 +
<FONT Color=gray>' ''int snd_seq_client_id (snd_seq_t * seq)''
 +
' ''Get the client id.''</font>
 +
Private Extern snd_seq_client_id(seq As Pointer) As Integer
 +
 +
<FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)''
 +
' ''Create a port - simple version.''</font>
 +
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
 +
 
 +
<FONT Color=gray>' ''int snd_seq_alloc_queue (snd_seq_t *handle)''
 +
' ''Allocate a queue.''</font>
 +
Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
 +
 
 
  <FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
 
  <FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
 
  ' ''Output an event.''</font>
 
  ' ''Output an event.''</font>
Riga 219: Riga 233:
 
   
 
   
 
  '''Public''' Sub Main()
 
  '''Public''' Sub Main()
    
+
   Dim sndseq As Pointer
+
   Dim handle As Pointer
 +
   Dim rit As Integer
 
   Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 
   Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
   Dim b As Byte
+
   Dim id, porta, b As Byte
   Dim evento As New Snd_seq_event_t
+
   Dim ev As New Snd_seq_event_t
    
+
   sndseq = Connessione()
+
   rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
+
   If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
   With evento
+
     <FONT Color=#B22222>.queue = SND_SEQ_QUEUE_DIRECT</font>
+
  id = snd_seq_client_id(handle)
     <FONT Color=#B22222>.dest_client = 128</font>
+
  If id < 0 Then Error.Raise("Errore: " & String@(snd_strerror(rit)))
     <FONT Color=#B22222>.dest_port = 0</font>
+
 +
  porta = snd_seq_create_simple_port(handle, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
 +
  If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")
 +
 +
   With ev
 +
     .queue = <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font>
 +
     .source_client = id
 +
    .source_port = porta
 +
    .dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font>
 +
     .dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font>
 
     .channel = 0
 
     .channel = 0
 
   End With
 
   End With
       
+
     
   program_change(sndseq, evento, 48)
+
   program_change(handle, ev, 48)
   
+
 
 
   For b = 0 To note.Max
 
   For b = 0 To note.Max
     Note_On(sndseq, evento, note[b])
+
     Note_On(handle, ev, note[b])
    InviaEvento(sndseq)
+
<FONT Color=gray>' ''Imposta la durata dell'esecuzione della nota.''
 +
' ''Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".''
 +
' ''Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.</font>
 
     Wait 1
 
     Wait 1
     Note_Off(sndseq, evento, note[b])
+
     Note_Off(handle, ev, note[b])
    InviaEvento(sndseq)
 
 
   Next
 
   Next
 
+
 
   snd_seq_close(sndseq)
+
   snd_seq_close(handle)
 
 
'''End'''
 
 
 
   
 
   
'''Private''' Function Connessione() As Pointer
 
 
 
  Dim snd As Pointer
 
  Dim rit, porta As Integer
 
 
 
  rit = snd_seq_open(VarPtr(snd), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
  If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 
         
 
  Return snd
 
 
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure program_change(p As Pointer, ev_prch As Snd_seq_event_t, strum As Integer)
 
   
 
   
'''Private''' Procedure program_change(pc_seq As Pointer, ev_prch As Snd_seq_event_t, strum As Integer)
 
 
 
 
   With ev_prch
 
   With ev_prch
 
     .type = SND_SEQ_EVENT_PGMCHANGE
 
     .type = SND_SEQ_EVENT_PGMCHANGE
 
     .value = strum
 
     .value = strum
 
   End With
 
   End With
 
+
   
  <FONT Color=gray>' ''Inserisce l'evento "Program_Change" nel buffer:''</font>
+
   InviaEvento(p, ev_prch)
   snd_seq_event_output(pc_seq, ev_prch)
+
 
 
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure Note_On(p As Pointer, ev_nton As Snd_seq_event_t, nota As Byte)
 
   
 
   
'''Private''' Procedure Note_On(nto As Pointer, ev_nton As Snd_seq_event_t, nota As Byte)
 
 
 
 
   With ev_nton
 
   With ev_nton
 
     .type = SND_SEQ_EVENT_NOTEON
 
     .type = SND_SEQ_EVENT_NOTEON
Riga 282: Riga 291:
 
     .velocity = 64
 
     .velocity = 64
 
   End With
 
   End With
 +
 +
  InviaEvento(p, ev_nton)
 
    
 
    
<FONT Color=gray>' ''Inserisce l'evento "Note_On" nel buffer:''</font>
 
  snd_seq_event_output(nto, ev_nton)
 
 
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure Note_Off(p As Pointer, ev_ntoff As Snd_seq_event_t, nota As Byte)
 
   
 
   
'''Private''' Procedure Note_Off(ntf As Pointer, ev_ntoff As Snd_seq_event_t, nota As Byte)
 
 
 
 
   With ev_ntoff
 
   With ev_ntoff
 
     .type = SND_SEQ_EVENT_NOTEOFF
 
     .type = SND_SEQ_EVENT_NOTEOFF
Riga 296: Riga 303:
 
     .velocity = 0
 
     .velocity = 0
 
   End With
 
   End With
 
+
   
  <FONT Color=gray>' ''Inserisce l'evento "Note_Off" nel buffer:''</font>
+
   InviaEvento(p, ev_ntoff)
   snd_seq_event_output(ntf, ev_ntoff)
+
 
 
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
'''Private''' Procedure InviaEvento(p As Pointer, evento As Snd_seq_event_t)
 
   
 
   
'''Private''' Procedure InviaEvento(seqP As Pointer)
+
  snd_seq_event_output(p, evento)
 +
 
 +
  snd_seq_drain_output(p)
 
   
 
   
<FONT Color=gray>' ''Invia l'intero contenuto del buffer ad Alsa:''</font>
 
  snd_seq_drain_output(seqP)
 
 
 
 
  '''End'''
 
  '''End'''
  
  
  
===Esempio più essenziale per invio dati Midi===
+
===Esempio più essenziale per invio diretto degli Eventi Midi ALSA===
Mostriamo ora la modalità più breve ed essenziale per inviare ad altro Client di Alsa alcuni eventi Midi, e nella quale non è prevista la creazione di porte del nostro Client applicativo:
+
Mostriamo ora la modalità più breve ed essenziale per inviare ad altro Client di Alsa alcuni eventi Midi, e nella quale non è prevista la creazione di porte del nostro Client applicativo.
  Library "libasound:2"
+
<BR>Si utilizzerà in questo caso la funzione esterna di ALSA: "snd_seq_event_output_direct()" per invio diretto di ciaascun Evento Midi ALSA.
 +
Private Const <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> As Byte = 128  <FONT Color=gray>' ''Solitamente l'identificativo è 128''</font>
 +
Private Const <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> As Byte = 0
 +
 +
  Library "libasound:2.0.0"
 
   
 
   
 
  Public Struct snd_seq_event_t
 
  Public Struct snd_seq_event_t
Riga 321: Riga 331:
 
   tag As Byte
 
   tag As Byte
 
   queue As Byte
 
   queue As Byte
   tick_o_Tv_sec As Integer
+
   tick_o_tv_sec As Integer
   Tv_nsec As Integer
+
   tv_nsec As Integer
 
   source_client As Byte
 
   source_client As Byte
 
   source_port As Byte
 
   source_port As Byte
Riga 336: Riga 346:
 
   
 
   
 
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
 
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
 +
Private Const <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> As Byte = 253
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
 
 
   
 
   
 
  <FONT Color=gray>' ''int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)''
 
  <FONT Color=gray>' ''int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)''
Riga 349: Riga 359:
 
  <FONT Color=gray>' ''int snd_seq_event_output_direct (snd_seq_t *handle, snd_seq_event_t *ev)''
 
  <FONT Color=gray>' ''int snd_seq_event_output_direct (snd_seq_t *handle, snd_seq_event_t *ev)''
 
  ' ''Output an event directly to the sequencer NOT through output buffer.''</font>
 
  ' ''Output an event directly to the sequencer NOT through output buffer.''</font>
  Private Extern snd_seq_event_output_direct(handle As Pointer, ev As Snd_seq_event_t) As Integer
+
  Private Extern <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(handle As Pointer, ev As Snd_seq_event_t) As Integer
 
   
 
   
 
  <FONT Color=gray>' ''int snd_seq_close (snd_seq_t *handle)
 
  <FONT Color=gray>' ''int snd_seq_close (snd_seq_t *handle)
Riga 361: Riga 371:
 
   Dim evento As New Snd_seq_event_t
 
   Dim evento As New Snd_seq_event_t
 
   Dim rit As Integer
 
   Dim rit As Integer
 
+
 
   snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
   snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0)
 
   If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 
   If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 
+
 
   With evento
 
   With evento
 
     .type = SND_SEQ_EVENT_NOTEON
 
     .type = SND_SEQ_EVENT_NOTEON
     .queue = SND_SEQ_QUEUE_DIRECT
+
     .queue = <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font>
     .dest_client = 128
+
     .dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font>
     .dest_port = 0
+
     .dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font>
 
     .channel = 0
 
     .channel = 0
 
     .note = 64
 
     .note = 64
 
     .velocity = 100
 
     .velocity = 100
 
   End With
 
   End With
 
+
   snd_seq_event_output_direct(seq, evento)
+
   <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(seq, evento)
   
+
 +
<FONT Color=gray>' ''Imposta la durata dell'esecuzione della nota.''
 +
' ''Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".''
 +
' ''Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.</font>
 
   Wait 1
 
   Wait 1
   
+
 
   evento.type = SND_SEQ_EVENT_NOTEOFF
 
   evento.type = SND_SEQ_EVENT_NOTEOFF
 
   evento.velocity = 0
 
   evento.velocity = 0
   snd_seq_event_output_direct(seq, evento)
+
   <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(seq, evento)
 
+
 
   snd_seq_close(seq)
 
   snd_seq_close(seq)
 
+
 
  '''End'''
 
  '''End'''

Versione delle 17:16, 23 gen 2022

Per inviare utilmente dati Midi ad altro Client di ALSA, non è necessario connettere i due Client (l'applicativo Gambas ed il Softsynth) mediante la funzione esterna di ALSA "snd_seq_connect_to()", purché si presti attenzione ad alcuni elementi che integrano due casi.


1° caso

Nel primo caso il codice dovrà prevedere:

  • la presenza della funzione di ALSA "snd_seq_alloc_queue()", la quale restituisce l'identificativo della coda (queue )degli Eventi Midi ALSA da assegnarsi al membro "queue" della Struttura snd_seq_event_t;
  • al membro dest_client e a quello dest_port della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del Client (Softsynth), al quale l'applicativo Gambas dovrà inviare i dati Midi.

Il dispositivo destinatario degli Eventi Midi ALSA sarà individuato, dunque, esclusivamente attraverso il suo numero identificativo e il numero della sua porta quale Client di ALSA.

Mostriamo un esempio pratico:

Private Const CLIENT_DESTINATARIO As Byte = 128   ' Solitamente l'identificativo è 128
Private Const PORTA_DESTINATARIO As Byte = 0


Library "libasound:2.0.0"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_o_tv_sec As Integer
  tv_nsec As Integer
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
  channel As Byte
  note As Byte
  velocity As Byte
  off_velocity As Byte
  param As Integer
  value As Integer
End Struct

Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE
 
' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(err As Integer) As Pointer

' int snd_seq_client_id (snd_seq_t * seq)
' Get the client id.
Private Extern snd_seq_client_id(seq As Pointer) As Integer

' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
' Create a port - simple version.
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
 
' int snd_seq_alloc_queue (snd_seq_t *handle)
' Allocate a queue.
Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
 
' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
' Output an event.
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)

' int snd_seq_drain_output (snd_seq_t * seq)
' Drain output buffer to sequencer.
Private Extern snd_seq_drain_output(seq As Pointer) As Integer

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Public Sub Main()

 Dim handle As Pointer
 Dim rit As Integer
 Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 Dim id, porta, que, b As Byte
 Dim ev As New Snd_seq_event_t

 rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
 If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))

 id = snd_seq_client_id(handle)
 If id < 0 Then Error.Raise("Errore: " & String@(snd_strerror(rit)))

 porta = snd_seq_create_simple_port(handle, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
 If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")

 que = snd_seq_alloc_queue(handle)

 With ev
   .queue = que
   .source_client = id
   .source_port = porta
   .dest_client = CLIENT_DESTINATARIO
   .dest_port = PORTA_DESTINATARIO
   .channel = 0
 End With
     
 program_change(handle, ev, 48)
  
 For b = 0 To note.Max
   Note_On(handle, ev, note[b])
' Imposta la durata dell'esecuzione della nota.
' Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".
' Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.
   Wait 1
   Note_Off(handle, ev, note[b])
 Next
 
 snd_seq_close(handle)

End

Private Procedure program_change(p As Pointer, ev_prch As Snd_seq_event_t, strum As Integer)

 With ev_prch
   .type = SND_SEQ_EVENT_PGMCHANGE
   .value = strum
 End With

 InviaEvento(p, ev_prch)
 
End

Private Procedure Note_On(p As Pointer, ev_nton As Snd_seq_event_t, nota As Byte)

 With ev_nton
   .type = SND_SEQ_EVENT_NOTEON
   .note = nota
   .velocity = 64
 End With

 InviaEvento(p, ev_nton)
 
End

Private Procedure Note_Off(p As Pointer, ev_ntoff As Snd_seq_event_t, nota As Byte)

 With ev_ntoff
   .type = SND_SEQ_EVENT_NOTEOFF
   .note = nota
   .velocity = 0
 End With

 InviaEvento(p, ev_ntoff)

End

Private Procedure InviaEvento(p As Pointer, evento As Snd_seq_event_t)

 snd_seq_event_output(p, evento)
 
 snd_seq_drain_output(p)

End


2° caso

Nel secondo caso si dovrà tenere conto di quanto segue:

  • non viene utilizzata la funzione esterna (usata invece nel caso precedente) specifica di ALSA per la creazione della porta del Client applicativo;
  • al membro queue della Struttura relativa agli eventi Midi dovrà essere assegnato il valore della Costante Alsa "SND_SEQ_QUEUE_DIRECT" (253);
  • al membro dest_id e a quello dest_port della Struttura relativa agli eventi Midi dovranno essere rispettivamente assegnati i valori dell'Id e della porta del Client (Softsynth), al quale l'applicativo Gambas dovrà inviare i dati Midi.

Mostriamo un esempio pratico:

Private Const CLIENT_DESTINATARIO As Byte = 128   ' Solitamente l'identificativo è 128
Private Const PORTA_DESTINATARIO As Byte = 0


Library "libasound:2.0.0"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_o_tv_sec As Integer
  tv_nsec As Integer
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
  channel As Byte
  note As Byte
  velocity As Byte
  off_velocity As Byte
  param As Integer
  value As Integer
End Struct

Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE
 
' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(err As Integer) As Pointer

' int snd_seq_client_id (snd_seq_t * seq)
' Get the client id.
Private Extern snd_seq_client_id(seq As Pointer) As Integer

' int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)
' Create a port - simple version.
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
 
' int snd_seq_alloc_queue (snd_seq_t *handle)
' Allocate a queue.
Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
 
' int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)
' Output an event.
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)

' int snd_seq_drain_output (snd_seq_t * seq)
' Drain output buffer to sequencer.
Private Extern snd_seq_drain_output(seq As Pointer) As Integer

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Public Sub Main()

 Dim handle As Pointer
 Dim rit As Integer
 Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 Dim id, porta, b As Byte
 Dim ev As New Snd_seq_event_t

 rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0)
 If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))

 id = snd_seq_client_id(handle)
 If id < 0 Then Error.Raise("Errore: " & String@(snd_strerror(rit)))

 porta = snd_seq_create_simple_port(handle, "porta_", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
 If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")

 With ev
   .queue = SND_SEQ_QUEUE_DIRECT
   .source_client = id
   .source_port = porta
   .dest_client = CLIENT_DESTINATARIO
   .dest_port = PORTA_DESTINATARIO
   .channel = 0
 End With
     
 program_change(handle, ev, 48)
  
 For b = 0 To note.Max
   Note_On(handle, ev, note[b])
' Imposta la durata dell'esecuzione della nota.
' Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".
' Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.
   Wait 1
   Note_Off(handle, ev, note[b])
 Next
 
 snd_seq_close(handle)

End

Private Procedure program_change(p As Pointer, ev_prch As Snd_seq_event_t, strum As Integer)

 With ev_prch
   .type = SND_SEQ_EVENT_PGMCHANGE
   .value = strum
 End With

 InviaEvento(p, ev_prch)
 
End

Private Procedure Note_On(p As Pointer, ev_nton As Snd_seq_event_t, nota As Byte)

 With ev_nton
   .type = SND_SEQ_EVENT_NOTEON
   .note = nota
   .velocity = 64
 End With

 InviaEvento(p, ev_nton)
 
End

Private Procedure Note_Off(p As Pointer, ev_ntoff As Snd_seq_event_t, nota As Byte)

 With ev_ntoff
   .type = SND_SEQ_EVENT_NOTEOFF
   .note = nota
   .velocity = 0
 End With

 InviaEvento(p, ev_ntoff)

End

Private Procedure InviaEvento(p As Pointer, evento As Snd_seq_event_t)

 snd_seq_event_output(p, evento)
 
 snd_seq_drain_output(p)

End


Esempio più essenziale per invio diretto degli Eventi Midi ALSA

Mostriamo ora la modalità più breve ed essenziale per inviare ad altro Client di Alsa alcuni eventi Midi, e nella quale non è prevista la creazione di porte del nostro Client applicativo.
Si utilizzerà in questo caso la funzione esterna di ALSA: "snd_seq_event_output_direct()" per invio diretto di ciaascun Evento Midi ALSA.

Private Const CLIENT_DESTINATARIO As Byte = 128   ' Solitamente l'identificativo è 128
Private Const PORTA_DESTINATARIO As Byte = 0

Library "libasound:2.0.0"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_o_tv_sec As Integer
  tv_nsec As Integer
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
  channel As Byte
  note As Byte
  velocity As Byte
  off_velocity As Byte
  param As Integer
  value As Integer
End Struct

Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF

' int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer

' const char * snd_strerror (int errnum)
' Returns the message for an error code.
Private Extern snd_strerror(err As Integer) As Pointer

' int snd_seq_event_output_direct (snd_seq_t *handle, snd_seq_event_t *ev)
' Output an event directly to the sequencer NOT through output buffer.
Private Extern snd_seq_event_output_direct(handle As Pointer, ev As Snd_seq_event_t) As Integer

' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer


Public Sub Main()

 Dim seq As Pointer
 Dim evento As New Snd_seq_event_t
 Dim rit As Integer

 snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0)
 If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))

 With evento
   .type = SND_SEQ_EVENT_NOTEON
   .queue = SND_SEQ_QUEUE_DIRECT
   .dest_client = CLIENT_DESTINATARIO
   .dest_port = PORTA_DESTINATARIO
   .channel = 0
   .note = 64
   .velocity = 100
 End With

 snd_seq_event_output_direct(seq, evento)

' Imposta la durata dell'esecuzione della nota.
' Va precisato che l'uso della funzione "Wait" NON è un modo coerente con il protocollo di ALSA per la temporizzazione degli Eventi Midi: dato che ALSA usa a tale fine la cosiddetta "marcatura degli Eventi Midi" assegnando degli opportuni valori nel membro "flags" e in quelli del "Timestamp" della Struttura "snd_seq_event_t".
' Qui si fa uso della funzione "Wait" soltanto per meri motivi didattici ed esemplificativi del funzionamento degli altri aspetti trattati in questa pagina.
 Wait 1

 evento.type = SND_SEQ_EVENT_NOTEOFF
 evento.velocity = 0
 snd_seq_event_output_direct(seq, evento)

 snd_seq_close(seq)

End