|
|
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.
| + | #REDIRECT [[ALSA_e_Gambas:_Esempio_di_semplice_Commutatore_Midi_con_Alsa]] |
− | 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.
| |
− | <BR>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 <FONT color=gray>' ''byte n° 0''</font>
| |
− | 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 <FONT color=gray>' ''byte n° 16''</font>
| |
− | note As Byte
| |
− | velocity As Short
| |
− | primoValore As Integer <FONT color=gray>' ''byte n° 20''</font>
| |
− | secondoValore As Integer <FONT color=gray>' ''byte n° 24''</font>
| |
− | 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
| |
− |
| |
− |
| |
− | <FONT color=gray>' ''const char * snd_strerror(int errnum)''
| |
− | ' ''Returns the message for an error code.''</font>
| |
− | Private Extern snd_strerror(errnum As Integer) As String
| |
− |
| |
− | <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>' ''int snd_seq_set_client_name(snd_seq_t* seq, const char* name)''
| |
− | ' ''Set client name.''</font>
| |
− | Private Extern snd_seq_set_client_name(handle As Pointer, name As String) As Integer
| |
− |
| |
− | <FONT color=gray>' ''int snd_seq_client_id (snd_seq_t *seq)''
| |
− | ' ''Get the client id.''</font>
| |
− | Private Extern snd_seq_client_id(handle 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)''
| |
− | ' ''Create a port - simple version.''</font>
| |
− | Private Extern snd_seq_create_simple_port(handle As Pointer, name As String, caps As Integer, type As Integer) As Integer
| |
− |
| |
− | <FONT color=gray>' ''int snd_seq_event_input(snd_seq_t *handle, snd_seq_event_t **ev)''
| |
− | ' ''Retrieve an event from sequencer.''</font>
| |
− | Private Extern snd_seq_event_input(handle As Pointer, ev As Snd_seq_event_t) 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 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 j 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 j = 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)
| |
− | If idportaU[j] < 0 Then Error.Raise("Impossibile creare una porta del Commutatore Midi: " & snd_strerror(err))
| |
− | Print "Id porta di Uscita n.: "; idportaU[j]
| |
− | 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
| |
− |
| |
− | While True
| |
− |
| |
− | snd_seq_event_input(seqiM, VarPtr(ev))
| |
− | midi@ = ev
| |
− |
| |
− |
| |
− | <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.''
| |
− | ' ''In questo esempio il Commutatore MIDI è connesso con due sue porte di Uscita ad due diversi Client Alsa attivi.''</font>
| |
− | With midi@
| |
− |
| |
− | If .note = 60 Then <FONT color=gray>' ''Se i messaggi "NoteOn" giungono''</font>
| |
− | .channel = 0 <FONT color=gray>' ''già con canali diversi,''</font>
| |
− | Else <FONT color=gray>' ''allora questa parte di codice''</font>
| |
− | .channel = 1 <FONT color=gray>' ''può essere eliminata.''</font>
| |
− | Endif <FONT color=gray>'</font>
| |
− |
| |
− | .source_id = idC
| |
− |
| |
− | If .channel = 0 Then
| |
− | .source_porta = 1 <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 1''</font>
| |
− | Else
| |
− | .source_porta = 2 <FONT color=gray>' ''Uscirà dalla porta di Uscita n. 2''</font>
| |
− | Endif
| |
− | .dest_id = SND_SEQ_ADDRESS_SUBSCRIBERS
| |
− | .dest_porta = SND_SEQ_ADDRESS_UNKNOWN
| |
− | End With
| |
− |
| |
− | snd_seq_event_output_direct(seqiM, midi@)
| |
− |
| |
− | Wend
| |
− |
| |
− | '''End'''
| |