Differenze tra le versioni di "Alsa e Gambas: Il Tempo della coda"

Da Gambas-it.org - Wikipedia.
(Redirect alla pagina ALSA e Gambas - Il Tempo della coda)
 
Riga 1: Riga 1:
==Introduzione==
+
#REDIRECT [[ALSA_e_Gambas_-_Il_Tempo_della_coda]]
Come è facilmente immaginabile, un brano potrà eventualmente prevedere una o più variazioni del Tempo metronomico durante la sua esecuzione. Si ha questo caso, quando tali variazioni del Tempo sono previste e stabilite all'interno del File Midi. L'impostazione del valore del nuovo Tempo metronomico avviene mediante la previsione di apposito Meta-evento (FF 51 03 nn nn nn ); laddove i tre dati ''nn nn nn'' esprimono il valore del Tempo metronomico in <SPAN style="text-decoration:underline">micro</span>secondi.
 
<BR>Inoltre, il cambio del Tempo metronomico può essere effettuato anche manualmente a valontà.
 
 
 
ALSA dispone di varie funzioni per poter gestire il Tempo metronomico di un brano musicale, ossia la velocità di una coda di eventi.
 
<BR>Il Tempo pianificato degli eventi è definito in:
 
* ''Tempo Midi'' che determina il tempo in microsecondi;
 
* ''Tick'' (PPQN - pulse per quarter note) che determina il Tempo per ''tick'' {[[#Note|1]]}.
 
 
 
<P>Il <Span style="text-decoration:underline">Tempo</span> di un brano musicale viene gestito in <SPAN style="text-decoration:underline">micro</span>secondi {[[#Note|2]]} per ''movimenti'' (beat), ossia per nota da un quarto (semiminima), mediante la funzione di ALSA ''snd_seq_queue_tempo_set_tempo()''. Solitamente, si preferisce impostare il Tempo in movimenti per minuto (bpm - beat per minute).</p>
 
<P>L'impostazione del Tempo in ''Tick'' (PPQN) definisce la <Span style="text-decoration:underline">risoluzione dei tick</span>, ed avviene mediante la funzione ''snd_seq_queue_tempo_set_ppq()''. Esso è impostato di default a 96 tick per quarto; ossia per ogni quarto (corrispondente al valore temporale in musica di una semiminima) vi sono 96 tick.</p>
 
<P>Inoltre, ALSA imposta di default il valore dei movimenti per minuto (bpm - beat per minute) a 120, che è pari a 50.000 microsecondi (= 60 * 1000000 / 120).</p>
 
 
 
<P>Da notare che l'impostazione in PPQN non può essere modificata mentre la coda sta scorrendo, pertanto quel parametro deve essere impostato prima della partenza della coda. Per modificare, invece, il tempo della coda, mentre sta scorrendo, si dovrà operare mediante la funzione di ALSA ''snd_seq_set_queue_tempo()''.</p>
 
 
 
Nel caso la coda sia stata impostata in ''real-time'', allora la risoluzione, come sappiamo, è definita in nanosecondi.
 
 
 
 
 
==La scrittura del codice in Gambas==
 
 
 
Si devono innanzitutto distiguere due possibilità di impostazione del Tempo metronomico:
 
* quello diretto con l'invio di un evento Midi Tempo Alsa.
 
* quello effettuato mediante la ricezione da Alsa di un evento Eco precedentemente inviato.
 
 
 
 
 
===Impostazione del Tempo metronomico con l'invio di un evento Midi Tempo Alsa===
 
In questo caso il valore del Tempo metronomico avviene attraverso l'invio ad Alsa di uno specifico evento con valore ''Type'' uguale a ''35'', corrispondente alla costante di Alsa: ''SND_SEQ_EVENT_TEMPO''.
 
<BR>Successivamente sulla base del suo Tempo Delta assoluto (ossia ponendolo correttamente nell'ordine crescente della coda di eventi Midi da inviare), invieremo ad Alsa l'evento Tempo metronomico <SPAN style="text-decoration:underline">come un qualsiasi Evento Midi</span>, avendo l'accortezza, però, di attribuirgli e di accompagnarlo con i seguenti valori:
 
* '''Type''' = <Font Color= #B22222>SND_SEQ_EVENT_TEMPO</font> (questo valore è una costante prevista da Alsa, e dovrà essere nel nostro codice impostata a '''35''');
 
* '''Flag''' = 0
 
* '''Tag'''  = 0
 
* '''Queue''' = il numero della coda ottenuto nel modo consueto;
 
* '''Timestamp''' 1 = <Font Color= #B22222>la somma dei Tempi Delta di tutti gli eventi sino al Meta-evento Tempo in questione</font>;
 
* '''Timestamp''' 2 = 0
 
* '''Id Client sorgente''' = identificato nel modo consueto;
 
* '''Porta Client sorgente''' = identificata nel modo consueto;
 
* '''Id Client destinatario''' = <Font Color= #B22222>SND_SEQ_CLIENT_SYSTEM</font> (questo valore è una costante prevista da Alsa, e dovrà essere nel nostro codice impostata a '''0''');
 
* '''Porta Client destinatario''' = <Font Color= #B22222>SND_SEQ_PORT_SYSTEM_TIMER</font> (questo valore è una costante prevista da Alsa, e dovrà essere nel nostro codice impostata a '''0''');
 
* '''Queue''' = nuovamente il numero della coda ottenuto nel modo consueto (nel manuale di Alsa è indicato come: <Font Color= #006400>''unsigned char  queue''</font>);
 
* '''altro campo''' = 0  (occupa tre byte e corrisponde sostanzialmente alla posizione in byte del ''.channel'', del ''.note'' e del ''.velocity'' nell'invio dell'evento del NoteOn) (nel manuale di Alsa è indicato come: <Font Color= #006400>''unsigned char  unused [3]''</font>);
 
* '''altro campo''' = 0  (corrisponde sostanzialmente alla posizione in byte del ''.off_velocity'' nell'invio dell'evento del NoteOn);
 
* '''primo Valore''' = <Font Color= #B22222>il valore del Tempo metronomico espresso in microsecondi</font> (nel manuale di Alsa è indicato come: <Font Color= #006400>''signed int  value''</font>);
 
* '''secondo Valore''' = 0
 
 
 
 
 
L'invio dell'evento Tempo può essere effettuato anche in modo immediato con ''timestamp'' uguale a zero. In questo caso sarà necessario il passaggio finale attraverso la funzione esterna, che già conosciamo, '' snd_seq_drain_output()''.
 
 
 
 
 
===Impostazione del Tempo metronomico da eco===
 
In quest'altro caso l'impostazione del Tempo metronomico avviene mediante una serie di funzioni esterne di Alsa.
 
<BR>innanzitutto assumeremo dal file Midi il Tempo Delta, inoltre il Tempo metronomico sarà soggetto ad una complessa operazione che vede interessato anche il predetto Tempo Delta.
 
Private EXTERN snd_seq_queue_tempo_malloc(queue_tempo As Pointer) As Integer
 
Private EXTERN snd_seq_queue_tempo_set_ppq(queue_tempo As Pointer, tempo_per_quarti As Integer) As Integer
 
Private EXTERN snd_seq_queue_tempo_set_tempo(qtempo As Pointer, quarti_per_minuto As Integer) As Integer
 
Private EXTERN snd_seq_set_queue_tempo(seq As Pointer, outq As Integer, qtempo As Pointer) As Integer
 
Private EXTERN snd_seq_queue_tempo_free(qtempo As Pointer) As Integer
 
 
'''Public''' Sub impostaTempo(modificaTempo As Integer)
 
 
 
  Dim qtempo As Pointer
 
  Dim tempoDefinitivo As Integer
 
 
  snd_seq_queue_tempo_malloc(varPtr(qtempo))
 
 
 
<Font Color= #006400>' ''Calcoliamo il Tempo in BpM (ossia quanti microsecondi dura una nota da un quarto):''</font>
 
  tempoDefinitivo = Round(240000000 / (modificaTempo * (risoluzioneTD / 24)))
 
<Font Color=gray>' ''...oppure:''
 
  ' '''tempoDefinitivo = CInt(6000000000 / (modificaTempo * risoluzioneTD))
 
  ' '''tempoDefinitivo = CInt((6e7 / (modificaTempo * risoluzioneTD)) * risoluzioneTD)'''''</font>
 
 
 
  snd_seq_queue_tempo_set_tempo(qtempo, tempoDefinitivo)
 
 
 
  snd_seq_queue_tempo_set_ppq(qTempo, risoluzioneTD)
 
 
  snd_seq_set_queue_tempo(handle, outq, qtempo)
 
 
  snd_seq_queue_tempo_free(qtempo)
 
 
 
'''End'''
 
 
 
La funzione di ALSA ''snd_seq_queue_tempo_malloc(snd_seq_queue_tempo_t ** ptr)'' riserva della memoria per la gestione del tempo da parte delle funzioni di ALSA, e ritorna un puntatore. In questo caso ALSA riserva la memoria necessaria per la funzione, e ritorna un puntatore (segnato dal secondo dei due asterischi). Il primo asterisco è necessario perché ALSA deve sapere dove scrivere il suo puntatore per passarlo poi all'applicativo. Quindi avremo un puntatore ad un puntatore. Infatti, ogni volta che una funzione C scrive qualcosa, è necessario passargli un puntatore. Se ALSA deve riempire un puntatore, bisognerà passarle un puntatore a questo puntatore. Per passare, dunque, un indirizzo del puntatore (cioè ''un puntatore ad un puntatore'') ad ALSA, useremo la funzione di Gambas ''VarPtr''.
 
 
 
La funzione ''int snd_seq_set_queue_tempo(snd_seq_t * seq, int q, snd_seq_queue_tempo_t * tempo)'' imposta il tempo di una coda. Laddove:
 
* ''seq'' è l'handle del sequencer ALSA;
 
* ''q'' è è il numero identificativo della coda, di cui si deve cambiare il tempo;
 
* ''tempo'' è un puntatore ed un'informazione relativa al tempo.
 
 
 
La funzione ''void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t * info, int ppq) imposta il valore della risoluzione del Tempo Delta alla coda degli eventi Midi Alsa.
 
 
 
La funzione ''snd_seq_queue_tempo_free(snd_seq_queue_tempo_t * obj)'' libera l'area di memoria precedentemente allocata.
 
 
 
 
 
 
 
=Note=
 
 
 
[1] Il ''Tick'' è l'unità di misura più piccola nella risoluzione del sequencer.
 
 
 
[2] Il ''microsecondo'' rappresenta un milionesimo di secondo.
 

Versione attuale delle 16:37, 12 gen 2022