Differenze tra le versioni di "Alsa e Gambas: Invio dati con l'uso di una Classe specifica"

Da Gambas-it.org - Wikipedia.
Riga 1: Riga 1:
===Preambolo===
+
===Introduzione===
 
 
Prenderemo ora in considerazione l'uso di una Classe specifica, nella quale inseriremo le variabili che saranno successivamente riempite dai valori relativi ai dati Midi e necessari per la definizione dell'evento Midi particolare. Dichiarando poi una variabile del tipo di quella Classe per ciascun evento Midi si avrà un'area di memoria utilizzabile. L'uso di tale Classe specifica sostituisce egregiamente e più dinamicamente la [[Strutture:_dichiarazione_ed_uso|Struttura]]. <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
 
  
 +
Prenderemo ora in considerazione l'uso di una Classe specifica, fornita di Proprietà in "lettura" e in "scrittura" che potranno essere usate per memorizzare i valori necessari per la definizione di un Evento Midi ALSA.
 +
<BR>Dichiarando poi una variabile del tipo di quella Classe per ciascun Evento Midi ALSA, si avrà un'area di memoria utilizzabile.
 +
<BR>L'uso di tale Classe specifica sostituisce egregiamente e più dinamicamente la [[Strutture:_dichiarazione_ed_uso|Struttura]]. <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
  
  
 
=Scrittura dei dati dei messaggi Midi nella Classe specifica dei dati Midi=
 
=Scrittura dei dati dei messaggi Midi nella Classe specifica dei dati Midi=
Viene innanzitutto creata ed impostata una ''Classe'' modello specifica che contiene, come già detto, tutte le Proprietà necessarie per la definizione di qualunque Evento Midi di ALSA.
+
La ''Classe'' modello specifica, contenente tutte le Proprietà necessarie per la definizione di qualunque Evento Midi di ALSA, sarà così organizzata:
 
  <FONT Color=#006400>' ''Definisce le Proprietà della Classe specifica:''</font>
 
  <FONT Color=#006400>' ''Definisce le Proprietà della Classe specifica:''</font>
  Property type As Byte
+
  Property Type As Byte
  Property flags As Byte
+
  Property Flags As Byte
  Property tag As Byte
+
  Property Tag As Byte
  Property queue As Byte
+
  Property Queue As Byte
  Property ticktime As Integer
+
  Property Ticktime As Integer
  Property realtime As Integer
+
  Property Realtime As Integer
  Property sourceclient As Byte
+
  Property Sourceclient As Byte
  Property sourceport As Byte
+
  Property Sourceport As Byte
  Property destclient As Byte
+
  Property Destclient As Byte
  Property destport As Byte
+
  Property Destport As Byte
  Property channel As Byte
+
  Property Channel As Byte
  Property note As Byte
+
  Property Note As Byte
  Property velocity As Byte
+
  Property Velocity As Byte
  Property off_velocity As Byte
+
  Property Off_velocity As Byte
  Property param As Integer
+
  Property Param As Integer
  Property value As Integer
+
  Property Value As Integer
 
   
 
   
 
  <FONT Color=#006400>' ''Definisce i simboli associati alle suddette Proprietà:''</font>
 
  <FONT Color=#006400>' ''Definisce i simboli associati alle suddette Proprietà:''</font>
  Private $type As Byte
+
  Private $Type As Byte
  Private $flags As Byte
+
  Private $Flags As Byte
  Private $tag As Byte
+
  Private $Tag As Byte
  Private $queue As Byte
+
  Private $Queue As Byte
  Private $ticktime As Integer
+
  Private $Ticktime As Integer
  Private $realtime As Integer
+
  Private $Realtime As Integer
  Private $sourceclient As Byte
+
  Private $Sourceclient As Byte
  Private $sourceport As Byte
+
  Private $Sourceport As Byte
 
  Private $destclient As Byte
 
  Private $destclient As Byte
  Private $destport As Byte
+
  Private $Destport As Byte
  Private $channel As Byte
+
  Private $Channel As Byte
  Private $note As Byte
+
  Private $Note As Byte
  Private $velocity As Byte
+
  Private $Velocity As Byte
  Private $off_velocity As Byte
+
  Private $Off_velocity As Byte
  Private $param As Integer
+
  Private $Param As Integer
  Private $value As Integer
+
  Private $Value As Integer
 
   
 
   
  Private Function type_Read() As Byte
+
  Private Function Type_Read() As Byte
   Return $type
+
   Return $Type
 
  End
 
  End
 
   
 
   
  Private Sub type_Write(Value As Byte)
+
  Private Sub Type_Write(Value As Byte)
   $type = Value
+
   $Type = Value
 
  End
 
  End
 
   
 
   
  Private Function flags_Read() As Byte
+
  Private Function Flags_Read() As Byte
   Return $flags
+
   Return $Flags
 
  End
 
  End
 
   
 
   
  Private Sub flags_Write(Value As Byte)
+
  Private Sub Flags_Write(Value As Byte)
   $flags = Value
+
   $Flags = Value
 
  End
 
  End
 
   
 
   
  Private Function tag_Read() As Byte
+
  Private Function Tag_Read() As Byte
   Return $tag
+
   Return $Tag
 
  End
 
  End
 
   
 
   
  Private Sub tag_Write(Value As Byte)
+
  Private Sub Tag_Write(Value As Byte)
   $tag = Value
+
   $Tag = Value
 
  End
 
  End
 
   
 
   
  Private Function queue_Read() As Byte
+
  Private Function Queue_Read() As Byte
   Return $queue
+
   Return $Queue
 
  End
 
  End
 
   
 
   
  Private Sub queue_Write(Value As Byte)
+
  Private Sub Queue_Write(Value As Byte)
   $queue = Value
+
   $Queue = Value
 
  End
 
  End
 
   
 
   
  Private Function ticktime_Read() As Integer
+
  Private Function Ticktime_Read() As Integer
   Return $ticktime
+
   Return $Ticktime
 
  End
 
  End
 
   
 
   
  Private Sub ticktime_Write(Value As Integer)
+
  Private Sub Ticktime_Write(Value As Integer)
   $ticktime = Value
+
   $Ticktime = Value
 
  End
 
  End
 
   
 
   
  Private Function realtime_Read() As Integer
+
  Private Function Realtime_Read() As Integer
   Return $realtime
+
   Return $Realtime
 
  End
 
  End
 
   
 
   
  Private Sub realtime_Write(Value As Integer)
+
  Private Sub Realtime_Write(Value As Integer)
   $realtime = Value
+
   $Realtime = Value
 
  End
 
  End
 
   
 
   
  Private Function sourceclient_Read() As Byte
+
  Private Function Sourceclient_Read() As Byte
   Return $sourceclient
+
   Return $Sourceclient
 
  End
 
  End
 
   
 
   
  Private Sub sourceclient_Write(Value As Byte)
+
  Private Sub Sourceclient_Write(Value As Byte)
   $sourceclient = Value
+
   $Sourceclient = Value
 
  End
 
  End
 
   
 
   
  Private Function sourceport_Read() As Byte
+
  Private Function Sourceport_Read() As Byte
   Return $sourceport
+
   Return $Sourceport
 
  End
 
  End
 
   
 
   
  Private Sub sourceport_Write(Value As Byte)
+
  Private Sub Sourceport_Write(Value As Byte)
   $sourceport = Value
+
   $Sourceport = Value
 
  End
 
  End
 
   
 
   
  Private Function destclient_Read() As Byte
+
  Private Function Destclient_Read() As Byte
   Return $destclient
+
   Return $Destclient
 
  End
 
  End
 
   
 
   
  Private Sub destclient_Write(Value As Byte)
+
  Private Sub Destclient_Write(Value As Byte)
   $destclient = Value
+
   $Destclient = Value
 
  End
 
  End
 
   
 
   
  Private Function destport_Read() As Byte
+
  Private Function Destport_Read() As Byte
   Return $destport
+
   Return $Destport
 
  End
 
  End
 
   
 
   
  Private Sub destport_Write(Value As Byte)
+
  Private Sub Destport_Write(Value As Byte)
   $destport = Value
+
   $Destport = Value
 
  End
 
  End
 
   
 
   
  Private Function channel_Read() As Byte
+
  Private Function Channel_Read() As Byte
   Return $channel
+
   Return $Channel
 
  End
 
  End
 
   
 
   
  Private Sub channel_Write(Value As Byte)
+
  Private Sub Channel_Write(Value As Byte)
   $channel = Value
+
   $Channel = Value
 
  End
 
  End
 
   
 
   
  Private Function note_Read() As Byte
+
  Private Function Note_Read() As Byte
   Return $note
+
   Return $Note
 
  End
 
  End
 
   
 
   
  Private Sub note_Write(Value As Byte)
+
  Private Sub Note_Write(Value As Byte)
   $note = Value
+
   $Note = Value
 
  End
 
  End
 
   
 
   
  Private Function velocity_Read() As Byte
+
  Private Function Velocity_Read() As Byte
   Return $velocity
+
   Return $Velocity
 
  End
 
  End
 
   
 
   
  Private Sub velocity_Write(Value As Byte)
+
  Private Sub Velocity_Write(Value As Byte)
   $velocity = Value
+
   $Velocity = Value
 
  End
 
  End
 
   
 
   
  Private Function off_velocity_Read() As Byte
+
  Private Function Off_velocity_Read() As Byte
   Return $off_velocity
+
   Return $Off_velocity
 
  End
 
  End
 
   
 
   
  Private Sub off_velocity_Write(Value As Byte)
+
  Private Sub Off_velocity_Write(Value As Byte)
   $off_velocity = Value
+
   $Off_velocity = Value
 
  End
 
  End
 
   
 
   
  Private Function param_Read() As Integer
+
  Private Function Param_Read() As Integer
   Return $param
+
   Return $Param
 
  End
 
  End
 
   
 
   
 
  Private Sub param_Write(Value As Integer)
 
  Private Sub param_Write(Value As Integer)
   $param = Value
+
   $Param = Value
 
  End
 
  End
 
   
 
   
  Private Function value_Read() As Integer
+
  Private Function Value_Read() As Integer
   Return $value
+
   Return $Value
 
  End
 
  End
 
   
 
   
  Private Sub value_Write(Value As Integer)
+
  Private Sub Value_Write(Value As Integer)
   $value = Value
+
   $Value = Value
 
  End
 
  End
 +
  
 
=I messaggi Midi specifici=
 
=I messaggi Midi specifici=
 
===Preambolo===
 
===Preambolo===
 
+
Scrivendo il codice Gambas, si dovrà ricordare che nella dichiarazione con ''Extern'' della funzione esterna di ALSA "snd_seq_event_output()" bisognerà inserire come secondo parametro il nome identificativo della predetta Classe modello per la creazione degli Eventi Midi di ALSA:
Organizzeremo nella classe secondaria CAlsa.class le routine per la gestione dei messaggi Midi. Poiché per i valori specifici di ciascun messaggio è prevista, come già sappiamo, una disposizione all'interno della zona di memoria comune con altri messaggi, prevederemo - per ciascun gruppo di messaggi dalla struttura simile - delle variabili del tipo della Classe specifica ''CMidi'' apposite che vadano bene per i messaggi appartenenti a quel gruppo.
+
  Private Extern snd_seq_event_output(handle As Pointer, vC As <FONT color=#B22222><I>Classe_Eventi_Midi</i></font>) As Integer
 
+
mentre all'interno delle routine, quando essa viene chiamata e effettivamente utilizzata, va inserito ovviamente il nome della sua variabile istanziata
V'è da sottolineare che nella classe ''CAlsa.class'' la funzione ''snd_seq_event_output'' va modificata inserendo come secondo parametro nella sua dichiarazione con la funzione ''Extern'' il nome della Classe modello ''CMidi'':
 
  Private Extern snd_seq_event_output(handle As Pointer, vC As <FONT color=#B22222>Cmidi</font>) As Integer
 
 
 
mentre all'interno delle routine, quando essa viene chiamata, va inserito il nome della variabile-classe specifica. Ad esempio:
 
err = snd_seq_event_output(handle, <FONT color=#FF7000>ev_OnOffPoly</font>)
 
 
 
  
 
==Gruppo messaggi: <FONT Color= "red">NoteON - NoteOFF</font> - <FONT Color= "red">Polyphonic Aftertouch</font>==
 
==Gruppo messaggi: <FONT Color= "red">NoteON - NoteOFF</font> - <FONT Color= "red">Polyphonic Aftertouch</font>==
Questi tre messaggi Midi hanno tra loro in comune tre medesimi specifici dati posti ai byte num. 16, 17 e 18 della Classe specifica modello, e che abbiamo chiamato: ''channel'', ''note'' e ''velocity''.
+
Questi tre messaggi Midi hanno tra loro in comune tre Proprietà della Classe specifica modello: ".Channel", ".Note" e ".Velocity"
 
+
<BR>Dunque per questi tre tipi di Messaggi Midi si valorizzeranno le suddette Proprietà della Classe specifica.
<P>Dichiareremo nella classe ''CAlsa.class'' una variabile ''ad hoc'' per questi tre messaggi Midi del tipo della Classe specifica modello ''CMidi'', della quale ultima assumerà così l'organizzazione interna delle particolari variabili ed il tipo dei valori:</p>
 
 
 
ev_OnOffPoly As New CMidi
 
 
 
<P>Ora la nostra variabile ''ev_OnOffPoly'' è operativa e può essere utilizzata per la gestione ed il successivo invio dei messaggi Midi ad ALSA.</p>
 
<P>L'uso di tale variabile-Classe si ha quando si dovrà definire ''concretamente'' il messaggio Midi richiesto, fissando in ciascun elemento costituivo (le diverse variabili in essa contenute) i relativi valori. Si potrà evitare di richiamare le varibili particolari della Classe che eventualmente non servono.</p>
 
 
 
<P>Quindi dalla classe principale chiameremo la routine specifica per i tre eventi qui considerati, passandogli anche tre valori necessari:</p>
 
Public Sub eventoOnOffPoly(def_Evento As Byte, nota as byte, velocitas As Byte)
 
 
Dim err As Integer
 
 
  With ev_OnOffPoly
 
    .type = def_Evento          <FONT color=#006400>' ''= 6, 7 oppure 8''</font>
 
    .queue = outq
 
    .source_id = id
 
    .source_porta = outport
 
    .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
 
    .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
 
    .channel = 0
 
    .note = 60
 
    .velocity = velocitas
 
  End With
 
 
  err = snd_seq_event_output(handle, <FONT color=#FF7000>ev_OnOffPoly</font>)    <FONT color=#006400>' ''si passano ad ALSA i valori presenti nella variabile-Classe: ev_OnOffPoly''</font>
 
  printerr("OnOffPoly = ", err)
 
 
End
 
  
 +
Ovviamente le prime sette Proprietà sono comuni a tutti Messaggi Midi.
  
 
==Gruppo messaggi: <FONT Color= "red">Program Change</font> - <FONT Color= "red">Channel Aftertouch (Key Pressure)</font>==
 
==Gruppo messaggi: <FONT Color= "red">Program Change</font> - <FONT Color= "red">Channel Aftertouch (Key Pressure)</font>==
Questi due messaggi Midi hanno tra loro in comune due medesimi specifici dati posti ai byte num. 16 e 24 della Classe ''CMidi.class'' modello, e che abbiamo chiamato: ''channel'' e ''valorePrimo''.
+
Questi due messaggi Midi hanno tra loro in comune due Proprietà: ".Channel" e ".Value".
 
 
<P>Dichiareremo una variabile ''ad hoc'' anche per questi due messaggi Midi del tipo della Classe ''CMidi.class'' modello, della quale ultima assumerà così l'organizzazione interna delle particolari variabili ed il tipo dei valori:</p>
 
 
 
ev_PgmKeyPress As New CMidi
 
 
 
<P>Ora la nostra variabile ''ev_PgmKeyPress'' è operativa e può essere utilizzata per la gestione ed il successivo invio dei messaggi Midi ad ALSA.</p>
 
<P>L'uso di tale variabile-Classe specifica si ha quando si dovrà definire ''concretamente'' il messaggio Midi richiesto, fissando in ciascun elemento costituivo (le diverse variabili in essa contenute) i relativi valori. Si potrà evitare di richiamare le varibili particolari della Classe che eventualmente non servono.</p>
 
 
 
<P>Quindi dalla classe principale chiameremo la routine specifica per i due eventi qui considerati, passandogli anche due valori necessari:</p>
 
 
 
Public Sub eventoPgmKeyPress(def_Evento As Byte, sec_Valore As Integer)
 
 
Dim err As Integer
 
 
  With ev_PgmKeyPress
 
  .type = def_Evento          <FONT color=#006400>' ''= 11 oppure 12''</font>
 
  .queue = outq
 
  .source_id = id
 
  .source_porta = outport
 
  .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
 
  .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
 
  .channel = 0
 
  .value = sec_Valore        <FONT color=#006400>' ''impostato nella classe principale''</font>
 
  End With
 
 
<FONT color=#006400>' ''Si passano ad ALSA i valori presenti nella variabile-Classe: ev_PgmKeyPress:''</font>
 
  err = snd_seq_event_output(handle, <FONT color=#FF7000>ev_PgmKeyPress</font>)
 
  printerr("PgmKeyPress = ", err)
 
 
End
 
 
 
  
 
==Gruppo messaggi: <FONT Color= "red">Control Change</font> - <FONT Color= "red">Pitch Bend (Pitch Wheel)</font>==
 
==Gruppo messaggi: <FONT Color= "red">Control Change</font> - <FONT Color= "red">Pitch Bend (Pitch Wheel)</font>==
Questi due messaggi Midi hanno tra loro in comune tre medesimi specifici dati posti ai byte num. 16, 20 e 24 della Classe ''CMidi.class'' modello, e che abbiamo chiamato: ''channel'', ''primoValore'' e ''secondoValore''.
+
Questi due messaggi Midi hanno tra loro in comune tre Proprietà della Classe specifica, che abbiamo chiamato: ''.Channel'', ''.Param'' e ''.Value''.
 
 
<P>Dichiareremo una variabile ''ad hoc'' anche per questi due messaggi Midi del tipo della Classe ''CMidi.class'' modello, della quale ultima assumerà così l'organizzazione interna delle particolari variabili ed il tipo dei valori:</p>
 
 
 
ev_CtrlPitBnd As New CMidi
 
 
 
<P>Ora la nostra variabile-Classe ''ev_CtrlPitBnd'' è operativa e può essere utilizzata per la gestione ed il successivo invio dei messaggi Midi ad ALSA.</p>
 
<P>L'uso di tale variabile-Classe specifica si ha quando si dovrà definire ''concretamente'' il messaggio Midi richiesto, fissando in ciascun elemento costituivo (le diverse variabili in essa contenute) i relativi valori. Si potrà evitare di richiamare le varibili particolari della Classe che eventualmente non servono.</p>
 
 
 
<P>Quindi dalla classe principale chiameremo la routine specifica per i due eventi qui considerati, passandogli anche tre valori necessari:</p>
 
 
 
Public Sub eventoPgmKeyPress(def_Evento As Byte, prm_Valore As Integer, sec_Valore As Integer)
 
 
Dim err As Integer
 
 
  With ev_CtrlPitBnd
 
    .type = def_Evento          <FONT color=#006400>' ''= 10 oppure 13''</font>
 
    .queue = outq
 
    .source_id = id
 
    .source_porta = outport
 
    .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
 
    .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
 
    .channel = 0
 
    .param = prm_Valore        <FONT color=#006400>' ''impostato nella classe principale''</font>
 
    .value = sec_Valore        <FONT color=#006400>' ''impostato nella classe principale''</font>
 
  End With
 
 
  err = snd_seq_event_output(handle, <FONT color=#FF7000>ev_CtrlPitBnd</font>)    <FONT color=#006400>' ''si passano ad ALSA i valori presenti nella variabile-Classe: CtrlPitBnd''</font>
 
  printerr("CtrlPitBnd = ", err)
 
 
End
 
<BR>Da notare che per il Pitch Bend il dato ''primoValore'' è ininfluente, e può essere quindi fissato a 0.
 
  
  
Riga 369: Riga 276:
 
  <FONT Color=gray>' '''Program Change'''</font>
 
  <FONT Color=gray>' '''Program Change'''</font>
 
   With ev_midi
 
   With ev_midi
     .type = SND_SEQ_EVENT_PGMCHANGE
+
     .Type = SND_SEQ_EVENT_PGMCHANGE
     .flags = 0
+
     .Flags = 0
     .tag = 0
+
     .Tag = 0
     .queue = que
+
     .Queue = que
     .ticktime = 0
+
     .Ticktime = 0
     .realtime = 0
+
     .Realtime = 0
     .sourceclient = id
+
     .Sourceclient = id
     .sourceport = porta
+
     .Sourceport = porta
     .destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
+
     .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
     .destport = SND_SEQ_ADDRESS_UNKNOWN
+
     .Destport = SND_SEQ_ADDRESS_UNKNOWN
     .channel = 0
+
     .Channel = 0
     .value = 44   ' Imposta il suono dello strumento musicale da usare
+
     .value = 44       <FONT Color=gray>' ''Imposta il suono dello strumento musicale da usare''</font>
 
   End With
 
   End With
 
   
 
   
Riga 387: Riga 294:
 
  <FONT Color=gray>' '''Note ON'''</font>
 
  <FONT Color=gray>' '''Note ON'''</font>
 
   With ev_midi
 
   With ev_midi
     .type = SND_SEQ_EVENT_NOTEON
+
     .Type = SND_SEQ_EVENT_NOTEON
     .flags = 0
+
     .Flags = 0
     .tag = 0
+
     .Tag = 0
     .queue = que
+
     .Queue = que
     .ticktime = 0
+
     .Ticktime = 0
     .realtime = 0
+
     .Realtime = 0
     .sourceclient = id
+
     .Sourceclient = id
     .sourceport = porta
+
     .Sourceport = porta
     .destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
+
     .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
     .destport = SND_SEQ_ADDRESS_UNKNOWN
+
     .Destport = SND_SEQ_ADDRESS_UNKNOWN
     .channel = 0
+
     .Channel = 0
     .note = 64        <FONT Color=gray>' ''Imposta una nota Midi da eseguire''</font>
+
     .Note = 64        <FONT Color=gray>' ''Imposta una nota Midi da eseguire''</font>
     .velocity = 100  <FONT Color=gray>' ''Imposta la velocità di tocco''</font>
+
     .Velocity = 100  <FONT Color=gray>' ''Imposta la velocità di tocco''</font>
 
   End With
 
   End With
 
   
 
   
Riga 409: Riga 316:
 
  <FONT Color=gray>' '''Note OFF'''</font>
 
  <FONT Color=gray>' '''Note OFF'''</font>
 
   With ev_midi
 
   With ev_midi
     .type = SND_SEQ_EVENT_NOTEOFF
+
     .Type = SND_SEQ_EVENT_NOTEOFF
     .flags = 0
+
     .Flags = 0
     .tag = 0
+
     .Tag = 0
     .queue = que
+
     .Queue = que
     .ticktime = 0
+
     .Ticktime = 0
     .realtime = 0
+
     .Realtime = 0
     .sourceclient = id
+
     .Sourceclient = id
     .sourceport = porta
+
     .Sourceport = porta
     .destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
+
     .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
     .destport = SND_SEQ_ADDRESS_UNKNOWN
+
     .Destport = SND_SEQ_ADDRESS_UNKNOWN
     .channel = 0
+
     .Channel = 0
     .note = 64        <FONT Color=gray>' ''Imposta una nota Midi da eseguire''</font>
+
     .Note = 64        <FONT Color=gray>' ''Imposta una nota Midi da eseguire''</font>
     .velocity = 0    <FONT Color=gray>' ''Imposta la velocità di tocco''</font>
+
     .Velocity = 0    <FONT Color=gray>' ''Imposta la velocità di tocco''</font>
 
   End With
 
   End With
 
   
 
   

Versione delle 09:13, 18 gen 2022

Introduzione

Prenderemo ora in considerazione l'uso di una Classe specifica, fornita di Proprietà in "lettura" e in "scrittura" che potranno essere usate per memorizzare i valori necessari per la definizione di un Evento Midi ALSA.
Dichiarando poi una variabile del tipo di quella Classe per ciascun Evento Midi ALSA, si avrà un'area di memoria utilizzabile.
L'uso di tale Classe specifica sostituisce egregiamente e più dinamicamente la Struttura. [nota 1]


Scrittura dei dati dei messaggi Midi nella Classe specifica dei dati Midi

La Classe modello specifica, contenente tutte le Proprietà necessarie per la definizione di qualunque Evento Midi di ALSA, sarà così organizzata:

' Definisce le Proprietà della Classe specifica:
Property Type As Byte
Property Flags As Byte
Property Tag As Byte
Property Queue As Byte
Property Ticktime As Integer
Property Realtime As Integer
Property Sourceclient As Byte
Property Sourceport As Byte
Property Destclient As Byte
Property Destport As Byte
Property Channel As Byte
Property Note As Byte
Property Velocity As Byte
Property Off_velocity As Byte
Property Param As Integer
Property Value As Integer

' Definisce i simboli associati alle suddette Proprietà:
Private $Type As Byte
Private $Flags As Byte
Private $Tag As Byte
Private $Queue As Byte
Private $Ticktime As Integer
Private $Realtime As Integer
Private $Sourceclient As Byte
Private $Sourceport As Byte
Private $destclient As Byte
Private $Destport As Byte
Private $Channel As Byte
Private $Note As Byte
Private $Velocity As Byte
Private $Off_velocity As Byte
Private $Param As Integer
Private $Value As Integer

Private Function Type_Read() As Byte
  Return $Type
End

Private Sub Type_Write(Value As Byte)
  $Type = Value
End

Private Function Flags_Read() As Byte
  Return $Flags
End

Private Sub Flags_Write(Value As Byte)
  $Flags = Value
End

Private Function Tag_Read() As Byte
  Return $Tag
End

Private Sub Tag_Write(Value As Byte)
  $Tag = Value
End

Private Function Queue_Read() As Byte
  Return $Queue
End

Private Sub Queue_Write(Value As Byte)
  $Queue = Value
End

Private Function Ticktime_Read() As Integer
  Return $Ticktime
End

Private Sub Ticktime_Write(Value As Integer)
  $Ticktime = Value
End

Private Function Realtime_Read() As Integer
  Return $Realtime
End

Private Sub Realtime_Write(Value As Integer)
  $Realtime = Value
End

Private Function Sourceclient_Read() As Byte
  Return $Sourceclient
End

Private Sub Sourceclient_Write(Value As Byte)
  $Sourceclient = Value
End

Private Function Sourceport_Read() As Byte
  Return $Sourceport
End

Private Sub Sourceport_Write(Value As Byte)
  $Sourceport = Value
End

Private Function Destclient_Read() As Byte
  Return $Destclient
End

Private Sub Destclient_Write(Value As Byte)
  $Destclient = Value
End

Private Function Destport_Read() As Byte
  Return $Destport
End

Private Sub Destport_Write(Value As Byte)
  $Destport = Value
End

Private Function Channel_Read() As Byte
  Return $Channel
End

Private Sub Channel_Write(Value As Byte)
  $Channel = Value
End

Private Function Note_Read() As Byte
  Return $Note
End

Private Sub Note_Write(Value As Byte)
  $Note = Value
End

Private Function Velocity_Read() As Byte
  Return $Velocity
End

Private Sub Velocity_Write(Value As Byte)
  $Velocity = Value
End

Private Function Off_velocity_Read() As Byte
  Return $Off_velocity
End

Private Sub Off_velocity_Write(Value As Byte)
  $Off_velocity = Value
End

Private Function Param_Read() As Integer
  Return $Param
End

Private Sub param_Write(Value As Integer)
  $Param = Value
End

Private Function Value_Read() As Integer
  Return $Value
End

Private Sub Value_Write(Value As Integer)
  $Value = Value
End


I messaggi Midi specifici

Preambolo

Scrivendo il codice Gambas, si dovrà ricordare che nella dichiarazione con Extern della funzione esterna di ALSA "snd_seq_event_output()" bisognerà inserire come secondo parametro il nome identificativo della predetta Classe modello per la creazione degli Eventi Midi di ALSA:

Private Extern snd_seq_event_output(handle As Pointer, vC As Classe_Eventi_Midi) As Integer

mentre all'interno delle routine, quando essa viene chiamata e effettivamente utilizzata, va inserito ovviamente il nome della sua variabile istanziata

Gruppo messaggi: NoteON - NoteOFF - Polyphonic Aftertouch

Questi tre messaggi Midi hanno tra loro in comune tre Proprietà della Classe specifica modello: ".Channel", ".Note" e ".Velocity"
Dunque per questi tre tipi di Messaggi Midi si valorizzeranno le suddette Proprietà della Classe specifica.

Ovviamente le prime sette Proprietà sono comuni a tutti Messaggi Midi.

Gruppo messaggi: Program Change - Channel Aftertouch (Key Pressure)

Questi due messaggi Midi hanno tra loro in comune due Proprietà: ".Channel" e ".Value".

Gruppo messaggi: Control Change - Pitch Bend (Pitch Wheel)

Questi due messaggi Midi hanno tra loro in comune tre Proprietà della Classe specifica, che abbiamo chiamato: .Channel, .Param e .Value.


Esempio di codice

Mostriamo ora il codice che sarà inserito nel Modulo di avvio principale, dal quale si richiamerà la Classe specifica per la gestione degli Eventi Midi di ALSA, che qui sarà chiamata EventoMidiAlsa:

Public ev_midi As EventoMidiAlsa    ' Dichiara la variabile del tipo della Classe "EventoMidiAlsa"

Library "libasound:2"

Private Const SND_SEQ_OPEN_DUPLEX As Integer = 3
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
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 Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_KEYPRESS,
             SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE, SND_SEQ_EVENT_CHANPRESS, SND_SEQ_EVENT_PITCHBEND

' int snd_seq_open (snd_seq_t **seqp, const char * name, int streams, int mode)
' Open the ALSA sequencer.
Private Extern snd_seq_open(seqp 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(seq As Pointer, name As String) As Integer

' int snd_seq_create_simple_port (snd_seq_t* seq, const char* name, unsigned int caps, unsigned int type)
' Creates a port with the given capability and type bits.
Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer

' 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_connect_to ( snd_seq_t * seq, int myport, int dest_client, int dest_port )
' Connect from the given receiver port in the current client to the given destination client:port.
Private Extern snd_seq_connect_to(seq As Pointer, myport As Integer, dest_client As Integer, dest_port As Integer) As Integer

' int snd_seq_alloc_named_queue (snd_seq_t * seq, CONST char * name)
' Allocate a queue.
Private Extern snd_seq_alloc_queue(seq As Pointer, name As String) As Integer
 
' int snd_seq_event_output (snd_seq_t * seq, snd_seq_event_t *ev)
' Output an event.
Private Extern snd_seq_event_output(seq As Pointer, ev As EventoMidiAlsa) As Integer

' 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

' 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_close (snd_seq_t * seq)
' Close the sequencer.
Private Extern snd_seq_close(seq As Pointer) As Integer


Public Sub Main()

 Dim handle As Pointer
 Dim err, id, porta, que As Integer

' Crea un'istanza della Classe specifica "EventoMidiAlsa", con la quale saranno richiamate e gestite le Proprietà della Classe:
 ev_midi = New EventoMidiAlsa

 err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)
 Print "Apertura del subsistema 'seq' di ALSA = "; err
 If err < 0 Then error.RAISE("Errore: " & snd_strerror(err))

 snd_seq_set_client_name(handle, "Test")
 id = snd_seq_client_id(handle)
 Print "Alsa ClientID = "; id

 porta = snd_seq_create_simple_port(handle, "Uscita", 0, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION) 
 Print "Porta del programma = "; porta
 If porta < 0 Then error.Raise("Errore: " & snd_strerror(porta))

 que = snd_seq_alloc_queue(handle, "queue")
 If que < 0 Then error.Raise("Errore: " & snd_strerror(que))

' Assume che l'ID/porta dell'altro Client (Softsynth) sia 128:0
 err = snd_seq_connect_to(handle, porta, 128, 0)
 If err < 0 Then error.Raise("Errore: " & snd_strerror(err))

' Program Change
 With ev_midi
   .Type = SND_SEQ_EVENT_PGMCHANGE
   .Flags = 0
   .Tag = 0
   .Queue = que
   .Ticktime = 0
   .Realtime = 0
   .Sourceclient = id
   .Sourceport = porta
   .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
   .Destport = SND_SEQ_ADDRESS_UNKNOWN
   .Channel = 0
   .value = 44       ' Imposta il suono dello strumento musicale da usare
 End With

 InviaEventoMidi(handle, ev_midi)

' Note ON
 With ev_midi
   .Type = SND_SEQ_EVENT_NOTEON
   .Flags = 0
   .Tag = 0
   .Queue = que
   .Ticktime = 0
   .Realtime = 0
   .Sourceclient = id
   .Sourceport = porta
   .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
   .Destport = SND_SEQ_ADDRESS_UNKNOWN
   .Channel = 0
   .Note = 64        ' Imposta una nota Midi da eseguire
   .Velocity = 100   ' Imposta la velocità di tocco
 End With

 InviaEventoMidi(handle, ev_midi)

' Imposta la durata dell'esecuzione della nota:
 Wait 3

' Note OFF
 With ev_midi
   .Type = SND_SEQ_EVENT_NOTEOFF
   .Flags = 0
   .Tag = 0
   .Queue = que
   .Ticktime = 0
   .Realtime = 0
   .Sourceclient = id
   .Sourceport = porta
   .Destclient = SND_SEQ_ADDRESS_SUBSCRIBERS
   .Destport = SND_SEQ_ADDRESS_UNKNOWN
   .Channel = 0
   .Note = 64        ' Imposta una nota Midi da eseguire
   .Velocity = 0     ' Imposta la velocità di tocco
 End With

 InviaEventoMidi(handle, ev_midi)

' Va in Chiusura:
 snd_seq_close(handle)

End

Private Procedure InviaEventoMidi(p As Pointer, ev_midi As EventoMidiAlsa)

 Dim err As Integer

 err = snd_seq_event_output(p, ev_midi)
 If err < 0 Then error.Raise("Errore: " & snd_strerror(err))

 err = snd_seq_drain_output(p)
 If err < 0 Then error.Raise("Errore: " & snd_strerror(err))

End


Note

[1] In Gambas una "Struttura " può anche essere sostituita con una Classe avente solo Proprietà (dunque senza Metodi né Eventi).