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 167: Riga 167:
 
===2° caso===
 
===2° caso===
 
Nel secondo caso si dovrà tenere conto di quanto segue:
 
Nel secondo caso si dovrà tenere conto di quanto segue:
* il membro ''.queue'' della Struttura relativa agli eventi Midi dovrà essere posto a zero;
+
* 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.
 
* 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.
  

Versione delle 20:23, 27 feb 2016

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:

 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
  duration As Integer
  value As Integer
End Struct

Private sndseq As Pointer
Private Const cl_dest As Byte = 128
Private Const po_dest As Byte = 0

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


' 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_t
 
  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])
    Sleep 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_t, 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_t, 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_t, 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_t)
 
  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:

 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
  duration As Integer
  value As Integer
End Struct


Library "libasound:2"

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
 
' 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)
    Sleep 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_t, 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:

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
  duration As Integer
  value As Integer
End Struct


Library "libasound:2"

Private SND_SEQ_OPEN_OUTPUT As Integer = 1
Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF
Private 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)
   
  Sleep 1
   
  evento.type = SND_SEQ_EVENT_NOTEOFF
  snd_seq_event_output_direct(seq, evento)
   
  snd_seq_close(seq)
  
End