Differenze tra le versioni di "Alsa e Gambas: Invio dati con l'uso di un'area di memoria allocata"

Da Gambas-it.org - Wikipedia.
Riga 3: Riga 3:
  
 
==Riservare innanzitutto memoria per il puntatore==
 
==Riservare innanzitutto memoria per il puntatore==
Utilizzeremo quindi la funzione "Alloc()" per riservare una porzione di memoria e porla a disposizione del pointer, che chiameremo: &quot;ev". Più precisamente con ''Alloc()'' si prende una parte di memoria dal sistema e la si assegna al programma. A questo punto è possibile operare con il pointer, a patto che si vada a scrivere ''esclusivamente'' dentro quella porzione di memoria che è stata appositamente riservata per il Puntatore <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
+
Utilizzeremo quindi la funzione "Alloc()" per riservare una porzione di memoria e porla a disposizione del pointer, che chiameremo: &quot;ev". Più precisamente con "Alloc()" si prende una parte di memoria dal sistema e la si assegna al programma. A questo punto è possibile operare con il pointer, a patto che si vada a scrivere ''esclusivamente'' dentro quella porzione di memoria che è stata appositamente riservata per il Puntatore <SUP>&#091;[[#Note|nota 1]]&#093;</sup>
  
 
Assegneremo un'adeguata porzione pari a 28 byte:
 
Assegneremo un'adeguata porzione pari a 28 byte:
Riga 78: Riga 78:
  
  
==Il codice completo==
+
==Codice Esemplificativo==
Mostriamo di seguito il codice definitivo sin qui descritto, proposto per un'applicazione in ambiente grafico, ed avente un'apposita Classe destinata a contenenre le funzioni e risorse per la gestione di ALSA e degli eventi Midi:
+
Mostriamo di seguito un codice esemplificativo, che fa uso appunto di un'area di memoria riservata per disporre adeguatamente i dati necessari a creare un Evento Midi da inviare ad ALSA.
 
+
Private Const ID_SOFTSYNTH As Byte = 128
  CLASSE: FMain.class
+
  Private Const PORTA_SOFTSYNTH As Byte = 0
 
+
  Private Const CANALE As Byte = 0
  Public alsa as CAlsa      <Font Color= #006400>' ''classe che incapsula le funzioni ALSA''</font>
+
  Private Const CONTROL_CHANGE As Integer = 7
  Public gross As Integer   <Font Color= #006400>' dovrebbe ricevere il valore da uno ''Slider''</font>
+
  Private Const VOLUME As Byte = 100
   
+
  Private Const NOTA As Byte = 64
   
+
  Private Const AREA_DI_MEMORIA As Byte = 28
  '''Public''' Sub Form_Open()
+
  Private strum 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",
<Font Color= #006400>' ''Crea ("istanzia") la classe per poterla usare''</font>
+
  "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Hammond Organ", "Percussive Organ", "Rock Organ", "Church Organ",
alsa = NEW CAlsa as "alsa"
+
  "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",
<Font Color= #006400>' ''Apre alsa e gli assegna un nome''</font>
+
  "Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1",
alsa.alsa_open("Progetto sequencer in Gambas-3")<Font Color= #006400> ' ''La stringa fra virgolette sarà il nome del nostro Client''</font>
+
   "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",
<Font Color= #006400>' ''Sceglie la periferica su cui suonare.''
+
  "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet",
' ''Ident.vo numerico e num. porta di altro dispositivo/client (ad esempio: QSynth), al quale il client si connetterà.''</font>
+
   "French Horn", "Brass Section", "Synth Brass 1", "Synth Brass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax",
alsa.setdevice(128, 0)
+
   "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)",
'''End'''
+
   "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)",
'''Public''' Sub noteOn_Click()         <Font Color= #006400>' '''Note ON'''</font>
+
   "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",
  <Font Color= #006400>' ''chiama la subroutine "noteon" nella classe secondaria CAlsa.class;''
+
   "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter", "Applause", "Gunshot"]
  ' ''poniamo come esempio la nota da suonare num. 60 (il DO centrale) e velocità 100.''</font>
 
  alsa.noteon(0, 60, 100)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
'''Public''' Sub noteOff_Click()         <Font Color= #006400>' '''Note OFF'''</font>
 
    
 
  <Font Color= #006400>' ''chiama la subroutine "noteoff" nella classe secondaria CAlsa.class;''
 
  ' ''poniamo come esempio la nota da far cessare di suonare num. 60 (il DO centrale) e velocità 0.''</font>
 
  alsa.noteoff(0, 60, 0)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
'''Public''' Sub polypho_Click()          <Font Color= #006400>' '''Polyphonic Aftertouch (Key pressure)'''</font>
 
   
 
   <FONT Color= #006400>' ''chiama la subroutine, che chiameremo "polypho", nella classe secondaria CAlsa.class;''</font>
 
   <FONT Color= #006400>' ''poniamo come esempio alla nota 50 un valore di pressione aggiuntiva di 110.''</font>
 
   alsa.polypho(0, 60, 110)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
 
'''Public''' Sub controller_Click()         <Font Color= #006400>' '''Control Change'''</font>
 
   
 
  <FONT Color= #006400>' ''chiama la subroutine, che chiameremo "controller", nella classe secondaria CAlsa.class;''</font>
 
   <FONT Color= #006400>' ''poniamo come esempio il tipo di controller num. 7 (Volume). Il terzo valore sarà posto a 100.''</font>
 
  alsa.controller(0, 7, 100)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
'''Public''' Sub pgmchange_Click()         <Font Color= #006400>' '''Program Change'''</font>
 
   
 
  ' ''chiama la subroutine, che chiameremo "pgmchange", nella classe secondaria CAlsa.class;''</font>
 
   <FONT Color= #006400>' ''poniamo come esempio lo strumento musicale num. 71 (Fagotto).''</font>
 
  alsa.pgmchange(0, 71)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
'''Public''' Sub chanpress_Click()         <Font Color= #006400>' '''Channel Aftertouch (Channel Pressure)'''</font>
 
   
 
  <FONT Color= #006400>' ''chiama la subroutine, che chiameremo "chanpress", nella classe secondaria CAlsa.class;''</font>
 
   <FONT Color= #006400>' ''poniamo come esempio un valore di pressione aggiuntiva di 110.''</font>
 
  alsa.chanpress(0, 110)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
'''Public''' Sub SliderPB_Change()         <Font Color= #006400>' '''Pitch Bend (Pitch Wheel)'''</font>
 
   
 
   gross = SliderPB.Value
 
 
   <FONT Color= #006400>' ''chiama la subroutine, che chiameremo "pitchbend", nella classe secondaria CAlsa.class;''</font>
 
   alsa.pitchbend(0, 0, gross)
 
 
  alsa.flush()
 
 
'''End'''
 
 
 
----
 
 
 
 
 
CLASSE: CAlsa.class
 
 
 
Private handle As Pointer
 
Private id As Integer
 
Private outport As Integer
 
Private outq As Integer
 
 
Public dclient As Byte
 
Public dport As Byte
 
 
   
 
   
 +
Private alsa As Pointer
 +
Private id As Byte
 +
Private que As Byte
 +
Private porta As Integer
 
  Private ev As Pointer
 
  Private ev As Pointer
  Private p As Stream
+
  Private st As Stream
 
Const SND_SEQ_OPEN_DUPLEX As Integer = 3
 
Const SND_SEQ_PORT_TYPE_MIDI_GENERIC As Integer = 2
 
Const SND_SEQ_PORT_TYPE_APPLICATION As Integer = 1048576  <Font Color= #006400>'  (1<<20)</font>
 
 
Const SND_SEQ_ADDRESS_UNKNOWN As Byte = 253
 
Const SND_SEQ_ADDRESS_SUBSCRIBERS As Byte = 254
 
 
Const SND_SEQ_EVENT_NOTEON As Byte = 6
 
Const SND_SEQ_EVENT_NOTEOFF As Byte = 7
 
Const SND_SEQ_EVENT_KEYPRESS As Byte = 8
 
Const SND_SEQ_EVENT_CONTROLLER As Byte = 10
 
Const SND_SEQ_EVENT_PGMCHANGE As Byte = 11
 
Const SND_SEQ_EVENT_CHANPRESS As Byte = 12
 
Const SND_SEQ_EVENT_PITCHBEND As Byte = 13
 
 
 
Private Const SIZE_OF_SEQEV As Integer = 64
 
 
   
 
   
 
  Library "libasound:2"
 
  Library "libasound:2"
 
   
 
   
  <Font Color= #006400>''''---- Parte relativa alla creazione del Client e delle sue porte ----'''
+
  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  '  (1<<20)
 +
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);'' </font>
+
  <FONT Color=gray>' ''int snd_seq_open (snd_seq_t **seqp, const char * name, int streams, int mode)''
  Private Extern snd_seq_open(handle As Pointer, name As String, streams As Integer, mode As Integer) As Integer
+
' Open the ALSA sequencer.''</font>
 +
  Private Extern snd_seq_open(seqp As Pointer, name As String, streams As Integer, mode As Integer) As Integer
 
   
 
   
  <Font Color= #006400>' ''int snd_seq_set_client_name(snd_seq_t* seq, const char* name)''</font>
+
  <FONT Color=gray>' ''int snd_seq_set_client_name (snd_seq_t* seq, const char* name)''
  Private Extern snd_seq_set_client_name(handle As Pointer, name As String) As Integer
+
' ''Set client name.''</font>
 +
  Private Extern snd_seq_set_client_name(seq As Pointer, name As String) As Integer
 
   
 
   
  <Font Color= #006400>' ''int snd_seq_create_simple_port(snd_seq_t* seq, const char* name, unsigned int caps, unsigned int type)''</font>
+
  <FONT Color=gray>' ''int snd_seq_create_simple_port (snd_seq_t* seq, const char* name, unsigned int caps, unsigned int type)''
  Private Extern snd_seq_create_simple_port(handle As Pointer, name As String, caps As Integer, type As Integer) As Integer
+
' ''Creates a port with the given capability and type bits.''</font>
 +
  Private Extern snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer
 
   
 
   
  <Font Color= #006400>' ''int snd_seq_client_id(snd_seq_t * seq)''</font>
+
  <FONT Color=gray>' ''int snd_seq_client_id (snd_seq_t * seq)''
  Private Extern snd_seq_client_id(handle As Pointer) As Integer
+
' ''Get the client id.''</font>
 +
  Private Extern snd_seq_client_id(seq As Pointer) As Integer
 
   
 
   
  <Font Color= #006400>' ''int snd_seq_connect_to(seq as pointer, myport as integer, src_client as integer, src_port as integer)''</font>
+
  <FONT Color=gray>' ''int snd_seq_connect_to ( snd_seq_t * seq, int myport, int dest_client, int dest_port )''
  Private Extern snd_seq_connect_to(seq As Pointer, myport As Integer, src_client As Integer, src_port As Integer) As Integer
+
' ''Connect from the given receiver port in the current client to the given destination client:port.''</font>
 +
  Private Extern snd_seq_connect_to(seq As Pointer, myport As Integer, dest_client As Integer, dest_port As Integer) As Integer
 
   
 
   
  <Font Color= #006400>' ''int snd_seq_alloc_named_queue(snd_seq_t * seq, CONST char * name)''</font>
+
  <FONT Color=gray>' ''int snd_seq_alloc_named_queue (snd_seq_t * seq, CONST char * name)''
 +
' ''Allocate a queue.''</font>
 
  Private Extern snd_seq_alloc_queue(seq As Pointer, name As String) As Integer
 
  Private Extern snd_seq_alloc_queue(seq As Pointer, name As String) As Integer
 
    
 
    
  ' ''int snd_seq_event_output (snd_seq_t *handle, snd_seq_event_t *ev)''</font>
+
  <FONT Color=gray>' ''int snd_seq_event_output (snd_seq_t * seq, snd_seq_event_t *ev)''
  Private Extern snd_seq_event_output(handle As Pointer, ev As Pointer) As Integer
+
  ' ''Output an event.''</font>
 
+
  Private Extern snd_seq_event_output(seq As Pointer, ev As Pointer) As Integer
  <Font Color= #006400>' ''int snd_seq_drain_output (snd_seq_t * handle)''</font>
 
  Private Extern snd_seq_drain_output(handle As Pointer) As Integer
 
 
   
 
   
 +
<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
 
   
 
   
  '''Public''' Sub alsa_open(myname As String)
+
  <FONT Color=gray>' ''const char * snd_strerror (int errnum)''
  Dim err As Integer
+
' ''Returns the message for an error code.''</font>
 +
Private Extern snd_strerror(errnum As Integer) As String
 
   
 
   
  err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)
+
<FONT Color=gray>' ''int snd_seq_close (snd_seq_t * seq)''
  Print "Opening alsa="; err
+
  ' ''Close the sequencer.''</font>
  If err < 0 Then error.RAISE("Error opening alsa")
+
Private Extern snd_seq_close(seq As Pointer) As Integer
 
 
  snd_seq_set_client_name(handle, myname)
 
  id = snd_seq_client_id(handle)
 
  Print "Alsa ClientID="; id
 
 
 
  err = snd_seq_create_simple_port(handle, "Seq-Out", 0, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)
 
  Print "My alsa client port="; err
 
  If err < 0 Then error.Raise("Error creating alsa port")
 
  outport = err
 
 
 
  err = snd_seq_alloc_queue(handle, "outqueue")        <Font Color= #006400>' ''per creare una coda di eventi''</font>
 
  printerr("Creating queue", err)
 
  If err < 0 Then error.Raise("Error creating out queue")
 
  outq = err
 
 
 
<Font Color= #006400>' ''alloca un evento nella zona di memoria riservata per lavorarci.''
 
  ' ''E' globale per evitare allocazioni/deallocazioni onerose.''</font>
 
  ev = Alloc(SIZE_OF_SEQEV)
 
 
 
  p = Memory ev For Write
 
 
   
 
   
'''End'''
 
 
   
 
   
 +
'''Public''' Sub Main()
 
   
 
   
'''Public''' Sub setdevice(client As Integer, port As Integer)
 
 
   Dim err As Integer
 
   Dim err As Integer
 
 
  dclient = client
 
  dport = port
 
  err = snd_seq_connect_to(handle, outport, dclient, dport)
 
  printerr("Subscribe", err)
 
  If err < 0 Then error.Raise("Error subscribe output device")
 
 
'''End'''
 
 
 
<Font Color= #006400>''''---- Parte relativa alla gestione degli errori ----'''</font>
 
 
Private Extern snd_strerror(err As Integer) As Pointer
 
 
'''Public''' Sub errmsg(err As Integer) As String
 
  Return String@(snd_strerror(err))
 
 
   
 
   
'''End'''
+
  err = snd_seq_open(VarPtr(alsa), "default", SND_SEQ_OPEN_DUPLEX, 0)
+
   If err < 0 Then  
+
    snd_strerror(err)
'''Private''' Sub printerr(operation As String, err As Integer)
+
    Error.Raise("Errore !")
+
  Endif
   If err < 0 Then Print operation; ": err ="; err; " ("; errmsg(err); ")"
 
 
'''End'''
 
 
 
<Font Color= #006400>''''---- Parte relativa all’invio degli eventi Midi ----'''
 
 
    
 
    
' '''Note ON'''</font>
+
  snd_seq_set_client_name(alsa, "Test")
'''Public''' Sub noteon(channel As Byte, note As Byte, velocity As Byte)
+
  id = snd_seq_client_id(alsa)
+
   Print "ID del programma Client di ALSA =  "; id
   Dim err As Integer
 
 
    
 
    
prepareev(SND_SEQ_EVENT_NOTEON)
+
  porta = snd_seq_create_simple_port(alsa, "porta_uscita", 0, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)
 +
  If porta < 0 Then
 +
    snd_strerror(porta)
 +
    snd_seq_close(alsa)
 +
    Error.Raise("Errore !")
 +
  Endif
 +
  Print "Porta del programma Client di ALSA = "; porta
 
   
 
   
   Write #p, channel As Byte
+
   que = snd_seq_alloc_queue(alsa, "queue")          <FONT Color=gray>' ''Crea una coda di eventi''</font>
 +
  If que < 0 Then
 +
    snd_strerror(que)
 +
    snd_seq_close(alsa)
 +
    Error.Raise("Errore !")
 +
  Endif
 
   
 
   
   Write #p, note As Byte
+
<FONT Color=gray>' ''Assume che il "Softsynth", altro Client di ALSA, abbia ID=128 e Porta=0:''</font>
 +
   err = snd_seq_connect_to(alsa, porta, ID_SOFTSYNTH, PORTA_SOFTSYNTH)
 +
  If err < 0 Then
 +
  snd_strerror(err)
 +
  snd_seq_close(alsa)
 +
  Error.Raise("Errore !")
 +
Endif
 
   
 
   
   Write #p, velocity As Byte
+
<FONT Color=gray>' ''Alloca un evento nella zona di memoria riservata per lavorarci.''
 +
' ''E' globale per evitare allocazioni/deallocazioni onerose.''</font>
 +
   ev = Alloc(SizeOf(gb.Byte), AREA_DI_MEMORIA)
 
   
 
   
 +
  st = Memory ev For Write
 
   
 
   
  err = snd_seq_event_output(handle, ev)
+
<FONT Color=gray>' '''---- Parte relativa all’invio degli eventi Midi ----'''</font>
  printerr("Noteon = ", err)
 
 
   
 
   
  '''End'''
+
  <FONT Color=gray>'</font> <FONT Color=#006400>'''Program Change'''</font>
 +
  PreparaEvento(SND_SEQ_EVENT_PGMCHANGE)
 +
  Write #st, CANALE As Byte
 +
  Seek #st, 24                              <FONT Color=gray>' ''Sposta il puntatore dello stream sul byte di indice 24''</font>
 +
  Write #st, strum.Find("Flute") As Integer <FONT Color=gray>' ''Imposta il suono dello strumento musicale''</font>
 +
  InvioMessaggio()
 
   
 
   
 +
<FONT Color=gray>'</font> <FONT Color=#006400>'''Control Change'''</font>
 +
  PreparaEvento(SND_SEQ_EVENT_CONTROLLER)
 +
  Write #st, CANALE As Integer
 +
  Write #st, CONTROL_CHANGE As Integer      <FONT Color=gray>' ''Invia un Messaggio relativo al "Volume"''</font>
 +
  Write #st, 100 As Integer                <FONT Color=gray>' ''Imposta il valore del "Volume"''</font>
 +
  InvioMessaggio()
 
   
 
   
  <FONT Color= #006400>' '''Note OFF'''</font>
+
  <FONT Color=gray>'</font> <FONT Color=#006400>'''Note ON'''</font>
'''Public''' Sub noteoff(channel As Byte, note As Byte, velocity As Byte)
+
  PreparaEvento(SND_SEQ_EVENT_NOTEON)
 +
  Write #st, CANALE As Byte
 +
  Write #st, NOTA As Byte
 +
  Write #st, 100 As Byte
 +
  InvioMessaggio()
 
   
 
   
  Dim err As Integer
+
<FONT Color=gray>' ''Imposta una durata di esecuzione del Messaggio "Note-ON":''</font>
    
+
   Wait 3
prepareev(SND_SEQ_EVENT_NOTEOFF)
 
 
   
 
   
   Write #p, channel As Byte
+
<FONT Color=gray>'</font> <FONT Color=#006400>'''Note OFF'''</font>
 +
  PreparaEvento(SND_SEQ_EVENT_NOTEOFF)
 +
  Write #st, CANALE As Byte
 +
   Write #st, NOTA As Byte
 +
  Write #st, 0 As Byte
 +
  InvioMessaggio()
 
   
 
   
   Write #p, note As Byte
+
   st.Close
+
   Free(ev)
  Write #p, velocity As Byte
+
   snd_seq_close(alsa)
 
 
   err = snd_seq_event_output(handle, ev)
 
   printerr("NoteOFF = ", err)
 
 
   
 
   
 
  '''End'''
 
  '''End'''
 
   
 
   
 +
<FONT Color=gray>' '''- - - > Scrittura dei dati generali per tutti i messaggi Midi < - - -'''</font>
 
   
 
   
  <FONT Color= #006400>' '''Polyphonic Aftertouch (Key Pressure)'''</font>
+
  '''Private''' Procedure PreparaEvento(type As Byte)
  '''Public''' Sub polypho(channel As Byte, note As Byte, velocity As Byte)
 
 
 
  Dim err As Integer
 
 
   
 
   
<FONT Color= #006400>' ''Chiama la subroutine prepareev''</font>
+
   Dim b As Byte
  prepareev(SND_SEQ_EVENT_KEYPRESS)
 
    
 
  Write #p, channel As Byte
 
 
   
 
   
  Write #p, note As Byte
+
<FONT Color=gray>' ''Ripulisce opportunamente l'area di memoria riservata per la definizione dell’evento Midi ALSA:''</font>
 +
  Seek #st, 0
 +
  For b = 1 To AREA_DI_MEMORIA
 +
    Write #st, 0 As Byte
 +
  Next
 
   
 
   
  Write #p, poly As Byte
+
  <FONT Color=gray>' ''Imposta i valori generali uguali per ciascun Evento Midi inviato ad ALSA:''</font>
+
   Seek #st, 0
+
   Write #st, type As Byte
  err = snd_seq_event_output(handle, ev)        <FONT Color= #006400>' ''output an event</font>
 
  printerr("Polyphonic = ", err)
 
 
'''End'''
 
 
   
 
  <FONT Color= #006400>' '''Control Change'''</font>
 
   '''Public''' Sub controller(channel As integer, ctrl As integer, valCtr as integer)
 
 
  Dim err As Integer
 
 
 
  <FONT Color= #006400>' ''Chiama la subroutine prepareev''</font>
 
  prepareev(SND_SEQ_EVENT_CONTROLLER)
 
    
 
    Write #p, channel As Integer
 
 
    Write #p, ctrl As Integer
 
 
    Write #p, valCtr As Integer
 
 
  err = snd_seq_event_output(handle, ev)        <FONT Color= #006400>' ''output an event</font>
 
  printerr("Controller = ", err)
 
 
'''End'''
 
 
   
 
   
 +
<FONT Color=gray>' Write #st, flags As Byte
 +
' Write #st, tag As Byte</font>
 
   
 
   
 +
<FONT Color=gray>' '''queue'''</font>
 +
  Seek #st, 3
 +
  Write #st, que As Byte
 
   
 
   
  <FONT Color= #006400>' '''Program Change'''</font>
+
  <FONT Color=gray>' Write #st, ts As Integer   (''timestamp'')
'''Public''' Sub pgmchange(channel As Byte, strum As Integer)
+
' Write #st, ts As Integer   (''realtime event'')
 
 
  Dim err As Integer
 
 
 
  <FONT Color= #006400>' ''Chiama la subroutine prepareev''</font>
 
  prepareev(SND_SEQ_EVENT_PGMCHANGE)
 
 
 
  Write #p, channel As Byte
 
   Seek #p, 24                            <FONT Color= #006400>' ''Spostiamo il puntatore dello stream sul byte num. 24''</font>
 
  Write #p, strum As Integer
 
 
   
 
   
  err = snd_seq_event_output(handle, ev)        <FONT Color= #006400>' ''output an event</font>
+
' '''source'''</font>
  printerr("Pgmchange = ", err)
+
  Seek #st, 12
    
+
   Write #st, id As Byte
'''End'''
+
  Write #st, porta As Byte
 
   
 
   
+
  <FONT Color=gray>' '''dest'''</font>
  <FONT Color= #006400>' '''Channel Aftertouch (Channel Pressure)'''</font>  
+
   Write #st, ID_SOFTSYNTH As Byte     <FONT Color=gray>' ''ID del Client destinatario (il SoftSynth) (oppure: SND_SEQ_ADDRESS_SUBSCRIBERS)''</font>
   '''Public''' Sub chanpress(channel As Byte, press As Integer)
+
   Write #st, PORTA_SOFTSYNTH As Byte <FONT Color=gray>' ''Porta del Client destinatario (oppure: SND_SEQ_ADDRESS_UNKNOWN)''</font>
 
  Dim err As Integer
 
 
 
<FONT Color= #006400>' ''Chiama la subroutine prepareev''</font>
 
  prepareev(SND_SEQ_EVENT_CHANPRESS)
 
    
 
  Write #p, channel As Byte
 
  Seek #p, 24                            <FONT Color= #006400>' ''Spostiamo il puntatore dello stream sul byte num. 24''</font>
 
  Write #p, press As Integer
 
 
 
  err = snd_seq_event_output(handle, ev)       <FONT Color= #006400>' ''output an event</font>
 
  printerr("ChanPress = ", err)
 
 
   
 
   
 
  '''End'''
 
  '''End'''
 
   
 
   
   
+
  '''Private''' Procedure InvioMessaggio()
<FONT Color= #006400>' '''Pitch Bend (Pitch Wheel)'''</font> 
 
  '''Public''' Sub pitchbend(channel As Integer, valorePB1 As Integer, gross As Integer)
 
 
   
 
   
 
   Dim err As Integer
 
   Dim err As Integer
 
    
 
    
  <FONT Color= #006400>' ''Chiama la subroutine prepareev''</font>
+
<FONT Color=gray>' ''Inserisce l'Evento di ALSA nel buffer:''</font>
  prepareev(SND_SEQ_EVENT_PITCHBEND)
+
  err = snd_seq_event_output(alsa, ev)
 
+
  If err < 0 Then
  Write #p, channel As Integer
+
    snd_seq_close(alsa)
 
+
    Error.Raise("Errore: " & snd_strerror(err))
  Write #p, valorePB1 As Integer          <FONT Color= #006400>' ''questo valore resta a 0''</font>
+
  Endif
 
 
  Write #p, gross As Integer
 
 
 
  err = snd_seq_event_output(handle, ev)   <FONT Color= #006400>' ''output an event''</font>
 
  printerr("PitchBend = ", err)
 
 
 
'''End'''
 
 
   
 
   
+
  <FONT Color=gray>' ''Invia l'Evento Midi di ALSA:''</font>
  <Font Color= #006400>'' ---> Scrittura dei dati generali per tutti i messaggi Midi <--- ''</font>
+
   err = snd_seq_drain_output(alsa)
+
   If err < 0 Then
'''Private''' Sub prepareev(type As Byte)
+
    snd_seq_close(alsa)
+
    Error.Raise("Errore: " & snd_strerror(err))
  Dim i As Integer
+
   Endif
  Dim flags, tag As Byte
 
 
 
<Font Color= #006400>' ''ripulisce la zona di memoria riservata per la definizione dell’evento''</font>
 
  Seek #p, 0
 
  For i = 1 To SIZE_OF_SEQEV
 
    Write #p, 0 As Byte
 
  Next
 
 
  Seek #p, 0
 
  Write #p, type As Byte
 
    
 
<Font Color= #006400>' Write #p, flags As Byte
 
    
 
' Write #p, tag As Byte</font>
 
 
  Seek #p, 3
 
  Write #p, outq As Byte
 
 
<Font Color= #006400>' Write #p, ts As Integer  ' ''timestamp''
 
 
 
' Write #p, ts As Integer  ' ''2^ parte (realtime event)''</font>
 
 
  Seek #p, 12
 
<Font Color= #006400>' ''source''</font>
 
  Write #p, id As Byte
 
 
 
  Write #p, outport As Byte
 
 
 
<Font Color= #006400>' ''dest''</font>
 
  Write #p, SND_SEQ_ADDRESS_SUBSCRIBERS As Byte  <Font Color= #006400>' ''254/dclient''</font>
 
 
 
   Write #p, SND_SEQ_ADDRESS_UNKNOWN As Byte  <Font Color= #006400>' ''253/dport''</font>
 
 
   
 
   
 
  '''End'''
 
  '''End'''
 
 
<Font Color= #006400>' ''Svuota il buffer in ALSA''</font>
 
 
 
'''Public''' Sub flush()
 
  Dim err As Integer
 
 
  err = snd_seq_drain_output(handle)    <Font Color= #006400>' ''drain output buffer to sequencer''</font>
 
  Printerr("Flush", err)
 
 
'''End'''
 
 
 
   
 
   
 
  <Font Color= #006400>' ENUM snd_seq_event_type {
 
  <Font Color= #006400>' ENUM snd_seq_event_type {

Versione delle 11:03, 17 gen 2022

Una modalità per creare ed inviare eventi Midi ad Alsa è quella mediante l'allocazione di memoria puntata da una variabile di tipo Puntatore.


Riservare innanzitutto memoria per il puntatore

Utilizzeremo quindi la funzione "Alloc()" per riservare una porzione di memoria e porla a disposizione del pointer, che chiameremo: "ev". Più precisamente con "Alloc()" si prende una parte di memoria dal sistema e la si assegna al programma. A questo punto è possibile operare con il pointer, a patto che si vada a scrivere esclusivamente dentro quella porzione di memoria che è stata appositamente riservata per il Puntatore [nota 1]

Assegneremo un'adeguata porzione pari a 28 byte:

ev = Alloc(SizeOf(gb.Byte), 28)


Uso dei Memory Stream per scrivere nell'area di memoria allocata

Per scrivere i valori arbitrari dentro la predetta area di memoria, necessari alla definizione dell'evento Midi, useremo i Memory Stream mediante l'istruzione Memory. In questo modo, dopo aver allocato la quantità di memoria adeguata per i dati necessari all'Evento Midi di ALSA (28 byte), agganceremo l'istruzione Memory a detta zona di memoria attraverso una variabile di tipo Stream. Il flusso di memoria di 28 byte sarà aperto in Scrittura e gestito similmente a un file.

Private st As Stream
......
st = Memory Puntatore For Write

Viene così creato lo stream di memoria, e il suo puntatore interno, implicito, è posto automaticamente all'inizio dello stream medesimo (offset 0). Esso all'atto della scrittura:

WRITE #stream, espressione As Tipo_di_Dati

automaticamente viene incrementato di una quantità di byte pari a quella occupata dal tipo di dati scritto. [nota 2]


La struttura degli eventi Midi trascritta in Gambas con i Memory Stream

Inseriamo dunque nel nostro codice la suddetta area di memoria allocata all'interno di una sub-routine generale per la preparazione degli Eventi Midi di ALSA, la quale sarà richiamata da ciascun Evento Midi.

Inseriremo fra le dichiarazioni iniziali due costanti relative agli indirizzi del sorgente e della destinazione degli eventi, che nella documentazione di ALSA sono così descritte:

  • #define SND_SEQ_ADDRESS_SUBSCRIBERS 254
    send event to all subscribed ports
  • #define SND_SEQ_ADDRESS_UNKNOWN 253
    special client (port) ids unknown source
Const SND_SEQ_ADDRESS_UNKNOWN As Byte = 253
Const SND_SEQ_ADDRESS_SUBSCRIBERS As Byte = 254

Ricordiamo che il nostro scopo iniziale era di creare un semplice applicativo capace di inviare unici eventi Midi. Pertanto, escluderemo i campi relativi al Timestamp e più in generale al Tempo (Time), ossia i campi denominati: flags, tag e time (li riportiamo comunque scritti per opportuna memoria):

Private Sub PreparaEvento(type As Byte)   ' Inseriamo solo il valore del campo Type,
                                          ' perché in questo nostro caso è l'unico che ci serve !
  Dim i As Integer
' Dim flags, tag As Byte
 
' Pulisce opportunamente l'area di memoria allocata, partendo dal 1° byte, ossia dall'indice 0:
  Seek #st, 0
  For i = 1 To SIZE_OF_SEQEV
    Write #st, 0 As Byte
  Next

' ==== Inizio area dell'Evento Midi secondo il protocollo ALSA ====

' Type
  Seek #st, 0
  Write #st, type As Byte

' Flags
' Write #st, flags As Byte

' Tag
' Write #st, tag As Byte

 ' Non scrivento nei byte di memoria precedenti, il puntatore implicito dello stream non avanza, ovviamente.
 ' Pertanto, bisogna porre il puntatore sul byte della zona di memoria opportuno, cioè quello richiesto da ALSA.
 Seek #st, 3
' Queue
  Write #st, outq As Byte

' Time 
' Write #st, ts As Integer        ' timestamp
' Write #st, ts As Integer        ' 2^ parte (realtime event)

 Seek #st, 12                     ' Sposta il puntatore dello stream al byte di indice 12 (ossia al 13°)
' Source
  Write #st, id As Byte
 
  Write #st, outport As Byte

' Dest
  Write #st, SND_SEQ_ADDRESS_SUBSCRIBERS As Byte   ' 254/dclient

  Write #st, SND_SEQ_ADDRESS_UNKNOWN As Byte       ' 253/dport

End


Codice Esemplificativo

Mostriamo di seguito un codice esemplificativo, che fa uso appunto di un'area di memoria riservata per disporre adeguatamente i dati necessari a creare un Evento Midi da inviare ad ALSA.

Private Const ID_SOFTSYNTH As Byte = 128
Private Const PORTA_SOFTSYNTH As Byte = 0
Private Const CANALE As Byte = 0
Private Const CONTROL_CHANGE As Integer = 7
Private Const VOLUME As Byte = 100
Private Const NOTA As Byte = 64
Private Const AREA_DI_MEMORIA As Byte = 28
Private strum 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"]

Private alsa As Pointer
Private id As Byte
Private que As Byte
Private porta As Integer
Private ev As Pointer
Private st As Stream

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  '  (1<<20)
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 Pointer) 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 err As Integer

 err = snd_seq_open(VarPtr(alsa), "default", SND_SEQ_OPEN_DUPLEX, 0)
 If err < 0 Then 
   snd_strerror(err)
   Error.Raise("Errore !")
 Endif
 
 snd_seq_set_client_name(alsa, "Test")
 id = snd_seq_client_id(alsa)
 Print "ID del programma Client di ALSA =  "; id
 
 porta = snd_seq_create_simple_port(alsa, "porta_uscita", 0, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)
 If porta < 0 Then 
   snd_strerror(porta)
   snd_seq_close(alsa)
   Error.Raise("Errore !")
 Endif
 Print "Porta del programma Client di ALSA = "; porta

 que = snd_seq_alloc_queue(alsa, "queue")          ' Crea una coda di eventi
 If que < 0 Then 
   snd_strerror(que)
   snd_seq_close(alsa)
   Error.Raise("Errore !")
 Endif

' Assume che il "Softsynth", altro Client di ALSA, abbia ID=128 e Porta=0:
 err = snd_seq_connect_to(alsa, porta, ID_SOFTSYNTH, PORTA_SOFTSYNTH)
 If err < 0 Then 
  snd_strerror(err)
  snd_seq_close(alsa)
  Error.Raise("Errore !")
Endif

' Alloca un evento nella zona di memoria riservata per lavorarci.
' E' globale per evitare allocazioni/deallocazioni onerose.
 ev = Alloc(SizeOf(gb.Byte), AREA_DI_MEMORIA)

 st = Memory ev For Write

' ---- Parte relativa all’invio degli eventi Midi ----

' Program Change
 PreparaEvento(SND_SEQ_EVENT_PGMCHANGE)
 Write #st, CANALE As Byte
 Seek #st, 24                              ' Sposta il puntatore dello stream sul byte di indice 24
 Write #st, strum.Find("Flute") As Integer ' Imposta il suono dello strumento musicale
 InvioMessaggio()

' Control Change
 PreparaEvento(SND_SEQ_EVENT_CONTROLLER)
 Write #st, CANALE As Integer
 Write #st, CONTROL_CHANGE As Integer      ' Invia un Messaggio relativo al "Volume"
 Write #st, 100 As Integer                 ' Imposta il valore del "Volume"
 InvioMessaggio()

' Note ON
 PreparaEvento(SND_SEQ_EVENT_NOTEON)
 Write #st, CANALE As Byte
 Write #st, NOTA As Byte
 Write #st, 100 As Byte
 InvioMessaggio()

' Imposta una durata di esecuzione del Messaggio "Note-ON":
 Wait 3

' Note OFF
 PreparaEvento(SND_SEQ_EVENT_NOTEOFF)
 Write #st, CANALE As Byte
 Write #st, NOTA As Byte
 Write #st, 0 As Byte
 InvioMessaggio()

 st.Close
 Free(ev)
 snd_seq_close(alsa)

End

' - - - > Scrittura dei dati generali per tutti i messaggi Midi < - - -

Private Procedure PreparaEvento(type As Byte)

 Dim b As Byte

' Ripulisce opportunamente l'area di memoria riservata per la definizione dell’evento Midi ALSA:
 Seek #st, 0
 For b = 1 To AREA_DI_MEMORIA
   Write #st, 0 As Byte
 Next

' Imposta i valori generali uguali per ciascun Evento Midi inviato ad ALSA:
 Seek #st, 0
 Write #st, type As Byte

' Write #st, flags As Byte
' Write #st, tag As Byte

' queue
 Seek #st, 3
 Write #st, que As Byte

' Write #st, ts As Integer    (timestamp)
' Write #st, ts As Integer    (realtime event)

' source
 Seek #st, 12
 Write #st, id As Byte
 Write #st, porta As Byte

' dest
 Write #st, ID_SOFTSYNTH As Byte     ' ID del Client destinatario (il SoftSynth) (oppure: SND_SEQ_ADDRESS_SUBSCRIBERS)
 Write #st, PORTA_SOFTSYNTH As Byte  ' Porta del Client destinatario (oppure: SND_SEQ_ADDRESS_UNKNOWN)

End

Private Procedure InvioMessaggio()

 Dim err As Integer
 
' Inserisce l'Evento di ALSA nel buffer:
 err = snd_seq_event_output(alsa, ev)
 If err < 0 Then 
   snd_seq_close(alsa)
   Error.Raise("Errore: " & snd_strerror(err))
 Endif

' Invia l'Evento Midi di ALSA:
 err = snd_seq_drain_output(alsa)
 If err < 0 Then 
   snd_seq_close(alsa)
   Error.Raise("Errore: " & snd_strerror(err))
 Endif

End

' ENUM snd_seq_event_type {
'    SND_SEQ_EVENT_SYSTEM = 0, SND_SEQ_EVENT_RESULT, SND_SEQ_EVENT_NOTE = 5, SND_SEQ_EVENT_NOTEON = 6, 
'    SND_SEQ_EVENT_NOTEOFF = 7, SND_SEQ_EVENT_KEYPRESS = 8, SND_SEQ_EVENT_CONTROLLER = 10, SND_SEQ_EVENT_PGMCHANGE = 11, 
'    SND_SEQ_EVENT_CHANPRESS = 12, SND_SEQ_EVENT_PITCHBEND = 13, SND_SEQ_EVENT_CONTROL14, SND_SEQ_EVENT_NONREGPARAM, 
'    SND_SEQ_EVENT_REGPARAM, SND_SEQ_EVENT_SONGPOS = 20, SND_SEQ_EVENT_SONGSEL, SND_SEQ_EVENT_QFRAME, 
'    SND_SEQ_EVENT_TIMESIGN, SND_SEQ_EVENT_KEYSIGN, SND_SEQ_EVENT_START = 30, SND_SEQ_EVENT_CONTINUE, 
'    SND_SEQ_EVENT_STOP, SND_SEQ_EVENT_SETPOS_TICK, SND_SEQ_EVENT_SETPOS_TIME, SND_SEQ_EVENT_TEMPO, 
'    SND_SEQ_EVENT_CLOCK, SND_SEQ_EVENT_TICK, SND_SEQ_EVENT_QUEUE_SKEW, SND_SEQ_EVENT_SYNC_POS, 
'    SND_SEQ_EVENT_TUNE_REQUEST = 40, SND_SEQ_EVENT_RESET, SND_SEQ_EVENT_SENSING, SND_SEQ_EVENT_ECHO = 50, 
'    SND_SEQ_EVENT_OSS, SND_SEQ_EVENT_CLIENT_START = 60, SND_SEQ_EVENT_CLIENT_EXIT, SND_SEQ_EVENT_CLIENT_CHANGE, 
'    SND_SEQ_EVENT_PORT_START, SND_SEQ_EVENT_PORT_EXIT, SND_SEQ_EVENT_PORT_CHANGE, SND_SEQ_EVENT_PORT_SUBSCRIBED, 
'    SND_SEQ_EVENT_PORT_UNSUBSCRIBED, SND_SEQ_EVENT_USR0 = 90, SND_SEQ_EVENT_USR1, SND_SEQ_EVENT_USR2, 
'    SND_SEQ_EVENT_USR3, SND_SEQ_EVENT_USR4, SND_SEQ_EVENT_USR5, SND_SEQ_EVENT_USR6, 
'    SND_SEQ_EVENT_USR7, SND_SEQ_EVENT_USR8, SND_SEQ_EVENT_USR9, SND_SEQ_EVENT_SYSEX = 130, 
'    SND_SEQ_EVENT_BOUNCE, SND_SEQ_EVENT_USR_VAR0 = 135, SND_SEQ_EVENT_USR_VAR1, SND_SEQ_EVENT_USR_VAR2, 
'    SND_SEQ_EVENT_USR_VAR3, SND_SEQ_EVENT_USR_VAR4, SND_SEQ_EVENT_NONE = 255 
'  }


Note

[1] Quando è dichiarato un Pointer, Gambas riserva 8 byte tutti per lui (in un sistema a 64 bit), che rappresentano l'indirizzo di memoria contenuto dal Pointer. Quando viene poi manipolato, vengono toccati quegli otto byte. Ma l'unica operazione utile da compiere su un Pointer è la dereferenziazione, che si riferisce ad un'altra area di memoria, alla quale si accede attraverso quell'indirizzo di memoria individuato - come abbiamo detto - dai predetti 8 byte.

Il Pointer risulta così legato a due aree distinte di memoria operative:
- una dove sono scritti otto byte dell'indirizzo di memoria (cioè l'altra) contenente i byte del valore solitamente contenuto da una variabile;
- l'altra ove, come appena detto, sono realmente stipati i byte costituenti il valore contenuto da una variabile.

[2] Qualora volessimo spostare il puntatore interno dello stream ad uno specifico byte, dovremo utilizzare la funzione Seek, la quale esegue - come è noto - uno spiazzamento assoluto puntando dritto al byte di numero definito nella funzione medesima.