Differenze tra le versioni di "Alsa e Gambas: Invio dei dati senza connessione della porta del programma con il Softsynth"
(10 versioni intermedie di uno stesso utente non sono mostrate) | |||
Riga 1: | Riga 1: | ||
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. | 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. | ||
+ | |||
+ | Di seguito vedremo tre casi possibili, che saranno dimostrati con esempi pratici. | ||
+ | <BR>Se nel proprio sistema è stato installato il softsynth ''Fluidsynth'', allora i programmi, appresso descritti, dovrebbero connettersi automaticamente a quel softsynth, consentendo così la riproduzione dei suoni. Qualora non avvenga, procedere come segue: | ||
+ | <BR>1) da Terminale lanciare questa riga: ":~$ ''fluidsynth reload 0''", o meglio: ":~$ ''fluidsynth <FONT Color=darkgreen>/percorso/del/file/soundfont/.sf2</font>''" | ||
+ | <BR>2) senza chiudere il Terminale, verificare nell'utilità "Monitor di sistema" che ''Fluidsynth'' sia presente fra i processi attivi; | ||
+ | <BR>3) se ''Fluidsynth'' è presente fra i processi, verificare anche che esso sia presente al num. 128 nel file ''/proc/asound/seq/clients''; | ||
+ | <BR>4) in caso affermativo - senza chiudere il Terminale - lanciare il codice sopra esposto. | ||
+ | |||
+ | |||
+ | ==Casi== | ||
===1° caso=== | ===1° caso=== | ||
− | + | In tale caso si deve sempre utilizzare la funzione esterna di ALSA: "[https://www.alsa-project.org/alsa-doc/alsa-lib/group___seq_event.html#ga63986686b918abeff9902108638c5b2f snd_seq_event_output_direct()]" per l'invio diretto di ciascun Evento Midi 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. | + | <BR>Inoltre il codice dovrà prevedere che 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. |
+ | <BR>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 ''[https://www.alsa-project.org/alsa-doc/alsa-lib/structsnd__seq__event__t.html snd_seq_event_t]'': | + | Mostriamo un esempio <U>astratto</u> 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 48: | Riga 59: | ||
<FONT Color=gray>' ''int snd_seq_client_id (snd_seq_t * seq)'' | <FONT Color=gray>' ''int snd_seq_client_id (snd_seq_t * seq)'' | ||
' ''Get the client id.''</font> | ' ''Get the client id.''</font> | ||
− | Private Extern snd_seq_client_id(seq As Pointer) As Integer | + | Private Extern <FONT Color=darkgreen><B>snd_seq_client_id</b></font>(seq As Pointer) As Integer |
<FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)'' | <FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)'' | ||
' ''Create a port - simple version.''</font> | ' ''Create a port - simple version.''</font> | ||
− | Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer | + | Private Extern <FONT Color=darkgreen><B>snd_seq_create_simple_port</b></font>(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer |
<FONT Color=gray>' ''int snd_seq_alloc_queue (snd_seq_t *handle)'' | <FONT Color=gray>' ''int snd_seq_alloc_queue (snd_seq_t *handle)'' | ||
' ''Allocate a queue.''</font> | ' ''Allocate a queue.''</font> | ||
− | Private Extern snd_seq_alloc_queue(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_direct (snd_seq_t *handle, snd_seq_event_t *ev)'' | ||
+ | ' ''Output an event directly to the sequencer NOT through output buffer.''</font> | ||
+ | Private Extern <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(handle As Pointer, ev As Snd_seq_event_t) 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 | ||
Public Sub Main() | Public Sub Main() | ||
Riga 78: | Riga 96: | ||
With ev | With ev | ||
+ | .type = ...etc... | ||
.queue = <FONT Color=darkorange><B>que</b></font> | .queue = <FONT Color=darkorange><B>que</b></font> | ||
.source_client = id | .source_client = id | ||
Riga 83: | Riga 102: | ||
.dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> | .dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> | ||
.dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> | .dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> | ||
− | . | + | ...etc... |
End With | End With | ||
− | + | ||
− | + | snd_seq_event_output_direct(handle, ev) | |
− | + | ||
+ | snd_seq_close(handle) | ||
+ | |||
End | End | ||
Riga 93: | Riga 114: | ||
===2° caso=== | ===2° caso=== | ||
Nel secondo caso si dovrà tenere conto di quanto segue: | Nel secondo caso si dovrà tenere conto di quanto segue: | ||
− | * non | + | * non sono utilizzate le funzioni esterne "snd_seq_client_id()" e "snd_seq_create_simple_port()", usate invece nel caso precedente, specifiche di ALSA per la creazione della porta del nostro Client applicativo in Gambas; |
+ | * pertanto non si useranno, lasciandoli al valore predefinito di zero, i membri ''.source_client'' e ''..source_port'' della Struttura relativa agli eventi Midi; | ||
+ | * neppure sarà usata la funzione esterna "snd_seq_alloc_queue()" di ALSA; | ||
* al membro ''queue'' della Struttura relativa agli eventi Midi dovrà essere assegnato il valore della Costante ALSA "SND_SEQ_QUEUE_DIRECT" (253); | * 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. |
Mostriamo un esempio astratto: | Mostriamo un esempio astratto: | ||
Riga 124: | Riga 147: | ||
Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1 | Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1 | ||
− | |||
− | |||
Private Const <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> As Byte = 253 | Private Const <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> 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 138: | Riga 158: | ||
Private Extern snd_strerror(err As Integer) As Pointer | Private Extern snd_strerror(err As Integer) As Pointer | ||
− | <FONT Color=gray>' ''int | + | <FONT Color=gray>' ''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.''</font> |
− | Private Extern | + | Private Extern <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(handle As Pointer, ev As Snd_seq_event_t) As Integer |
− | <FONT Color=gray>' ''int | + | <FONT Color=gray>' ''int snd_seq_close (snd_seq_t *handle) |
− | ' '' | + | ' ''Close the sequencer.''</font> |
− | Private Extern | + | Private Extern snd_seq_close(handle As Pointer) As Integer |
Riga 151: | Riga 171: | ||
Dim handle As Pointer | Dim handle As Pointer | ||
Dim rit As Integer | Dim rit As Integer | ||
− | |||
Dim ev As New Snd_seq_event_t | Dim ev As New Snd_seq_event_t | ||
rit = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_OUTPUT, 0) | 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))) | If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & String@(snd_strerror(rit))) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
With ev | With ev | ||
+ | .type = ...etc... | ||
.queue = <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> | .queue = <FONT Color=#006400><B>SND_SEQ_QUEUE_DIRECT</b></font> | ||
− | |||
− | |||
.dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> | .dest_client = <FONT Color=#B22222><B>CLIENT_DESTINATARIO</b></font> | ||
.dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> | .dest_port = <FONT Color=#B22222><B>PORTA_DESTINATARIO</b></font> | ||
− | . | + | ...etc... |
End With | End With | ||
− | + | snd_seq_event_output_direct(handle, ev) | |
+ | |||
+ | snd_seq_close(handle) | ||
End | End | ||
Riga 179: | Riga 193: | ||
===Esempio più essenziale per invio diretto degli Eventi Midi ALSA=== | ===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. | + | Mostriamo ora la modalità più breve ed essenziale per inviare ad altro Client di Alsa alcuni eventi Midi, e nella quale <U>non</u> è prevista la creazione di porte del nostro Client applicativo. |
− | <BR>Si utilizzerà | + | <BR>Si utilizzerà ovviamente la funzione esterna di ALSA "snd_seq_event_output_direct()" per l'invio diretto di ciascun Evento Midi ALSA. |
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 245: | Riga 259: | ||
End With | End With | ||
− | + | snd_seq_event_output_direct(seq, evento) | |
<FONT Color=gray>' ''Imposta la durata dell'esecuzione della nota.'' | <FONT Color=gray>' ''Imposta la durata dell'esecuzione della nota.'' | ||
Riga 254: | Riga 268: | ||
evento.type = SND_SEQ_EVENT_NOTEOFF | evento.type = SND_SEQ_EVENT_NOTEOFF | ||
evento.velocity = 0 | evento.velocity = 0 | ||
− | + | ||
+ | snd_seq_event_output_direct(seq, evento) | ||
snd_seq_close(seq) | snd_seq_close(seq) | ||
Riga 322: | Riga 337: | ||
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))) | ||
+ | |||
+ | InvioMessaggioMidi(SND_SEQ_EVENT_NOTEON, SpinBox1.Value, 100) | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | Public Sub Button1_MouseUp() | ||
+ | |||
+ | InvioMessaggioMidi(SND_SEQ_EVENT_NOTEOFF, SpinBox1.Value, 0) | ||
+ | |||
+ | snd_seq_close(seq) | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | Private Procedure InvioMessaggioMidi(tipo As Byte, nota As Byte, veloc As Byte) | ||
+ | |||
+ | Dim evento As Snd_seq_event_t | ||
With evento = New Snd_seq_event_t | With evento = New Snd_seq_event_t | ||
− | .type = | + | .type = tipo |
.queue = SND_SEQ_QUEUE_DIRECT | .queue = SND_SEQ_QUEUE_DIRECT | ||
.dest_client = CLIENT_DESTINATARIO | .dest_client = CLIENT_DESTINATARIO | ||
.dest_port = PORTA_DESTINATARIO | .dest_port = PORTA_DESTINATARIO | ||
.channel = 0 | .channel = 0 | ||
− | .note = | + | .note = nota |
− | .velocity = | + | .velocity = veloc |
End With | End With | ||
+ | |||
+ | snd_seq_event_output_direct(seq, evento) | ||
+ | |||
+ | End | ||
+ | In questo esempio, per inviare l'evento Midi di ALSA, invece della Struttura ''snd_seq_event_t'' sarà utilizzato un vettore di tipo Byte[]. | ||
+ | Private Const CLIENT_DESTINATARIO As Byte = 128 <FONT Color=gray>' ''Solitamente l'identificativo è 128''</font> | ||
+ | Private Const PORTA_DESTINATARIO As Byte = 0 | ||
+ | Private seq As Pointer | ||
+ | |||
+ | |||
+ | Library "libasound:2.0.0" | ||
+ | |||
+ | 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 | ||
+ | |||
+ | <FONT Color=gray>' ''int snd_seq_open (snd_seq_t **handle, const char * name, int streams, int mode)'' | ||
+ | ' ''Open the ALSA sequencer.''</font> | ||
+ | Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer | ||
+ | |||
+ | <FONT Color=gray>' ''const char * snd_strerror (int errnum)'' | ||
+ | ' ''Returns the message for an error code.''</font> | ||
+ | Private Extern snd_strerror(err As Integer) As Pointer | ||
+ | |||
+ | <FONT Color=gray>' ''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.''</font> | ||
+ | Private Extern <FONT Color=blue><B>snd_seq_event_output_direct</b></font>(handle As Pointer, ev 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 | ||
+ | |||
+ | |||
+ | Public Sub Form_Open() | ||
+ | |||
+ | SpinBox1.MaxValue = 127 | ||
+ | SpinBox1.Value = 64 | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | Public Sub Button1_MouseDown() | ||
+ | |||
+ | 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))) | ||
+ | |||
+ | InvioMessaggioMidi(SND_SEQ_EVENT_NOTEON, SpinBox1.Value, 100) | ||
End | End | ||
Riga 338: | Riga 420: | ||
Public Sub Button1_MouseUp() | Public Sub Button1_MouseUp() | ||
− | + | InvioMessaggioMidi(SND_SEQ_EVENT_NOTEOFF, SpinBox1.Value, 0) | |
− | |||
− | |||
snd_seq_close(seq) | snd_seq_close(seq) | ||
End | End | ||
− | In | + | |
− | + | ||
− | + | Private Procedure InvioMessaggioMidi(tipo As Byte, nota As Byte, veloc As Byte) | |
+ | |||
+ | Dim ev As New Byte[28] | ||
+ | |||
+ | <FONT Color=gray>' ''Vengono assegnati al vettore i valori fondamentali per generare l'evento Midi di ALSA:''</font> | ||
+ | ev[0] = tipo | ||
+ | ev[3] = SND_SEQ_QUEUE_DIRECT | ||
+ | ev[14] = CLIENT_DESTINATARIO | ||
+ | ev[15] = PORTA_DESTINATARIO | ||
+ | ev[17] = SpinBox1.Value | ||
+ | ev[18] = 100 | ||
+ | |||
+ | snd_seq_event_output_direct(seq, ev.Data) | ||
+ | |||
+ | End | ||
+ | |||
+ | |||
+ | ===3° caso=== | ||
+ | In questo caso si farà uso delle funzioni esterne di ALSA "snd_seq_event_output()" e "snd_seq_drain_output()" per l'invio di ciascun Evento Midi ALSA. | ||
+ | |||
+ | Nell'esempio pratico che segue viene rappresentata sul ''Form'' una tastierina Midi che può inviare dati Midi grezzi attraverso ALSA al Client-softsynth (ad esempio QSynth). Premendo un tasto di questa tastiera Midi interna, udiremo il suono della sua nota con il timbro dello strumento musicale prescelto in un ''ComboBox'' sul ''Form''. | ||
Private cb As ComboBox | Private cb As ComboBox | ||
Private Const ALTEZZA_TASTI_BIANCHI As Single = 0.35 | Private Const ALTEZZA_TASTI_BIANCHI As Single = 0.35 | ||
Riga 385: | Riga 485: | ||
.Y = 0 | .Y = 0 | ||
.List = instrumenta | .List = instrumenta | ||
− | . | + | .Placeholder = "Strumenti musicali GM" |
End With | End With | ||
Riga 482: | Riga 582: | ||
If Last.Background = Color.DarkGray Then Last.Background = Color.Black | If Last.Background = Color.DarkGray Then Last.Background = Color.Black | ||
− | Me.Title = | + | Me.Title = " " |
End | End | ||
Riga 513: | Riga 613: | ||
Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1 | Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1 | ||
− | |||
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253 | Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253 | ||
− | Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF | + | Private Enum SND_SEQ_EVENT_NOTEON = 6, SND_SEQ_EVENT_NOTEOFF, SND_SEQ_EVENT_PGMCHANGE = 11 |
<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 565: | Riga 664: | ||
− | Private Procedure InvioMIDI(tipo | + | Private Procedure InvioMIDI(tipo As Byte, mid As Byte[]) |
Dim evento As New Snd_seq_event_t | Dim evento As New Snd_seq_event_t | ||
Riga 606: | Riga 705: | ||
End | End | ||
− | |||
− | |||
− | |||
− | |||
− |
Versione attuale delle 12:03, 24 dic 2023
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.
Di seguito vedremo tre casi possibili, che saranno dimostrati con esempi pratici.
Se nel proprio sistema è stato installato il softsynth Fluidsynth, allora i programmi, appresso descritti, dovrebbero connettersi automaticamente a quel softsynth, consentendo così la riproduzione dei suoni. Qualora non avvenga, procedere come segue:
1) da Terminale lanciare questa riga: ":~$ fluidsynth reload 0", o meglio: ":~$ fluidsynth /percorso/del/file/soundfont/.sf2"
2) senza chiudere il Terminale, verificare nell'utilità "Monitor di sistema" che Fluidsynth sia presente fra i processi attivi;
3) se Fluidsynth è presente fra i processi, verificare anche che esso sia presente al num. 128 nel file /proc/asound/seq/clients;
4) in caso affermativo - senza chiudere il Terminale - lanciare il codice sopra esposto.
Indice
Casi
1° caso
In tale caso si deve sempre utilizzare la funzione esterna di ALSA: "snd_seq_event_output_direct()" per l'invio diretto di ciascun Evento Midi ALSA.
Inoltre il codice dovrà prevedere che 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 ' 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 handle As Pointer Dim rit As Integer 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 .type = ...etc... .queue = que .source_client = id .source_port = porta .dest_client = CLIENT_DESTINATARIO .dest_port = PORTA_DESTINATARIO ...etc... End With snd_seq_event_output_direct(handle, ev) snd_seq_close(handle) End
2° caso
Nel secondo caso si dovrà tenere conto di quanto segue:
- non sono utilizzate le funzioni esterne "snd_seq_client_id()" e "snd_seq_create_simple_port()", usate invece nel caso precedente, specifiche di ALSA per la creazione della porta del nostro Client applicativo in Gambas;
- pertanto non si useranno, lasciandoli al valore predefinito di zero, i membri .source_client e ..source_port della Struttura relativa agli eventi Midi;
- neppure sarà usata la funzione esterna "snd_seq_alloc_queue()" di ALSA;
- 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_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_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 handle As Pointer Dim rit As Integer 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))) With ev .type = ...etc... .queue = SND_SEQ_QUEUE_DIRECT .dest_client = CLIENT_DESTINATARIO .dest_port = PORTA_DESTINATARIO ...etc... End With snd_seq_event_output_direct(handle, ev) snd_seq_close(handle) 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à ovviamente la funzione esterna di ALSA "snd_seq_event_output_direct()" per l'invio diretto di ciascun 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
Quest'altro esempio, simile al precedente, è realizzato in ambiente grafico: sul Form sono posti uno SpinBox e un Button.
Cliccando sul Button si ascolterà il suono della nota Midi espressa dal valore mostrato dallo SpinBox che potrà essere variata manualmente.
Private Const CLIENT_DESTINATARIO As Byte = 128 ' Solitamente l'identificativo è 128 Private Const PORTA_DESTINATARIO As Byte = 0 Private seq As Pointer 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 Form_Open() SpinBox1.MaxValue = 127 SpinBox1.Value = 64 End Public Sub Button1_MouseDown() 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))) InvioMessaggioMidi(SND_SEQ_EVENT_NOTEON, SpinBox1.Value, 100) End Public Sub Button1_MouseUp() InvioMessaggioMidi(SND_SEQ_EVENT_NOTEOFF, SpinBox1.Value, 0) snd_seq_close(seq) End Private Procedure InvioMessaggioMidi(tipo As Byte, nota As Byte, veloc As Byte) Dim evento As Snd_seq_event_t With evento = New Snd_seq_event_t .type = tipo .queue = SND_SEQ_QUEUE_DIRECT .dest_client = CLIENT_DESTINATARIO .dest_port = PORTA_DESTINATARIO .channel = 0 .note = nota .velocity = veloc End With snd_seq_event_output_direct(seq, evento) End
In questo esempio, per inviare l'evento Midi di ALSA, invece della Struttura snd_seq_event_t sarà utilizzato un vettore di tipo Byte[].
Private Const CLIENT_DESTINATARIO As Byte = 128 ' Solitamente l'identificativo è 128 Private Const PORTA_DESTINATARIO As Byte = 0 Private seq As Pointer Library "libasound:2.0.0" 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 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 Form_Open() SpinBox1.MaxValue = 127 SpinBox1.Value = 64 End Public Sub Button1_MouseDown() 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))) InvioMessaggioMidi(SND_SEQ_EVENT_NOTEON, SpinBox1.Value, 100) End Public Sub Button1_MouseUp() InvioMessaggioMidi(SND_SEQ_EVENT_NOTEOFF, SpinBox1.Value, 0) snd_seq_close(seq) End Private Procedure InvioMessaggioMidi(tipo As Byte, nota As Byte, veloc As Byte) Dim ev As New Byte[28] ' Vengono assegnati al vettore i valori fondamentali per generare l'evento Midi di ALSA: ev[0] = tipo ev[3] = SND_SEQ_QUEUE_DIRECT ev[14] = CLIENT_DESTINATARIO ev[15] = PORTA_DESTINATARIO ev[17] = SpinBox1.Value ev[18] = 100 snd_seq_event_output_direct(seq, ev.Data) End
3° caso
In questo caso si farà uso delle funzioni esterne di ALSA "snd_seq_event_output()" e "snd_seq_drain_output()" per l'invio di ciascun Evento Midi ALSA.
Nell'esempio pratico che segue viene rappresentata sul Form una tastierina Midi che può inviare dati Midi grezzi attraverso ALSA al Client-softsynth (ad esempio QSynth). Premendo un tasto di questa tastiera Midi interna, udiremo il suono della sua nota con il timbro dello strumento musicale prescelto in un ComboBox sul Form.
Private cb As ComboBox Private Const ALTEZZA_TASTI_BIANCHI As Single = 0.35 Private bb As New Byte[3] Private instrumenta As String[] = ["Acustic Grand Piano", "Bright Acustic Piano", "Electric Grand Piano", "Honky-tonk", "Electric Piano 1", "Electric Piano 2", "Harpsichord", "Clavinet", "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Hammond Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango Accordion", "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar(muted)", "Overdriven Guitar", "Distortion Guitar", "Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Harp", "Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section", "Synth Brass 1", "Synth Brass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Basson", "Clarinet", "Piccolo", "Flute", "Recorder", "Pan Flute", "Bottle Blow", "Shakuhachi", "Whistle", "Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (caliope lead)", "Lead 4 (chiff lead)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8(brass+lead)", "Pad 1 (new age)", "Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)", "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe", "Fiddle", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter", "Applause", "Gunshot"] Public Sub Form_Open() With Me .W = Screen.AvailableWidth * 0.5 .H = Screen.AvailableHeight * 0.2 .Center End With CreaClient() With cb = New ComboBox(Me) As "Combo" .W = 160 .H = 25 .X = (Me.W * 0.94) - .W .Y = 0 .List = instrumenta .Placeholder = "Strumenti musicali GM" End With CreaTastiera() End Private Procedure CreaTastiera() Dim pn As Panel Dim neri As New Byte[40] Dim tasti As Button[] Dim b, c, n As Byte With pn = New Panel(Me) .W = Me.W * 0.88 .H = Me.H * 0.2 .X = (Me.W / 2) - (pn.W / 2) .Y = Me.H * 0.2 .Border = Border.Sunken .Background = &8b4513 End With Repeat neri[b] = 25 + (12 * b / 5) neri[b + 1] = 27 + (12 * b / 5) neri[b + 2] = 30 + (12 * b / 5) neri[b + 3] = 32 + (12 * b / 5) neri[b + 4] = 34 + (12 * b / 5) b += 5 Until b == neri.Count tasti = New Button[109] For t As Short = 0 To tasti.Max With tasti[t] = New Button(Me) As "Tasti" .W = 0 If t > 23 Then If neri.Exist(t) Then ' Imposta i tasti neri .W = Me.W * 0.013 .H = ((Me.H * ALTEZZA_TASTI_BIANCHI) * 66.66) / 100 Select Case t Case 25 + (12 * n) .X = tasti[t - 1].X + (((Me.W * 0.025) / 2)) Case 27 + (12 * n) .X = tasti[t - 1].X + (((Me.W * 0.025) / 2)) Case 30 + (12 * n) .X = tasti[t - 1].X + (((Me.W * 0.025) / 2)) Case 32 + (12 * n) .X = tasti[t - 1].X + (((Me.W * 0.025) / 2)) Case 34 + (12 * n) .X = tasti[t - 1].X + (((Me.W * 0.025) / 2)) Inc n End Select .Y = Me.H * 0.375 .Background = Color.Black .Tag = t Else ' Imposta i tasti bianchi: .W = Me.W * 0.018 .H = Me.H * ALTEZZA_TASTI_BIANCHI .X = (.W * c) + (Me.W / 16) .Y = Me.H * 0.37 .Background = Color.White .Tag = t .Lower Inc c Endif Endif End With Next End Public Sub Tasti_MouseDown() bb[0] = 0 bb[1] = Last.Tag bb[2] = &64 InvioMIDI(SND_SEQ_EVENT_NOTEON, bb) If Last.Background = Color.Black Then Last.Background = Color.DarkGray Me.Title = "Nota Midi: " & Last.Tag End Public Sub Tasti_MouseUp() bb[0] = 0 bb[1] = Last.Tag bb[2] = 0 InvioMIDI(SND_SEQ_EVENT_NOTEOFF, bb) If Last.Background = Color.DarkGray Then Last.Background = Color.Black Me.Title = " " End ''''''''''''''''''''''''''''''''''''''''''''''' Private seq As Pointer Library "libasound:2" Public Struct snd_seq_event_t ' Struttura dell'Evento Midi di ALSA 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_PGMCHANGE = 11 ' 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 String ' 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 Private Procedure CreaClient() Dim rit As Integer rit = snd_seq_open(VarPtr(seq), "default", SND_SEQ_OPEN_OUTPUT, 0) If rit < 0 Then Error.Raise("Impossibile aprire il subsistema 'seq' di ALSA: " & snd_strerror(rit)) End Public Sub Combo_Change() ' Imposta lo strumento musicale Dim evento As New Snd_seq_event_t With evento .queue = SND_SEQ_QUEUE_DIRECT .dest_client = 128 .dest_port = 0 .channel = 0 End With ' Imposta il tipo di strumento musicale mediante il Messaggio Midi "Program-Change": Messaggio(evento, SND_SEQ_EVENT_PGMCHANGE, [0, 0, 0], cb.Index) End Private Procedure InvioMIDI(tipo As Byte, mid As Byte[]) Dim evento As New Snd_seq_event_t With evento .queue = SND_SEQ_QUEUE_DIRECT .dest_client = 128 .dest_port = 0 .channel = mid[0] End With ' Imposta il Messaggio Midi: Messaggio(evento, tipo, mid, 0) End Private Procedure Messaggio(ev As Snd_seq_event_t, tipo As Byte, nota As Byte[], strum As Integer) With ev .type = tipo .channel = nota[0] .note = nota[1] .velocity = nota[2] .value = strum End With ' Inserisce l'Evento di ALSA nel buffer: snd_seq_event_output(seq, ev) ' Invia l'Evento: snd_seq_drain_output(seq) End Public Sub Form_Close() snd_seq_close(seq) End