Differenze tra le versioni di "ALSA e Gambas - La marcatura temporale degli eventi: il Timestamp"

Da Gambas-it.org - Wikipedia.
(Creata pagina con "===Preambolo=== Nelle due sezioni precedenti abbiamo studiato le fondamenta della gestione del Midi con Gambas in ambiente ALSA: l'''Invio'' e la ''Ricezione'' dei messaggi Mi...")
 
Riga 25: Riga 25:
  
 
<P>I valori da assegnare al Timestamp sono definiti dal campo ''Time''. Riguardo alla sua dimensione la documentazione presente in ''seq_event.h'' dice che:</p>
 
<P>I valori da assegnare al Timestamp sono definiti dal campo ''Time''. Riguardo alla sua dimensione la documentazione presente in ''seq_event.h'' dice che:</p>
 
+
  typedef struct <FONT Color=#B22222>snd_seq_real_time</font> {
  typedef struct snd_seq_real_time {
 
 
               unsigned int tv_sec;             
 
               unsigned int tv_sec;             
 
               unsigned int tv_nsec;           
 
               unsigned int tv_nsec;           
       } snd_seq_real_time_t;
+
       } <FONT Color=#B22222>snd_seq_real_time_t</font>;
 
   
 
   
 
       typedef unsigned int snd_seq_tick_time_t;
 
       typedef unsigned int snd_seq_tick_time_t;
 
   
 
   
   typedef '''union''' snd_seq_timestamp {
+
   typedef '''union''' <FONT Color=blue>snd_seq_timestamp {
               snd_seq_tick_time_t tick;       
+
               snd_seq_tick_time_t tick</font>;       
               struct snd_seq_real_time time;   
+
               struct <FONT Color=#B22222>snd_seq_real_time time</font>;   
 
       } snd_seq_timestamp_t;
 
       } snd_seq_timestamp_t;
 
 
Come possiamo vedere, ''snd_seq_timestamp'' è una ''union'' (unione). <SUP>&#091;[[#Note|nota 3]]&#093;</sup>
 
Come possiamo vedere, ''snd_seq_timestamp'' è una ''union'' (unione). <SUP>&#091;[[#Note|nota 3]]&#093;</sup>
 
Ora, poiché il più lungo dei suoi elementi è "real_time", composto da due ''unsigned int'', ossia da "due" integer, se ne deduce che la lunghezza di tale ''unione'', e quindi dell'intero campo ''Time'' è pari a '''2''' integer. La ''union'' "''snd_seq_timestamp''" può contenere, in alternativa, un "tick_time" (che è 1 integer) oppure un "real_time", che a sua volta è composto da 2 integer. Per un determinato evento i due dati sono sovrapposti e non possono essere validi entrambi contemporaneamente. Infatti, un bit nel campo ''flags'' indica quale dei due casi si sta trattando. Se il flag "real time" non è impostato, risulta valido solo il campo "tick_time", e l'altro campo va ignorato. Se invece è impostato il flag "real time", allora entrambi i campi (entrambi gli integer) della ''union'' sono significativi: il primo di essi specifica i secondi e l'altro i nanosecondi (miliardesimi di secondo).
 
Ora, poiché il più lungo dei suoi elementi è "real_time", composto da due ''unsigned int'', ossia da "due" integer, se ne deduce che la lunghezza di tale ''unione'', e quindi dell'intero campo ''Time'' è pari a '''2''' integer. La ''union'' "''snd_seq_timestamp''" può contenere, in alternativa, un "tick_time" (che è 1 integer) oppure un "real_time", che a sua volta è composto da 2 integer. Per un determinato evento i due dati sono sovrapposti e non possono essere validi entrambi contemporaneamente. Infatti, un bit nel campo ''flags'' indica quale dei due casi si sta trattando. Se il flag "real time" non è impostato, risulta valido solo il campo "tick_time", e l'altro campo va ignorato. Se invece è impostato il flag "real time", allora entrambi i campi (entrambi gli integer) della ''union'' sono significativi: il primo di essi specifica i secondi e l'altro i nanosecondi (miliardesimi di secondo).

Versione delle 15:09, 19 gen 2022

Preambolo

Nelle due sezioni precedenti abbiamo studiato le fondamenta della gestione del Midi con Gambas in ambiente ALSA: l'Invio e la Ricezione dei messaggi Midi in modo immediato.

Ora possiamo passare ad un livello superiore e più complesso: possiamo definirlo come quello dell'invio dei messaggi Midi pre-ordinato nel futuro.

Ciò avviene attraverso la loro temporizzazione, che vuol dire pre-disporre l'invio di uno o più messaggi Midi secondo un ordine temporale. Essa insomma ci dice quando un messaggio sarà inviato.
Mentre nelle due sezioni precedenti i dati Midi venivano inviati "ad libitum "; i dati cioè venivano inviati immediatamente, di volta in volta quando lo decidevamo noi. Ora si tratta di stabilire a monte quando saranno inviati - uno dopo l'altro - i messaggi Midi senza dover più intervenire direttamente per il loro invio.
Per ottenere questi eventi temporali (l'invio preordinato, prestabilito nel tempo dei messaggi Midi) dovrà essere usato il marcatore temporale: Timestamp.

Questo ci permetterà di creare un applicativo capace di svolgere le funzioni di sequencer Midi; ossia - appunto - capace di inviare in sequenza temporale i vari messaggi Midi, secondo un ordine prestabilito da chi ha creato la sequenza medesima di quei messaggi, costitutivi del brano musicale.

"Lo scopo [nella realizzazione di un sequencer] è quello di produrre un flusso di eventi che sarà eseguito in maniera successiva. Dobbiamo preparare un gruppo di eventi in anticipo in modo che l'hardware ha dei dati su cui lavorare. Ma [un sequecer] può durare anche per un lungo periodo e noi non possiamo effettuare un buffer di tutti gli eventi - dobbiamo selezionarne un certo numero, né troppi e né pochi. Il "puntatore" interno [del sequencer] è sempre di una misura musicale più avanti di ciò che stiamo ascoltando. Noi non possiamo prevedere in maniera precisa quando i nuovi dati saranno necessari, poiché il sequencer solleva gli eventi basandosi su una temporizzazione che può essere diversa dalla nostra. Senza un feedback del sequencer è quasi impossibile rimanere in sincronia con esso." [nota 1]


Introduzione al Timestamp

Nella programmazione Midi l'uso di una marcatura temporale (Timestamp) risulta utile in via generale se è richiesta la verifica dell'avvenimento di uno o più eventi. Gli eventi Midi così temporizzati vengono "accodati" e gestiti l'uno dopo l'altro (in sequenza) secondo l'ordine temporale della loro attivazione imposto dal marcatore temporale.
Come già accennato all'inizio di questa guida, il subsistema seq di ALSA gestisce gli eventi Midi temporizzati [nota 2], i cui molti dati costitutivi sono organizzati internamente in modo - come abbiamo visto - molto preciso, arrivando ad occupare una zona di memoria riservata pari sino a 28 byte.

Caratteristiche del Timestamp

All'interno di quella struttura di dati vi sono due parametri per determinare il Timestamp: il campo Flags ed il campo Time. Il campo Flags serve per poter impostare il tipo di timestamp (Timestamp mode) che si intende utilizzare. Il Timestamp può essere impostato in:

  • real time, corrisponde all'orologio, e la risoluzione è in secondi e nanosecondi;
  • song ticks, corrisponde ai tick del Midi.

Il Timestamp può inoltre essere:

  • assoluto, quando il tempo è determinato dal momento in cui la coda di eventi ha inizio;
  • relativo, quando il tempo è determinato dal momento in cui l'evento della coda è stato inviato.

I valori da assegnare al Timestamp sono definiti dal campo Time. Riguardo alla sua dimensione la documentazione presente in seq_event.h dice che:

typedef struct snd_seq_real_time {
             unsigned int tv_sec;            
             unsigned int tv_nsec;           
     } snd_seq_real_time_t;

     typedef unsigned int snd_seq_tick_time_t;

 typedef union snd_seq_timestamp {
             snd_seq_tick_time_t tick;       
             struct snd_seq_real_time time;  
     } snd_seq_timestamp_t;

Come possiamo vedere, snd_seq_timestamp è una union (unione). [nota 3] Ora, poiché il più lungo dei suoi elementi è "real_time", composto da due unsigned int, ossia da "due" integer, se ne deduce che la lunghezza di tale unione, e quindi dell'intero campo Time è pari a 2 integer. La union "snd_seq_timestamp" può contenere, in alternativa, un "tick_time" (che è 1 integer) oppure un "real_time", che a sua volta è composto da 2 integer. Per un determinato evento i due dati sono sovrapposti e non possono essere validi entrambi contemporaneamente. Infatti, un bit nel campo flags indica quale dei due casi si sta trattando. Se il flag "real time" non è impostato, risulta valido solo il campo "tick_time", e l'altro campo va ignorato. Se invece è impostato il flag "real time", allora entrambi i campi (entrambi gli integer) della union sono significativi: il primo di essi specifica i secondi e l'altro i nanosecondi (miliardesimi di secondo).
Ciò significa che in Gambas, se nel campo Flags non attiveremo il Real-Time, nel successivo campo Time, poiché per definire i valori del Tick-Time - come sappiamo - basta un solo valore integer, porremo il secondo integer dell'unione a zero. Quindi, ricapitolando, quando scriviamo un evento, dobbiamo usare sempre due integer. Nel caso di "tick_time", scriviamo il primo ed impostiamo a zero il secondo.

Determinazione ed impostazione del Timestamp

Per determinare il "Timestamp Mode", al fine di individuare il tipo di Timestamp da usare, si utilizzeranno le seguenti costanti, definite sempre in seq_event.h:

* #define SND_SEQ_TIME_STAMP_TICK(0<<0)/**< timestamp in clock ticks */
* #define SND_SEQ_TIME_STAMP_REAL(1<<0)/**< timestamp in real time */
* #define SND_SEQ_TIME_MODE_ABS(0<<1)/**< absolute timestamp */
* #define SND_SEQ_TIME_MODE_REL(1<<1)/**< relative to current time */

Pertanto, in Gambas scriveremo:

Const SND_SEQ_TIME_STAMP_TICK As Integer = 0
Const SND_SEQ_TIME_STAMP_REAL As Integer = 1
Const SND_SEQ_TIME_MODE_ABS As Integer = 0
Const SND_SEQ_TIME_MODE_REL As Integer = 2

Note

[1] Vedi D. Blengino: Una Drum Machine in Gambas

[2] Il sub-sistema di ALSA chiamato rawmidi, invece, gestisce un flusso di messaggi Midi nei loro valori essenziali secondo le specifiche standard Midi.

[3] Nel linguaggio C una union è "l'alternativa" di più elementi, che sono sovrapposti. La lunghezza in byte di una union è pari alla lunghezza del più lungo dei suoi elementi.