Differenze tra le versioni di "Alsa e Gambas: Invio dati con l'uso di un'area di memoria allocata"
(Creata pagina con "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 memo...") |
|||
Riga 1: | Riga 1: | ||
− | Una modalità per creare ed inviare eventi Midi ad Alsa è quella mediante l'allocazione di memoria puntata da una variabile di tipo | + | 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== | ==Riservare innanzitutto memoria per il puntatore== | ||
− | Utilizzeremo quindi la funzione | + | 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 <SUP>[[[#Note|nota 1]]]</sup> |
− | Assegneremo un' | + | Assegneremo un'adeguata porzione pari a 28 byte: |
− | + | ev = Alloc(SizeOf(gb.Byte), 28) | |
− | |||
− | ev = Alloc( | ||
==Uso dei Memory Stream per scrivere nell'area di memoria allocata== | ==Uso dei Memory Stream per scrivere nell'area di memoria allocata== | ||
− | Per scrivere i valori arbitrari dentro la predetta | + | Per scrivere i valori arbitrari dentro la predetta area di memoria, necessari alla definizione dell'evento Midi, useremo i ''[[Definizione_ed_uso_dei_Memory_Stream|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 | Private st As Stream | ||
...... | ...... | ||
− | + | st = Memory Puntatore For Write | |
− | Viene così creato lo ''stream'', | + | 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 [https://gambaswiki.org/wiki/cat/datatypes?l=it tipo di dati] scritto. <SUP>[[[#Note|nota 2]]]</sup> | |
− | WRITE #''stream'', ''espressione'' As '' | ||
− | automaticamente viene incrementato di | ||
===La struttura degli eventi Midi trascritta in Gambas con i ''Memory Stream''=== | ===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: | 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: | ||
Riga 35: | Riga 31: | ||
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): | 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) <Font Color= #006400>' ''Inseriamo solo il valore del campo ''Type'','' | |
− | + | ' ''perché ''in questo nostro caso'' è l'unico che ci serve !''</font> | |
− | + | Dim i As Integer | |
− | |||
<Font Color= #006400>' Dim flags, tag As Byte | <Font Color= #006400>' Dim flags, tag As Byte | ||
− | + | ' ''Pulisce opportunamente l'area di memoria allocata, partendo dal 1° byte, ossia dall'indice 0:''</font> | |
− | + | Seek #st, 0 | |
− | + | For i = 1 To SIZE_OF_SEQEV | |
Write #st, 0 As Byte | Write #st, 0 As Byte | ||
− | + | Next | |
− | + | <Font Color= #006400>' ''==== Inizio area dell'Evento Midi secondo il protocollo ALSA ===='' | |
'</font> <Font Color= "blue">'''Type'''</font> | '</font> <Font Color= "blue">'''Type'''</font> | ||
Riga 59: | Riga 54: | ||
<Font Color= #006400>' Write #st, tag As Byte</font> | <Font Color= #006400>' Write #st, tag As Byte</font> | ||
− | <Font Color= #006400>' '' | + | <Font Color= #006400>' ''Non scrivento nei byte di memoria precedenti, il puntatore implicito dello stream non avanza, ovviamente.'' |
− | ' ''Pertanto, | + | ' ''Pertanto, bisogna porre il puntatore sul byte della zona di memoria opportuno, cioè quello richiesto da ALSA.''</font> |
Seek #st, 3 | Seek #st, 3 | ||
<Font Color= #006400>'</font> <Font Color= "blue">'''Queue'''</font> | <Font Color= #006400>'</font> <Font Color= "blue">'''Queue'''</font> | ||
Riga 69: | Riga 64: | ||
' Write #st, ts As Integer ' ''2^ parte (realtime event)''</font> | ' Write #st, ts As Integer ' ''2^ parte (realtime event)''</font> | ||
− | Seek #st, 12 <Font Color= #006400>' '' | + | Seek #st, 12 <Font Color= #006400>' ''Sposta il puntatore dello stream al byte di indice 12 (ossia al 13°)'' |
'</font> <Font Color= "blue">'''Source'''</font> | '</font> <Font Color= "blue">'''Source'''</font> | ||
Write #st, id As Byte | Write #st, id As Byte | ||
Riga 81: | Riga 76: | ||
'''End''' | '''End''' | ||
− | |||
Versione delle 08:00, 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.
Indice
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
Il codice completo
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:
CLASSE: FMain.class
Public alsa as CAlsa ' classe che incapsula le funzioni ALSA Public gross As Integer ' dovrebbe ricevere il valore da uno Slider Public Sub Form_Open() ' Crea ("istanzia") la classe per poterla usare alsa = NEW CAlsa as "alsa" ' Apre alsa e gli assegna un nome alsa.alsa_open("Progetto sequencer in Gambas-3") ' La stringa fra virgolette sarà il nome del nostro Client ' Sceglie la periferica su cui suonare. ' Ident.vo numerico e num. porta di altro dispositivo/client (ad esempio: QSynth), al quale il client si connetterà. alsa.setdevice(128, 0) End Public Sub noteOn_Click() ' Note ON ' chiama la subroutine "noteon" nella classe secondaria CAlsa.class; ' poniamo come esempio la nota da suonare num. 60 (il DO centrale) e velocità 100. alsa.noteon(0, 60, 100) alsa.flush() End Public Sub noteOff_Click() ' Note OFF ' 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. alsa.noteoff(0, 60, 0) alsa.flush() End Public Sub polypho_Click() ' Polyphonic Aftertouch (Key pressure) ' chiama la subroutine, che chiameremo "polypho", nella classe secondaria CAlsa.class; ' poniamo come esempio alla nota 50 un valore di pressione aggiuntiva di 110. alsa.polypho(0, 60, 110) alsa.flush() End Public Sub controller_Click() ' Control Change ' chiama la subroutine, che chiameremo "controller", nella classe secondaria CAlsa.class; ' poniamo come esempio il tipo di controller num. 7 (Volume). Il terzo valore sarà posto a 100. alsa.controller(0, 7, 100) alsa.flush() End Public Sub pgmchange_Click() ' Program Change ' chiama la subroutine, che chiameremo "pgmchange", nella classe secondaria CAlsa.class;</font> ' poniamo come esempio lo strumento musicale num. 71 (Fagotto). alsa.pgmchange(0, 71) alsa.flush() End Public Sub chanpress_Click() ' Channel Aftertouch (Channel Pressure) ' chiama la subroutine, che chiameremo "chanpress", nella classe secondaria CAlsa.class; ' poniamo come esempio un valore di pressione aggiuntiva di 110. alsa.chanpress(0, 110) alsa.flush() End Public Sub SliderPB_Change() ' Pitch Bend (Pitch Wheel) gross = SliderPB.Value ' chiama la subroutine, che chiameremo "pitchbend", nella classe secondaria CAlsa.class; 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 ev As Pointer Private p 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 ' (1<<20) 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" '---- Parte relativa alla creazione del Client e delle sue porte ---- ' 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 ' 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 ' 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 ' int snd_seq_client_id(snd_seq_t * seq) Private Extern snd_seq_client_id(handle As Pointer) As Integer ' int snd_seq_connect_to(seq as pointer, myport as integer, src_client as integer, src_port as integer) Private Extern snd_seq_connect_to(seq As Pointer, myport As Integer, src_client As Integer, src_port As Integer) As Integer ' int snd_seq_alloc_named_queue(snd_seq_t * seq, CONST char * name) 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> Private Extern snd_seq_event_output(handle As Pointer, ev As Pointer) As Integer ' int snd_seq_drain_output (snd_seq_t * handle) Private Extern snd_seq_drain_output(handle As Pointer) As Integer Public Sub alsa_open(myname As String) Dim err As Integer err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0) Print "Opening alsa="; err If err < 0 Then error.RAISE("Error opening alsa") 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") ' per creare una coda di eventi printerr("Creating queue", err) If err < 0 Then error.Raise("Error creating out queue") outq = err ' alloca un evento nella zona di memoria riservata per lavorarci. ' E' globale per evitare allocazioni/deallocazioni onerose. ev = Alloc(SIZE_OF_SEQEV) p = Memory ev For Write End Public Sub setdevice(client As Integer, port 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 '---- Parte relativa alla gestione degli errori ---- Private Extern snd_strerror(err As Integer) As Pointer Public Sub errmsg(err As Integer) As String Return String@(snd_strerror(err)) End Private Sub printerr(operation As String, err As Integer) If err < 0 Then Print operation; ": err ="; err; " ("; errmsg(err); ")" End '---- Parte relativa all’invio degli eventi Midi ---- ' Note ON Public Sub noteon(channel As Byte, note As Byte, velocity As Byte) Dim err As Integer prepareev(SND_SEQ_EVENT_NOTEON) Write #p, channel As Byte Write #p, note As Byte Write #p, velocity As Byte err = snd_seq_event_output(handle, ev) printerr("Noteon = ", err) End ' Note OFF Public Sub noteoff(channel As Byte, note As Byte, velocity As Byte) Dim err As Integer prepareev(SND_SEQ_EVENT_NOTEOFF) Write #p, channel As Byte Write #p, note As Byte Write #p, velocity As Byte err = snd_seq_event_output(handle, ev) printerr("NoteOFF = ", err) End ' Polyphonic Aftertouch (Key Pressure) Public Sub polypho(channel As Byte, note As Byte, velocity As Byte) Dim err As Integer ' Chiama la subroutine prepareev prepareev(SND_SEQ_EVENT_KEYPRESS) Write #p, channel As Byte Write #p, note As Byte Write #p, poly As Byte err = snd_seq_event_output(handle, ev) ' output an event printerr("Polyphonic = ", err) End ' Control Change Public Sub controller(channel As integer, ctrl As integer, valCtr as integer) Dim err As Integer ' Chiama la subroutine prepareev 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) ' output an event printerr("Controller = ", err) End ' Program Change Public Sub pgmchange(channel As Byte, strum As Integer) Dim err As Integer ' Chiama la subroutine prepareev prepareev(SND_SEQ_EVENT_PGMCHANGE) Write #p, channel As Byte Seek #p, 24 ' Spostiamo il puntatore dello stream sul byte num. 24 Write #p, strum As Integer err = snd_seq_event_output(handle, ev) ' output an event printerr("Pgmchange = ", err) End ' Channel Aftertouch (Channel Pressure) Public Sub chanpress(channel As Byte, press As Integer) Dim err As Integer ' Chiama la subroutine prepareev prepareev(SND_SEQ_EVENT_CHANPRESS) Write #p, channel As Byte Seek #p, 24 ' Spostiamo il puntatore dello stream sul byte num. 24 Write #p, press As Integer err = snd_seq_event_output(handle, ev) ' output an event printerr("ChanPress = ", err) End ' Pitch Bend (Pitch Wheel) Public Sub pitchbend(channel As Integer, valorePB1 As Integer, gross As Integer) Dim err As Integer ' Chiama la subroutine prepareev prepareev(SND_SEQ_EVENT_PITCHBEND) Write #p, channel As Integer Write #p, valorePB1 As Integer ' questo valore resta a 0 Write #p, gross As Integer err = snd_seq_event_output(handle, ev) ' output an event printerr("PitchBend = ", err) End ---> Scrittura dei dati generali per tutti i messaggi Midi <--- Private Sub prepareev(type As Byte) Dim i As Integer Dim flags, tag As Byte ' ripulisce la zona di memoria riservata per la definizione dell’evento Seek #p, 0 For i = 1 To SIZE_OF_SEQEV Write #p, 0 As Byte Next Seek #p, 0 Write #p, type As Byte ' Write #p, flags As Byte ' Write #p, tag As Byte Seek #p, 3 Write #p, outq As Byte ' Write #p, ts As Integer ' timestamp ' Write #p, ts As Integer ' 2^ parte (realtime event) Seek #p, 12 ' source Write #p, id As Byte Write #p, outport As Byte ' dest Write #p, SND_SEQ_ADDRESS_SUBSCRIBERS As Byte ' 254/dclient Write #p, SND_SEQ_ADDRESS_UNKNOWN As Byte ' 253/dport End ' Svuota il buffer in ALSA Public Sub flush() Dim err As Integer err = snd_seq_drain_output(handle) ' drain output buffer to sequencer Printerr("Flush", err) 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.