Differenze tra le versioni di "ALSA e Gambas: Esempio di semplice Commutatore Midi con Alsa"

Da Gambas-it.org - Wikipedia.
(Creata pagina con "Mostreremo di seguito il codice di un semplice Client Midi di Alsa capace di ricevere dati Midi da un altro Client di Alsa (ad esempio da una tastiera Midi esterna) e di invia...")
 
 
Riga 1: Riga 1:
 
Mostreremo di seguito il codice di un semplice Client Midi di Alsa capace di ricevere dati Midi da un altro Client di Alsa (ad esempio da una tastiera Midi esterna) e di inviarli immediatamente a due o più altri Client attraverso una porta di Uscita distinta, in questo esempio, sulla base del numero di Canale dell'evento "NoteON" ricevuto.
 
Mostreremo di seguito il codice di un semplice Client Midi di Alsa capace di ricevere dati Midi da un altro Client di Alsa (ad esempio da una tastiera Midi esterna) e di inviarli immediatamente a due o più altri Client attraverso una porta di Uscita distinta, in questo esempio, sulla base del numero di Canale dell'evento "NoteON" ricevuto.
Al terzo parametro della funzione ''snd_seq_open()'', necessaria per l'apertura del subsistema ''Seq'' di Alsa, va inserita la costante ''SND_SEQ_OPEN_DUPLEX'' per consentire il flusso di dati sia in Entrata che in Uscita.
+
Al terzo parametro della funzione esterna "snd_seq_open()", necessaria per l'apertura del subsistema ''Seq'' di Alsa, va inserita la costante ''SND_SEQ_OPEN_DUPLEX'' per consentire il flusso di dati sia in Entrata che in Uscita.
 
<BR>I dati Midi ricevuti sono assegnati ad una variabile di tipo ''Struttura'' organizzata secondo lo schema tipico di un "''Evento''" Midi Alsa.
 
<BR>I dati Midi ricevuti sono assegnati ad una variabile di tipo ''Struttura'' organizzata secondo lo schema tipico di un "''Evento''" Midi Alsa.
  
Riga 68: Riga 68:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
   
 
   
 
   Dim seq As Pointer
 
   Dim seq As Pointer
 
   Dim idportaE, err, id As Integer
 
   Dim idportaE, err, id As Integer
   Dim j As Byte
+
   Dim n As Byte
   Dim idportaU As New Integer[16]
+
   Dim idportaU As New Integer[16]
   
 
 
   
 
   
  err = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_DUPLEX, 0)
+
  err = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_DUPLEX, 0)
  If err < 0 Then Error.Raise("Impossibile inizializzare il subsistema 'seq' di ALSA: " & snd_strerror(err))
+
  If err < 0 Then Error.Raise("Impossibile inizializzare il subsistema 'seq' di ALSA: " & snd_strerror(err))
  Print "Apertura del dispositivo 'seq' di Alsa:  regolare\nNome del dispositivo 'seq':  "; "'default'"
+
  Print "Apertura del dispositivo 'seq' di Alsa:  regolare\nNome del dispositivo 'seq':  "; "'default'"
 
      
 
      
  err = snd_seq_set_client_name(seq, "Commutatore MIDI")
+
  err = snd_seq_set_client_name(seq, "Commutatore MIDI")
  If err < 0 Then Error.Raise("Impossibile assegnare un nome al Client applicativo di ALSA: " & snd_strerror(err))
+
  If err < 0 Then Error.Raise("Impossibile assegnare un nome al Client applicativo di ALSA: " & snd_strerror(err))
 
    
 
    
  id = snd_seq_client_id(seq)
+
  id = snd_seq_client_id(seq)
  Print "Numero identificativo del Commutatore MIDI:  "; id
+
  Print "Numero identificativo del Commutatore MIDI:  "; id
 
   
 
   
  idportaE = snd_seq_create_simple_port(seq, "Porta di Entrata", SND_SEQ_PORT_CAP_WRITE Or SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)
+
  idportaE = snd_seq_create_simple_port(seq, "Porta di Entrata", SND_SEQ_PORT_CAP_WRITE Or SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)
    If idportaE < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
+
  If idportaE < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
    Print "Id porta di Entrata n.:  "; idportaE
+
  Print "Id porta di Entrata n.:  "; idportaE
 
   
 
   
    For j = 0 To 15  <FONT color=gray>' ''Crea 16 porte di Uscita dell'applicativo.''</font>
+
  For b = 0 To 15  <FONT color=gray>' ''Crea 16 porte di Uscita dell'applicativo.''</font>
      idportaU[j] = snd_seq_create_simple_port(seq, "Porta di Uscita n. " & CStr(j), SND_SEQ_PORT_CAP_READ Or SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION)
+
    idportaU[b] = snd_seq_create_simple_port(seq, "Porta di Uscita n. " & CStr(b), SND_SEQ_PORT_CAP_READ Or SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION)
      If idportaU[j] < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
+
    If idportaU[b] < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
      Print "Id porta di Uscita n.:  "; idportaU[j]
+
    Print "Id porta di Uscita n.:  "; idportaU[b]
    Next
+
  Next
 
   
 
   
  intercettaMessaggiMidi(seq, id)
+
  intercettaMessaggiMidi(seq, id)
 
   
 
   
  '''End'''
+
  End  
 
   
 
   
 
   
 
   
  '''Public''' Procedure intercettaMessaggiMidi(seqiM As Pointer, idC As Integer)
+
  Public Procedure intercettaMessaggiMidi(seqiM As Pointer, idC As Integer)
 
    
 
    
 
   Dim ev As Pointer
 
   Dim ev As Pointer
 
   Dim midi@ As Snd_seq_event_t
 
   Dim midi@ As Snd_seq_event_t
 
      
 
      
  While True
+
  Do
+
    snd_seq_event_input(seqiM, VarPtr(ev))
    snd_seq_event_input(seqiM, VarPtr(ev))
+
    midi@ = ev
    midi@ = ev
+
 
 
 
 
  <FONT color=gray>' ''Effettuiamo la commutazione delle porte di Uscita sulla base del canale dell'evento "NoteON".''
 
  <FONT color=gray>' ''Effettuiamo la commutazione delle porte di Uscita sulla base del canale dell'evento "NoteON".''
 
  ' ''Ovviamente l'elemento discriminante potrebbe essere anche un altro.''
 
  ' ''Ovviamente l'elemento discriminante potrebbe essere anche un altro.''
 
  ' ''In questo esempio il Commutatore MIDI è connesso con due sue porte di Uscita ad due diversi Client Alsa attivi.''</font>
 
  ' ''In questo esempio il Commutatore MIDI è connesso con due sue porte di Uscita ad due diversi Client Alsa attivi.''</font>
    With midi@
+
    With midi@
+
      If .note = 60 Then  <FONT color=gray>' ''Se i messaggi "NoteOn" giungono''</font>
      If .note = 60 Then  <FONT color=gray>' ''Se i messaggi "NoteOn" giungono''</font>
+
        .channel = 0      <FONT color=gray>' ''già con canali diversi,''</font>
        .channel = 0      <FONT color=gray>' ''già con canali diversi,''</font>
+
      Else                <FONT color=gray>' ''allora questa parte di codice''</font>
      Else                <FONT color=gray>' ''allora questa parte di codice''</font>
+
        .channel = 1      <FONT color=gray>' ''può essere eliminata.''</font>
        .channel = 1      <FONT color=gray>' ''può essere eliminata.''</font>
+
      Endif              <FONT color=gray>'</font>
      Endif              <FONT color=gray>'</font>
+
      .source_id = idC
       
+
      If .channel = 0 Then
      .source_id = idC
+
        .source_porta = 1  <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 1''</font>
+
      Else
      If .channel = 0 Then
+
        .source_porta = 2  <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 2''</font>
        .source_porta = 1  <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 1''</font>
+
      Endif
      Else
+
      .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
        .source_porta = 2  <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 2''</font>
+
      .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
      Endif
+
    End With
      .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
 
      .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
 
    End With
 
 
   
 
   
    snd_seq_event_output_direct(seqiM, midi@)
+
    snd_seq_event_output_direct(seqiM, midi@)
 +
  Wend
 
    
 
    
  Wend
+
  End
 
 
  '''End'''
 

Versione attuale delle 17:02, 13 dic 2023

Mostreremo di seguito il codice di un semplice Client Midi di Alsa capace di ricevere dati Midi da un altro Client di Alsa (ad esempio da una tastiera Midi esterna) e di inviarli immediatamente a due o più altri Client attraverso una porta di Uscita distinta, in questo esempio, sulla base del numero di Canale dell'evento "NoteON" ricevuto. Al terzo parametro della funzione esterna "snd_seq_open()", necessaria per l'apertura del subsistema Seq di Alsa, va inserita la costante SND_SEQ_OPEN_DUPLEX per consentire il flusso di dati sia in Entrata che in Uscita.
I dati Midi ricevuti sono assegnati ad una variabile di tipo Struttura organizzata secondo lo schema tipico di un "Evento" Midi Alsa.

Sarà necessario effettuare le dovute connessioni via Alsa fra i vari Client. In particolare la tastiera esterna andrà collegata alla porta di Entrata del nostro applicativo, e le porte di Entrata degli altri Client di Alsa attivi, che saranno utilizzati, verranno connesse alle porte di Uscita del nostro applicativo Commutatore Midi.

Public Struct snd_seq_event_t
  type As Byte                ' byte n° 0
  flag As Byte
  tag As Byte 
  queue As Byte 
  timestamp1 As Integer 
  timestamp2 As Integer          
  source_id As Byte
  source_porta As Byte
  dest_id As Byte
  dest_porta As Byte
    channel As Byte             ' byte n° 16
    note As Byte
    velocity As Short
      primoValore As Integer      ' byte n° 20
      secondoValore As Integer    ' byte n° 24
End Struct
 

Library "libasound:2.0.0"

Private Const SND_SEQ_OPEN_DUPLEX As Integer = 3
Private Const SND_SEQ_PORT_CAP_WRITE As Integer = 2
Private Const SND_SEQ_PORT_CAP_SUBS_WRITE As Integer = 64
Private Const SND_SEQ_PORT_CAP_READ As Integer = 1
Private Const SND_SEQ_PORT_CAP_SUBS_READ As Integer = 32
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576
Private Const SND_SEQ_ADDRESS_UNKNOWN As Byte = 253
Private Const SND_SEQ_ADDRESS_SUBSCRIBERS As Byte = 254
Private Const SND_SEQ_EVENT_NOTEON As Byte = 6
Private Const SND_SEQ_EVENT_NOTEOFF As Byte = 7
Private Const SND_SEQ_EVENT_CONTROLLER As Byte = 10
Private Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11

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

' 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

' int snd_seq_set_client_name(snd_seq_t* seq, const char* name)
' Set client name.
Private Extern snd_seq_set_client_name(handle As Pointer, name As String) As Integer

' int snd_seq_client_id (snd_seq_t *seq)
' Get the client id.
Private Extern snd_seq_client_id(handle 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(handle As Pointer, name As String, caps As Integer, type As Integer) As Integer
 
' int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev)
' Retrieve an event from sequencer.
Private Extern snd_seq_event_input(handle As Pointer, ev As Snd_seq_event_t) As Integer

' 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


Public Sub Main()

 Dim seq As Pointer
 Dim idportaE, err, id As Integer
 Dim n As Byte
 Dim idportaU As New Integer[16]  

 err = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_DUPLEX, 0)
 If err < 0 Then Error.Raise("Impossibile inizializzare il subsistema 'seq' di ALSA: " & snd_strerror(err))
 Print "Apertura del dispositivo 'seq' di Alsa:  regolare\nNome del dispositivo 'seq':  "; "'default'"
   
 err = snd_seq_set_client_name(seq, "Commutatore MIDI")
 If err < 0 Then Error.Raise("Impossibile assegnare un nome al Client applicativo di ALSA: " & snd_strerror(err))
 
 id = snd_seq_client_id(seq)
 Print "Numero identificativo del Commutatore MIDI:  "; id

 idportaE = snd_seq_create_simple_port(seq, "Porta di Entrata", SND_SEQ_PORT_CAP_WRITE Or SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)
 If idportaE < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
 Print "Id porta di Entrata n.:  "; idportaE

 For b = 0 To 15   ' Crea 16 porte di Uscita dell'applicativo.
   idportaU[b] = snd_seq_create_simple_port(seq, "Porta di Uscita n. " & CStr(b), SND_SEQ_PORT_CAP_READ Or SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION)
   If idportaU[b] < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
   Print "Id porta di Uscita n.:  "; idportaU[b]
 Next

 intercettaMessaggiMidi(seq, id)

End 


Public Procedure intercettaMessaggiMidi(seqiM As Pointer, idC As Integer)
  
 Dim ev As Pointer
 Dim midi@ As Snd_seq_event_t
    
 Do
   snd_seq_event_input(seqiM, VarPtr(ev))
   midi@ = ev
 
' Effettuiamo la commutazione delle porte di Uscita sulla base del canale dell'evento "NoteON".
' Ovviamente l'elemento discriminante potrebbe essere anche un altro.
' In questo esempio il Commutatore MIDI è connesso con due sue porte di Uscita ad due diversi Client Alsa attivi.
   With midi@
     If .note = 60 Then  ' Se i messaggi "NoteOn" giungono
       .channel = 0      ' già con canali diversi,
     Else                ' allora questa parte di codice
       .channel = 1      ' può essere eliminata.
     Endif               '
     .source_id = idC
     If .channel = 0 Then
       .source_porta = 1   ' Uscirà dalla porta di Uscita n. 1
     Else
       .source_porta = 2   ' Uscirà dalla porta di Uscita n. 2
     Endif
     .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
     .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
   End With

   snd_seq_event_output_direct(seqiM, midi@)
 Wend
 
End