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 4: Riga 4:
 
===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 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]'';
+
* 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;
 
* 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_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.   
 
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 astratto facendo uso di una Struttura dichiarata ad immagine della citata Struttura di ALSA ''[https://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__event__t.html snd_seq_event_t]'':
 
  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>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
 
  Private Const <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> As Byte = 0
Riga 59: Riga 59:
 
  ' ''Allocate a queue.''</font>
 
  ' ''Allocate a queue.''</font>
 
  Private Extern <FONT Color=darkorange><B>snd_seq_alloc_queue</b></font>(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)
 
' ''Output an event.''</font>
 
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)
 
 
<FONT Color=gray>' ''int snd_seq_drain_output (snd_seq_t * seq)
 
' ''Drain output buffer to sequencer.''</font>
 
Private Extern snd_seq_drain_output(seq As Pointer) As Integer
 
 
<FONT Color=gray>' ''int snd_seq_close (snd_seq_t *handle)
 
' ''Close the sequencer.''</font>
 
Private Extern snd_seq_close(handle As Pointer) As Integer
 
 
   
 
   
 
   
 
   
Riga 101: Riga 89:
 
   End With
 
   End With
 
        
 
        
   program_change(handle, ev, 48)
+
   ...etc...
 
 
  For b = 0 To note.Max
 
    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
 
    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'''
 
  '''End'''
  
Riga 166: Riga 100:
 
* 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 astratto:
 
  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>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
 
  Private Const <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> As Byte = 0
Riga 218: Riga 152:
 
  ' ''Allocate a queue.''</font>
 
  ' ''Allocate a queue.''</font>
 
  Private Extern snd_seq_alloc_queue(handle As Pointer) As Integer
 
  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)
 
' ''Output an event.''</font>
 
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)
 
 
<FONT Color=gray>' ''int snd_seq_drain_output (snd_seq_t * seq)
 
' ''Drain output buffer to sequencer.''</font>
 
Private Extern snd_seq_drain_output(seq As Pointer) As Integer
 
 
<FONT Color=gray>' ''int snd_seq_close (snd_seq_t *handle)
 
' ''Close the sequencer.''</font>
 
Private Extern snd_seq_close(handle As Pointer) As Integer
 
 
   
 
   
 
   
 
   
Riga 236: Riga 158:
 
   Dim handle As Pointer
 
   Dim handle As Pointer
 
   Dim rit As Integer
 
   Dim rit As Integer
  Dim note As Byte[] = [60, 62, 64, 65, 67, 69, 71, 72]
+
   Dim id, porta As Byte
   Dim id, porta, b As Byte
 
 
   Dim ev As New Snd_seq_event_t
 
   Dim ev As New Snd_seq_event_t
 
   
 
   
Riga 258: Riga 179:
 
   End With
 
   End With
 
        
 
        
   program_change(handle, ev, 48)
+
   ...etc...
 
 
  For b = 0 To note.Max
 
    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
 
    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'''
 
  '''End'''
  

Versione delle 16:53, 24 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;
  • 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 astratto facendo uso di una Struttura dichiarata ad immagine della citata Struttura di ALSA snd_seq_event_t:

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


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
     
 ...etc...
 
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 astratto:

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


Public Sub Main()

 Dim handle As Pointer
 Dim rit As Integer
 Dim id, porta 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
     
 ...etc...
 
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