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 9: Riga 9:
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
 +
Private sndseq As Pointer
 +
Private Const cl_dest As Byte = 128
 +
Private Const po_dest As Byte = 0
 +
 +
 +
Library "libasound:2"
 +
 
  Public Struct snd_seq_event
 
  Public Struct snd_seq_event
 
   type As Byte
 
   type As Byte
Riga 28: Riga 35:
 
  End Struct
 
  End Struct
 
   
 
   
Private sndseq As Pointer
+
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Const cl_dest As Byte = 128
+
  Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
  Private Const po_dest As Byte = 0
+
  Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
+
  Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
Library "libasound:2"
 
 
Private SND_SEQ_OPEN_OUTPUT As Integer = 1
 
  Private SND_SEQ_PORT_CAP_READ As Integer = 1
 
  Private SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
 
  Private SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1 * CInt(2 ^ 20)
 
 
  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
+
 
 
 
  <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)''
 
  ' ''Open the ALSA sequencer.''</font>
 
  ' ''Open the ALSA sequencer.''</font>
Riga 76: Riga 76:
 
   Dim ev As New Snd_seq_event
 
   Dim ev As New Snd_seq_event
 
    
 
    
  porta_source = Connessione()
+
  porta_source = Connessione()
 
    
 
    
  With ev
+
  With ev
    <FONT Color=#B22222>.queue = 0</font>
+
    <FONT Color=#B22222>.queue = 0</font>
    .source_client = 0
+
    .source_client = 0
    .source_port = porta_source
+
    .source_port = porta_source
    <FONT Color=#B22222>.dest_client = cl_dest</font>
+
    <FONT Color=#B22222>.dest_client = cl_dest</font>
    <FONT Color=#B22222>.dest_port = po_dest</font>
+
    <FONT Color=#B22222>.dest_port = po_dest</font>
    .channel = 0
+
    .channel = 0
  End With
+
  End With
 
          
 
          
  program_change(ev, 48)
+
  program_change(ev, 48)
 
      
 
      
  For b = 0 To note.Max
+
  For b = 0 To note.Max
    Note_On(ev, note[b])
+
    Note_On(ev, note[b])
    Sleep 1
+
    Wait 1
    Note_Off(ev, note[b])
+
    Note_Off(ev, note[b])
  Next
+
  Next
 
      
 
      
  snd_seq_close(sndseq)
+
  snd_seq_close(sndseq)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 104: Riga 104:
 
   Dim rit, porta As Integer
 
   Dim rit, porta As Integer
 
    
 
    
  rit = snd_seq_open(VarPtr(sndseq), "default", SND_SEQ_OPEN_OUTPUT, 0)
+
  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)))
+
  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)
+
  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 !")
+
  If porta < 0 Then Error.Raise("Impossibile creare la porta di uscita dati ALSA !")
 
        
 
        
  <FONT Color=#B22222>snd_seq_alloc_queue(sndseq)</font>
+
  <FONT Color=#B22222>snd_seq_alloc_queue(sndseq)</font>
 
    
 
    
  Return porta
+
  Return porta
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 119: Riga 119:
 
  '''Private''' Procedure program_change(ev_prch As Snd_seq_event, strum As Integer)
 
  '''Private''' Procedure program_change(ev_prch As Snd_seq_event, 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(ev_prch)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 131: Riga 131:
 
  '''Private''' Procedure Note_On(ev_nton As Snd_seq_event, nota As Byte)
 
  '''Private''' Procedure Note_On(ev_nton As Snd_seq_event, nota As Byte)
 
    
 
    
  With ev_nton
+
  With ev_nton
    .type = SND_SEQ_EVENT_NOTEON
+
    .type = SND_SEQ_EVENT_NOTEON
    .note = nota
+
    .note = nota
    .velocity = 64
+
    .velocity = 64
  End With
+
  End With
 
    
 
    
  InviaEvento(ev_nton)
+
  InviaEvento(ev_nton)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 144: Riga 144:
 
  '''Private''' Procedure Note_Off(ev_ntoff As Snd_seq_event, nota As Byte)
 
  '''Private''' Procedure Note_Off(ev_ntoff As Snd_seq_event, nota As Byte)
 
    
 
    
  With ev_ntoff
+
  With ev_ntoff
    .type = SND_SEQ_EVENT_NOTEOFF
+
    .type = SND_SEQ_EVENT_NOTEOFF
    .note = nota
+
    .note = nota
    .velocity = 0
+
    .velocity = 0
  End With
+
  End With
 
    
 
    
  InviaEvento(ev_ntoff)
+
  InviaEvento(ev_ntoff)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 157: Riga 157:
 
  '''Private''' Procedure InviaEvento(evento As Snd_seq_event)
 
  '''Private''' Procedure InviaEvento(evento As Snd_seq_event)
 
    
 
    
  snd_seq_event_output(sndseq, evento)
+
  snd_seq_event_output(sndseq, evento)
 
    
 
    
  snd_seq_drain_output(sndseq)
+
  snd_seq_drain_output(sndseq)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 172: Riga 172:
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
  Public Struct snd_seq_event
+
Library "libasound:2"
 +
 +
  Public Struct snd_seq_event_t
 
   type As Byte
 
   type As Byte
 
   flags As Byte
 
   flags As Byte
Riga 190: Riga 192:
 
   value As Integer
 
   value As Integer
 
  End Struct
 
  End Struct
+
 
+
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Library "libasound:2"
+
  Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
 
  Private SND_SEQ_OPEN_OUTPUT As Integer = 1
 
  Private SND_SEQ_QUEUE_DIRECT As Byte = 253
 
 
  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 224: Riga 223:
 
   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 b As Byte
   Dim evento As New Snd_seq_event
+
   Dim evento As New Snd_seq_event_t
 
    
 
    
  sndseq = Connessione()
+
  sndseq = Connessione()
 
    
 
    
  With evento
+
  With evento
    <FONT Color=#B22222>.queue = SND_SEQ_QUEUE_DIRECT</font>
+
    <FONT Color=#B22222>.queue = SND_SEQ_QUEUE_DIRECT</font>
    <FONT Color=#B22222>.dest_client = 128</font>
+
    <FONT Color=#B22222>.dest_client = 128</font>
    <FONT Color=#B22222>.dest_port = 0</font>
+
    <FONT Color=#B22222>.dest_port = 0</font>
    .channel = 0
+
    .channel = 0
  End With
+
  End With
 
          
 
          
  program_change(sndseq, evento, 48)
+
  program_change(sndseq, evento, 48)
 
      
 
      
  For b = 0 To note.Max
+
  For b = 0 To note.Max
    Note_On(sndseq, evento, note[b])
+
    Note_On(sndseq, evento, note[b])
    InviaEvento(sndseq)
+
    InviaEvento(sndseq)
    Sleep 1
+
    Wait 1
    Note_Off(sndseq, evento, note[b])
+
    Note_Off(sndseq, evento, note[b])
    InviaEvento(sndseq)
+
    InviaEvento(sndseq)
  Next
+
  Next
   
+
 
  snd_seq_close(sndseq)
+
  snd_seq_close(sndseq)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 255: Riga 254:
 
   Dim rit, porta As Integer
 
   Dim rit, porta As Integer
 
    
 
    
  rit = snd_seq_open(VarPtr(snd), "default", SND_SEQ_OPEN_OUTPUT, 0)
+
  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)))
+
  If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit)))
 
            
 
            
 
   Return snd
 
   Return snd
Riga 265: Riga 264:
 
  '''Private''' Procedure program_change(pc_seq As Pointer, ev_prch As Snd_seq_event, strum As Integer)
 
  '''Private''' Procedure program_change(pc_seq As Pointer, ev_prch As Snd_seq_event, 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>
 
  <FONT Color=gray>' ''Inserisce l'evento "Program_Change" nel buffer:''</font>
  snd_seq_event_output(pc_seq, ev_prch)
+
  snd_seq_event_output(pc_seq, ev_prch)
 
    
 
    
 
  '''End'''
 
  '''End'''
 
   
 
   
 
   
 
   
  '''Private''' Procedure Note_On(nto As Pointer, ev_nton As Snd_seq_event, nota As Byte)
+
  '''Private''' Procedure Note_On(nto 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
 
    
 
    
  With ev_nton
 
    .type = SND_SEQ_EVENT_NOTEON
 
    .note = nota
 
    .velocity = 64
 
  End With
 
 
 
 
  <FONT Color=gray>' ''Inserisce l'evento "Note_On" nel buffer:''</font>
 
  <FONT Color=gray>' ''Inserisce l'evento "Note_On" nel buffer:''</font>
  snd_seq_event_output(nto, ev_nton)
+
  snd_seq_event_output(nto, ev_nton)
 
    
 
    
 
  '''End'''
 
  '''End'''
 
   
 
   
 
   
 
   
  '''Private''' Procedure Note_Off(ntf As Pointer, ev_ntoff As Snd_seq_event, 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
    .note = nota
+
    .note = nota
    .velocity = 0
+
    .velocity = 0
  End With
+
  End With
 
    
 
    
 
  <FONT Color=gray>' ''Inserisce l'evento "Note_Off" nel buffer:''</font>
 
  <FONT Color=gray>' ''Inserisce l'evento "Note_Off" nel buffer:''</font>
  snd_seq_event_output(ntf, ev_ntoff)
+
  snd_seq_event_output(ntf, ev_ntoff)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 307: Riga 306:
 
   
 
   
 
  <FONT Color=gray>' ''Invia l'intero contenuto del buffer ad Alsa:''</font>
 
  <FONT Color=gray>' ''Invia l'intero contenuto del buffer ad Alsa:''</font>
  snd_seq_drain_output(seqP)
+
  snd_seq_drain_output(seqP)
 
    
 
    
 
  '''End'''
 
  '''End'''
Riga 314: Riga 313:
  
 
===Esempio più essenziale per invio dati Midi===
 
===Esempio più essenziale per invio dati Midi===
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:
  Public Struct snd_seq_event
+
Library "libasound:2"
 +
 +
  Public Struct snd_seq_event_t
 
   type As Byte
 
   type As Byte
 
   flags As Byte
 
   flags As Byte
Riga 334: Riga 335:
 
  End Struct
 
  End Struct
 
   
 
   
+
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
Library "libasound:2"
 
 
  Private SND_SEQ_OPEN_OUTPUT As Integer = 1
 
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
 
  Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
  Private SND_SEQ_QUEUE_DIRECT As Byte = 253
+
  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 361: Riga 359:
 
   
 
   
 
   Dim seq As Pointer
 
   Dim seq As Pointer
   Dim evento As New Snd_seq_event
+
   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 = SND_SEQ_QUEUE_DIRECT
    .dest_client = 128
+
    .dest_client = 128
    .dest_port = 0
+
    .dest_port = 0
    .channel = 0
+
    .channel = 0
    .note = 64
+
    .note = 64
    .velocity = 100
+
    .velocity = 100
  End With
+
  End With
 +
 
 +
  snd_seq_event_output_direct(seq, evento)
 
      
 
      
  snd_seq_event_output_direct(seq, evento)
+
  Wait 1
 
      
 
      
  Sleep 1
+
  evento.type = SND_SEQ_EVENT_NOTEOFF
   
+
  evento.velocity = 0
  evento.type = SND_SEQ_EVENT_NOTEOFF
+
  snd_seq_event_output_direct(seq, evento)
  evento.velocity = 0
+
 
  snd_seq_event_output_direct(seq, evento)
+
  snd_seq_close(seq)
   
 
  snd_seq_close(seq)
 
 
    
 
    
 
  '''End'''
 
  '''End'''

Versione delle 12:56, 9 set 2020

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.


1° caso

Nel primo caso il codice dovrà prevedere:

  • la presenza della funzione di ALSA snd_seq_alloc_queue();
  • il membro .queue della Struttura relativa agli eventi Midi dovrà essere posto a zero;
  • 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 sndseq As Pointer
Private Const cl_dest As Byte = 128
Private Const po_dest As Byte = 0


Library "libasound:2"

Public Struct snd_seq_event
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_time As Integer
  real_time 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_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 note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 Dim porta_source, b As Byte
 Dim ev As New Snd_seq_event
 
 porta_source = Connessione()
  
 With ev
   .queue = 0
   .source_client = 0
   .source_port = porta_source
   .dest_client = cl_dest
   .dest_port = po_dest
   .channel = 0
 End With
       
 program_change(ev, 48)
   
 For b = 0 To note.Max
   Note_On(ev, note[b])
   Wait 1
   Note_Off(ev, note[b])
 Next
   
 snd_seq_close(sndseq)
  
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 !")
      
 snd_seq_alloc_queue(sndseq)
 
 Return porta
 
End


Private Procedure program_change(ev_prch As Snd_seq_event, strum As Integer)
 
 With ev_prch
   .type = SND_SEQ_EVENT_PGMCHANGE
   .value = strum
 End With
   
 InviaEvento(ev_prch)
  
End


Private Procedure Note_On(ev_nton As Snd_seq_event, nota As Byte)
 
 With ev_nton
   .type = SND_SEQ_EVENT_NOTEON
   .note = nota
   .velocity = 64
 End With
  
 InviaEvento(ev_nton)
  
End


Private Procedure Note_Off(ev_ntoff As Snd_seq_event, nota As Byte)
 
 With ev_ntoff
   .type = SND_SEQ_EVENT_NOTEOFF
   .note = nota
   .velocity = 0
 End With
  
 InviaEvento(ev_ntoff)
  
End


Private Procedure InviaEvento(evento As Snd_seq_event)
 
 snd_seq_event_output(sndseq, evento)
  
 snd_seq_drain_output(sndseq)
 
End


2° caso

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;
  • 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:

Library "libasound:2"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_time As Integer
  real_time 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, 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_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 sndseq As Pointer
 Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
 Dim b As Byte
 Dim evento As New Snd_seq_event_t
 
 sndseq = Connessione()
  
 With evento
   .queue = SND_SEQ_QUEUE_DIRECT
   .dest_client = 128
   .dest_port = 0
   .channel = 0
 End With
       
 program_change(sndseq, evento, 48)
   
 For b = 0 To note.Max
   Note_On(sndseq, evento, note[b])
   InviaEvento(sndseq)
   Wait 1
   Note_Off(sndseq, evento, note[b])
   InviaEvento(sndseq)
 Next
  
 snd_seq_close(sndseq)
  
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


Private Procedure program_change(pc_seq As Pointer, ev_prch As Snd_seq_event, strum As Integer)
 
 With ev_prch
   .type = SND_SEQ_EVENT_PGMCHANGE
   .value = strum
 End With
  
' Inserisce l'evento "Program_Change" nel buffer:
 snd_seq_event_output(pc_seq, ev_prch)
  
End


Private Procedure Note_On(nto 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
 
' Inserisce l'evento "Note_On" nel buffer:
 snd_seq_event_output(nto, ev_nton)
  
End


Private Procedure Note_Off(ntf 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
  
' Inserisce l'evento "Note_Off" nel buffer:
 snd_seq_event_output(ntf, ev_ntoff)
  
End


Private Procedure InviaEvento(seqP As Pointer)

' Invia l'intero contenuto del buffer ad Alsa:
 snd_seq_drain_output(seqP)
 
End


Esempio più essenziale per invio dati Midi

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"

Public Struct snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte
  queue As Byte
  tick_time As Integer
  real_time 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 Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253

' 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 = 128
   .dest_port = 0
   .channel = 0
   .note = 64
   .velocity = 100
 End With
  
 snd_seq_event_output_direct(seq, evento)
   
 Wait 1
   
 evento.type = SND_SEQ_EVENT_NOTEOFF
 evento.velocity = 0
 snd_seq_event_output_direct(seq, evento)
 
 snd_seq_close(seq)
  
End