Differenze tra le versioni di "Ricevere dati Midi senza funzioni di ALSA e inviarli mediante le funzioni di Alsa"

Da Gambas-it.org - Wikipedia.
 
(6 versioni intermedie di uno stesso utente non sono mostrate)
Riga 29: Riga 29:
 
     value As Integer</font>
 
     value As Integer</font>
 
  End Struct
 
  End Struct
 +
  
 
==Esempi pratici==
 
==Esempi pratici==
===Ricevere dati Midi grezzi inviati da un dispositivo Midi interno===
+
===Ricevere dati Midi grezzi inviati da un dispositivo Midi esterno===
Mostriamo un semplice esempio, in ambiente grafico, per ricevere dati Midi grezzi, inviati dal codice interno dell'esempio medesimo, che saranno inviati subito attraverso ALSA al Client-softsynth (ad esempio QSynth).
+
Mostriamo un semplice esempio, in ambiente grafico, per ricevere dati Midi grezzi, inviati da un dispositivo Midi esterno (ad esempio una tastiera Midi) e che saranno inviati subito attraverso ALSA al Client-softsynth (ad esempio QSynth).
<BR>Sul ''Form'' è rappresentata una tastiera musicale. 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''.
 
 
<BR>Come si potrà notare, utilizzeremo uno speciale codice per la gestione delle risorse di ALSA, nel quale non si creerà arbitrariamente una Porta del nostro ''Client'' Midi mediante la specifica funzione esterna di ALSA. Conseguentemente, dovremo assegnare al membro "''queue'' " della Struttura degli "Eventi Midi" di ALSA, sopra illustrata, il valore della Costante "SND_SEQ_QUEUE_DIRECT" delle risorse di ALSA che ha il valore 253.
 
<BR>Come si potrà notare, utilizzeremo uno speciale codice per la gestione delle risorse di ALSA, nel quale non si creerà arbitrariamente una Porta del nostro ''Client'' Midi mediante la specifica funzione esterna di ALSA. Conseguentemente, dovremo assegnare al membro "''queue'' " della Struttura degli "Eventi Midi" di ALSA, sopra illustrata, il valore della Costante "SND_SEQ_QUEUE_DIRECT" delle risorse di ALSA che ha il valore 253.
Private cb As ComboBox
 
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.6
 
    .H = Screen.AvailableHeight * 0.3
 
    .Center
 
  End With
 
  CreaClient()
 
  With cb = New ComboBox(Me) As "Combo"
 
    .W = 160
 
    .H = 25
 
    .X = (Me.W * 0.93) - .W
 
    .Y = 0
 
    .List = instrumenta
 
    .Index = 0
 
  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.86
 
    .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  <FONT Color=gray>' ''Imposta i tasti neri''</font>
 
          .W = Me.W * 0.0122
 
          .H = Me.H * 0.16
 
          Select Case t
 
            Case 25 + (12 * n)
 
              .X = tasti[t - 1].X + (((Me.W * 0.0245) / 2))
 
            Case 27 + (12 * n)
 
              .X = tasti[t - 1].X + (((Me.W * 0.0245) / 2))
 
            Case 30 + (12 * n)
 
              .X = tasti[t - 1].X + (((Me.W * 0.0245) / 2))
 
            Case 32 + (12 * n)
 
              .X = tasti[t - 1].X + (((Me.W * 0.0245) / 2))
 
            Case 34 + (12 * n)
 
              .X = tasti[t - 1].X + (((Me.W * 0.0245) / 2))
 
              Inc n
 
          End Select
 
          .Y = Me.H * 0.38
 
          .Background = Color.Black
 
          .Tag = t
 
        Else
 
<FONT Color=gray>' ''Imposta i tasti bianchi:''</font>
 
          .W = Me.W * 0.018
 
          .H = Me.H * 0.25
 
          .X = (.W * c) + (Me.W / 14) + 1
 
          .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(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(bb)
 
 
  If Last.Background = Color.DarkGray Then Last.Background = Color.Black
 
  Me.Title = Null
 
 
End
 
 
<FONT Color=gray>''''''''''''''''''''''''''''''''''''''''''''''''''''</font>
 
 
Private seq As Pointer
 
 
 
Library "libasound:2"
 
 
Public Struct snd_seq_event_t  <FONT Color=gray>' ''Struttura dell'Evento Midi di ALSA''</font>
 
  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 Const SND_SEQ_EVENT_NOTEON As Byte = 6
 
Private Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11
 
 
<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 String
 
 
 
<FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)''
 
' ''Output an event.''</font>
 
Private Extern snd_seq_event_output(handle As Pointer, ev As Snd_seq_event_t)
 
 
<FONT Color=gray>' ''int snd_seq_drain_output (snd_seq_t * seq)''
 
' ''Drain output buffer to sequencer.''</font>
 
Private Extern snd_seq_drain_output(seq 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
 
 
 
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()  <FONT Color=gray>' ''Imposta lo strumento musicale''</font>
 
 
  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
 
 
<FONT Color=gray>' ''Imposta il tipo di strumento musicale mediante il Messaggio Midi "Program-Change":''</font>
 
  Messaggio(evento, SND_SEQ_EVENT_PGMCHANGE, [0, 0, 0], cb.Index)
 
 
End
 
 
 
Private Procedure InvioMIDI(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
 
 
<FONT Color=gray>' ''Imposta il Messaggio Midi "Note-ON":''</font>
 
  Messaggio(evento, SND_SEQ_EVENT_NOTEON, 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
 
 
<FONT Color=gray>' ''Inserisce l'Evento di ALSA nel buffer:''</font>
 
  snd_seq_event_output(seq, ev)
 
 
<FONT Color=gray>' ''Invia l'Evento:''</font>
 
  snd_seq_drain_output(seq)
 
 
End
 
 
 
Public Sub Form_Close()
 
 
  snd_seq_close(seq)
 
 
End
 
 
 
===Ricevere dati Midi grezzi inviati da un dispositivo Midi esterno===
 
Il seguente semplice codice è simile a quello precedente, ma con la differenza che in questo caso i dati Midi grezzi saranno ricevuti da un dispositivo Midi esterno (ad esempio una tastiera Midi).
 
 
  Private fl As File
 
  Private fl As File
 
  Private cb As ComboBox
 
  Private cb As ComboBox
Riga 396: Riga 135:
 
  End Struct
 
  End Struct
 
   
 
   
Private Const SND_SEQ_PORT_CAP_READ As Integer = 0
 
 
  Private Const SND_SEQ_OPEN_OUTPUT As Integer = 1
 
  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_MIDI_GENERIC As Integer = 2
 
  Private Const SND_SEQ_EVENT_NOTEON As Byte = 6
 
  Private Const SND_SEQ_EVENT_NOTEON As Byte = 6

Versione attuale delle 03:41, 2 dic 2023

Non è necessario in modo assoluto utilizzare le risorse esterne di ALSA per ricevere dati Midi inviati da un dispositivo esterno (ad esempio da una tastiera Midi).
I dati Midi, inviati da tale dispositivo, possono essere intercettati aprendo e leggendo il file-device specifico, creato all'atto della connessione di quel dispositivo esterno al computer.
In questo caso si intercetteranno dal dispositivo esterno i dati grezzi inviati.

In questa pagina vedremo come ricevere dati grezzi, dunque, da un dispositivo esterno e come inviarli subito attraverso ALSA ad un softsynth (ad esempio QSynth), affinché siano riprodotti i suoni delle note e dello strumento prescelti.
In particolare, il programma intercetterà i dati Midi grezzi, inviati dal dispositivo Midi esterno, aprendo in lettura e ponendo sotto "osservazione" il file-device creato appositamente dal sistema, senza l'uso di risorse esterne di ALSA. Opportunamente elaborati secondo il protocollo di ALSA, tali dati ricevuti saranno inviati al softhsynth mediante le funzioni esterne di ALSA per la riproduzione sonora.

A tal proposito, come sappiamo, ALSA non accetta semplici dati Midi grezzi, come quelli che arrivano al file-device della tastiera Midi esterna connessa ed inviati da appunto questo dispositivo.
ALSA accetta solo i dati Midi inviati ad essa rigorosamente nella forma dei suoi "Eventi Midi", come stabiliti e descritti dalle specificazioni di ALSA.
Così, ogni "Messaggio", previsto dal protocollo Midi, deve essere organizzato in una porzione di memoria assegnata, introducendo diversi specifici valori, e solo dopo possono essere inviati ad ALSA.
Sappiamo anche che la prima parte (16 byte) di questa porzione di memoria sarà occupata da valori comuni a tutti gli "Eventi Midi" di ALSA; mentre la parte restante e ultima sarà occupata dai valori inerenti agli specifici "Messaggi" previsti dal protocollo Midi.
Dunque, per organizzare un "Evento Midi " di ALSA, terremo conto della Struttura snd_seq_event_t prevista dall'API di ALSA, e in Gambas potremo utilizzare l'Oggetto Struttura come astrattamente segue:

Public Struct Snd_seq_event_t
  type As Byte
  flags As Byte
  tag As Byte           
  queue As Byte                 Dati comuni
  tick_time As Integer          a tutti
  real_time As Integer          gli Eventi Midi di ALSA
  source_client As Byte
  source_port As Byte
  dest_client As Byte
  dest_port As Byte
    channel As Byte
    note As Byte                   Dati appartenenti
    velocity As Byte               agli specifici "Messaggi"
    off_velocity As Byte           del protocollo Midi
    param As Integer
    value As Integer
End Struct


Esempi pratici

Ricevere dati Midi grezzi inviati da un dispositivo Midi esterno

Mostriamo un semplice esempio, in ambiente grafico, per ricevere dati Midi grezzi, inviati da un dispositivo Midi esterno (ad esempio una tastiera Midi) e che saranno inviati subito attraverso ALSA al Client-softsynth (ad esempio QSynth).
Come si potrà notare, utilizzeremo uno speciale codice per la gestione delle risorse di ALSA, nel quale non si creerà arbitrariamente una Porta del nostro Client Midi mediante la specifica funzione esterna di ALSA. Conseguentemente, dovremo assegnare al membro "queue " della Struttura degli "Eventi Midi" di ALSA, sopra illustrata, il valore della Costante "SND_SEQ_QUEUE_DIRECT" delle risorse di ALSA che ha il valore 253.

Private fl As File
Private cb As ComboBox
Private bb As Byte[]
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()

 Dim dev As String

' Individua il file-device Midi:
 dev = Dir("/dev", "*midi*", gb.Device)[0]

 With Me
   .W = 300
   .H = 150
   .Center
 End With

 CreaClient()

 With cb = New ComboBox(Me) As "Combo"
   .W = 180
   .H = 30
   .X = (Me.W / 2) - (.W / 2)
   .Y = (Me.H / 2.5) - .H
   .List = instrumenta
   .Index = 0
 End With

 bb = New Byte[]

' Apre il file-device Midi in "Lettura" e lo pone in "Osservazione":
 fl = Open "/dev" &/ dev For Read Watch

End


Public Sub File_Read()

 Dim b As Byte

' Se c'è qualcosa da leggere dal file-device, lo legge":
 Read #fl, b

' Prende in considerazione soltanto Messaggi-Midi "Note-OFF" e "Note-ON":
 If b > 159 Then Return
 bb.Push(b)
 If bb.Count == 3 Then
   InvioMIDI(bb)
   bb = New Byte[]
 Endif

End

'''''''''''''''''''''''''''''''''''''''''''''

Private seq As Pointer
Private id As Integer
Private porta As Integer


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_PORT_CAP_READ As Integer = 1
Private Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
Private Const SND_SEQ_EVENT_NOTEON As Byte = 6
Private Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11
Private Const SND_SEQ_QUEUE_DIRECT As Byte = 253
Private Const SND_SEQ_ADDRESS_UNKNOWN As Byte = 253
Private Const SND_SEQ_ADDRESS_SUBSCRIBERS As Byte = 254
Private Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576

' 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_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_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_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))

 id = snd_seq_client_id(seq)

 porta = snd_seq_create_simple_port(seq, "Uscita", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)

' Si connette al Client di ALSA avente numero ID 128:
 rit = snd_seq_connect_to(seq, porta, 128, 0)
 If rit < 0 Then Error.Raise("Impossibile connettersi al Client 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
   .source_client = id
   .source_port = porta
   .dest_client = SND_SEQ_ADDRESS_SUBSCRIBERS
   .dest_port = SND_SEQ_ADDRESS_UNKNOWN
   .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(mid As Byte[])

 Dim evento As New Snd_seq_event_t

 With evento
   .queue = SND_SEQ_QUEUE_DIRECT
   .source_client = id
   .source_port = porta
   .dest_client = SND_SEQ_ADDRESS_SUBSCRIBERS
   .dest_port = SND_SEQ_ADDRESS_UNKNOWN
   .channel = mid[0] And &0F
 End With

' Imposta il Messaggio Midi "Note-ON":
 Messaggio(evento, SND_SEQ_EVENT_NOTEON, 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
   .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)
 fl.Close

End