vamos de nuevo con la... MIDI-mania
Este código intercepta con las funciones externas del subsistema Seq de ALSA los datos Midi enviados de un dispositivo Midi externo (por ejemplo un teclado Midi).
Hace falta conectar antes de todo el teclado Midi con el sistema ALSA:
~ $ aconnect 24:0 14:0
Private bo as Boolean
Library "libasound:2"
Public Struct snd_seq_event
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_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_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
' 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_connect_from(seq as pointer, myport as integer, src_client as integer, src_port as integer)
' Simple subscription (w/o exclusive & time conversion)
Private Extern snd_seq_connect_from(seq As Pointer, myport As Integer, src_client As Integer, src_port 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 Pointer) As Integer
' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer
Public Sub Main()
Dim seq, po As Pointer
Dim i As Integer
Dim evento As Snd_seq_event
seq = Connectio_Alsa()
While bo = False
i = snd_seq_event_input(seq, VarPtr(po))
evento = po
If i = 0 Then Break
If IsNull(evento) = False Then Videre_Eventum(evento)
Wait 0.01
Wend
snd_seq_close(seq)
Print "\nFinis terrae !"
Quit
End
Private Function Connectio_Alsa() As Pointer
Dim hs As Pointer
Dim i, porta_in As Integer
i = snd_seq_open(VarPtr(hs), "default", SND_SEQ_OPEN_DUPLEX, 0)
If i < 0 Then Error.Raise("No se ha podido abrir el sub-sistema 'seq' de ALSA !")
porta_in = snd_seq_create_simple_port(hs, "gambas", SND_SEQ_PORT_CAP_WRITE Or SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
If porta_in < 0 Then Error.Raise("No se ha podido crear una puerta del Client de ALSA !")
i = snd_seq_connect_from(hs, porta_in, 14, 0)
If i < 0 Then Error.Raise("No se ha podido conectar la puerta del Client a ALSA !")
Return hs
End
Private Procedure Videre_Eventum(eventum As Snd_seq_event)
Select Case eventum.type
Case SND_SEQ_EVENT_NOTEOFF
With eventum
Print "Note Off: ", .channel, .note, .velocity
End With
Case SND_SEQ_EVENT_NOTEON
With eventum
Print "Note On: ", .channel, .note, .velocity
End With
Case SND_SEQ_EVENT_CONTROLLER
With eventum
Print "Control Change: ", .channel, .param, .value
End With
Case SND_SEQ_EVENT_PGMCHANGE
With eventum
Print "Program Change: ", .channel, .value
End With
End Select
End
Public Sub Application_Read() ' ...para cerrar la aplicación
Dim s As String
Input #File.in, s
If s = "q" Then bo = True
End
Library "libasound:2"
Public Struct snd_seq_event
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_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_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
' 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_connect_from(seq as pointer, myport as integer, src_client as integer, src_port as integer)
' Simple subscription (w/o exclusive & time conversion)
Private Extern snd_seq_connect_from(seq As Pointer, myport As Integer, src_client As Integer, src_port 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 Pointer) As Integer
' int snd_seq_close (snd_seq_t *handle)
' Close the sequencer.
Private Extern snd_seq_close(handle As Pointer) As Integer
Public Sub Main()
Dim seq, po As Pointer
Dim i As Integer
Dim evento As Snd_seq_event
seq = Connectio_Alsa()
While bo = False
i = snd_seq_event_input(seq, VarPtr(po))
evento = po
If i = 0 Then Break
If IsNull(evento) = False Then Videre_Eventum(evento)
Wait 0.01
Wend
snd_seq_close(seq)
Print "\nFinis terrae !"
Quit
End
Private Function Connectio_Alsa() As Pointer
Dim hs As Pointer
Dim i, porta_in As Integer
i = snd_seq_open(VarPtr(hs), "default", SND_SEQ_OPEN_DUPLEX, 0)
If i < 0 Then Error.Raise("No se ha podido abrir el sub-sistema 'seq' de ALSA !")
porta_in = snd_seq_create_simple_port(hs, "gambas", SND_SEQ_PORT_CAP_WRITE Or SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC Or SND_SEQ_PORT_TYPE_APPLICATION)
If porta_in < 0 Then Error.Raise("No se ha podido crear una puerta del Client de ALSA !")
i = snd_seq_connect_from(hs, porta_in, 14, 0)
If i < 0 Then Error.Raise("No se ha podido conectar la puerta del Client a ALSA !")
Return hs
End
Private Procedure Videre_Eventum(eventum As Snd_seq_event)
Select Case eventum.type
Case SND_SEQ_EVENT_NOTEOFF
With eventum
Print "Note Off: ", .channel, .note, .velocity
End With
Case SND_SEQ_EVENT_NOTEON
With eventum
Print "Note On: ", .channel, .note, .velocity
End With
Case SND_SEQ_EVENT_CONTROLLER
With eventum
Print "Control Change: ", .channel, .param, .value
End With
Case SND_SEQ_EVENT_PGMCHANGE
With eventum
Print "Program Change: ", .channel, .value
End With
End Select
End
Public Sub Application_Read() ' ...para cerrar la aplicación
Dim s As String
Input #File.in, s
If s = "q" Then bo = True
End