Differenze tra le versioni di "Alsa e Gambas: Ricezione con un programma esterno di supporto"

Da Gambas-it.org - Wikipedia.
(La soluzione di un programma esterno di supporto)
(La soluzione di un programma esterno di supporto)
Riga 9: Riga 9:
 
Per risolvere il problema relativo all'input degli eventi da ALSA, è possibile pensare ad una soluzione esterna combinata: si tratterebbe di scrivere un breve programma C, cosa che quindi permetterebbe di avere accesso alle piene funzionalità del sistema. Poi da Gambas si farebbe un Exec a quel programma, per poterne leggere lo standard output con un ''watch''. Il programma di supporto in C normalmente dormirebbe; qualora, però, dovesse trovare eventi da ALSA, li manderebbe fuori. Il programma principale di Gambas potrebbe intercettare e leggere tali dati in output dal programma C con un evento del tipo process_Read.
 
Per risolvere il problema relativo all'input degli eventi da ALSA, è possibile pensare ad una soluzione esterna combinata: si tratterebbe di scrivere un breve programma C, cosa che quindi permetterebbe di avere accesso alle piene funzionalità del sistema. Poi da Gambas si farebbe un Exec a quel programma, per poterne leggere lo standard output con un ''watch''. Il programma di supporto in C normalmente dormirebbe; qualora, però, dovesse trovare eventi da ALSA, li manderebbe fuori. Il programma principale di Gambas potrebbe intercettare e leggere tali dati in output dal programma C con un evento del tipo process_Read.
  
<BR>Presentiamo, allora, di seguito soltanto le parti essenziali e fondamentali di codice sia del programma C di supporto che del programma in Gambas.
+
<BR>Presentiamo, allora, di seguito soltanto le parti essenziali e ''fondamentali'' di codice sia del programma C di supporto che del programma in Gambas.
  
 
<BR>'''Programma in C di supporto''':
 
<BR>'''Programma in C di supporto''':
  
 +
Come ''base'' abbiamo preso il codice del programma "''aseqdump''" e lo abbiamo opportunamente modificato per ottenere l'invio di singoli messaggi Midi all'output.
 +
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <stdarg.h>
 +
#include <string.h>
 +
#include <signal.h>
 +
#include <getopt.h>
 +
#include <sys/poll.h>
 +
#include <alsa/asoundlib.h>
 +
 +
<Font Color= #006400>/* Qui le varie funzioni per la Gestione degli Errori */</font>
 +
......
 +
 +
<Font Color= #006400>/* Qui le varie funzioni per l'apertura di ALSA e per la creazione del Client e delle sue porte */</font>
 +
......
 
   
 
   
 +
 +
<Font Color= #006400>/* Ora le funzioni per la distinzione dei vari possibili eventi Midi ricevuti, */</font>
 +
<Font Color= #006400>/* e per l'invio dei singoli Messaggi Midi all'output */</font>
 +
static void dump_event(const snd_seq_event_t *ev)
 +
{
 +
      switch (ev->type) {
 +
      case SND_SEQ_EVENT_NOTEON:
 +
                write(1, &ev->data.note.channel, sizeof(char));
 +
fflush(stdout);
 +
write(1, &ev->data.note.note, sizeof(char));
 +
fflush(stdout);
 +
write(1, &ev->data.note.velocity, sizeof(char));
 +
fflush(stdout);
 +
            break;
 +
 +
  
  
Riga 66: Riga 98:
 
   Read #Last, vRacc
 
   Read #Last, vRacc
 
   
 
   
  <Font Color= #006400>'' ' Per fini didattici qui viene stampato in console in contenuto della variabile vRacc.''</font>
+
  <Font Color= #006400>'' ' Per fini didattici qui viene soltanto stampato in console in contenuto della variabile vRacc.''</font>
 
   Print vRacc
 
   Print vRacc
 
      
 
      

Versione delle 08:45, 16 set 2011

Procederemo, ora, a mostrare un secondo metodo, che fa uso di una pipe da un programma esterno, scritto in linguaggio C, con il quale evitare ogni possibile evidente latenza. Questa soluzione è allo stato attuale l'unico modo corretto di inserire nel message loop i messaggi Midi che ci interessano.
Tale soluzione si rende necessaria, poiché con ALSA il meccanismo usato solitamente è di controllare gli eventi dal device Midi nel Main Message Loop, basato sulle funzioni poll() e select(). ALSA, però, non viene letto come se fosse un file, e quindi uno stream di Gambas non è in grado di sollevare un evento, tipo stream_Read(), usando la funzione poll(). Questa funzione, in breve, ci dice se c'è qualche dato da leggere. La procedura, dunque, prevede che dapprima vengono ottenuti da ALSA i descrittori dei file; successivamente viene utilizzata la chiamata alla funzione poll() per vedere se c'è quealcosa da leggere. Più precisamente si chiede al sistema di controllare tutti i file descriptors, e poi si va a leggere con la funzione di ALSA: snd_seq_event_input(snd_seqt * seq, snd_seq_event_t ** ev). Purtroppo, tale procedura non è possibile integrarla nell'event loop di Gambas. Sarebbe davvero risolutivo, se Gambas permettesse di inserire nel message loop dei file descriptor arbitrari. Come abbiamo cercato di spiegare, con Gambas sono inutilizzabili i fdescrittori di file che ci passano le funzioni di ALSA, poiché non esiste (...speriamo in futuro !) una funzione per interagire con il message loop. Se Gambas fosse più elastico, darebbe la possibilità di personalizzare il message loop, dato che è cosa buona e giusta inserire appunto nel message loop i dati ed i valori che vogliamo. Attualmente, purtroppo, ciò può essere fatto soltanto attraverso l'uso di componenti scritti in C++ che usano l'API interna.
I semplici programmi in C, come arecordmidi e aseqdump, per leggere gli eventi per leggere gli eventi dalla predetta funzione di ALSA, eseguono un ciclo. Ciò ha un senso, poiché tali semplici programmi di ricezione di eventi Midi svolgono soltanto una sola applicazione: quella di leggere dati. Ma se un programma GUI deve anche gestire la grafica, il ciclo non va bene. Noi, allora, abbiamo insomma bisogno di un modo efficace per essere avvertiti che c'è qualche dato da leggere. Cosa, questa, che potrebbe essere fatta anche con un ciclo, se in modo sicuro vi fossero dati da leggere. Se, però non c'è niente da eggere, non può essere usato un ciclo, sarebbe una perdita di tempo ed inutile uso della CPU e delle altre risorse di sistema.

E', quindi, necessario un evento di Gambas.


La soluzione di un programma esterno di supporto

Per risolvere il problema relativo all'input degli eventi da ALSA, è possibile pensare ad una soluzione esterna combinata: si tratterebbe di scrivere un breve programma C, cosa che quindi permetterebbe di avere accesso alle piene funzionalità del sistema. Poi da Gambas si farebbe un Exec a quel programma, per poterne leggere lo standard output con un watch. Il programma di supporto in C normalmente dormirebbe; qualora, però, dovesse trovare eventi da ALSA, li manderebbe fuori. Il programma principale di Gambas potrebbe intercettare e leggere tali dati in output dal programma C con un evento del tipo process_Read.


Presentiamo, allora, di seguito soltanto le parti essenziali e fondamentali di codice sia del programma C di supporto che del programma in Gambas.


Programma in C di supporto:

Come base abbiamo preso il codice del programma "aseqdump" e lo abbiamo opportunamente modificato per ottenere l'invio di singoli messaggi Midi all'output.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <sys/poll.h>
#include <alsa/asoundlib.h>

/* Qui le varie funzioni per la Gestione degli Errori */
......

/* Qui le varie funzioni per l'apertura di ALSA e per la creazione del Client e delle sue porte */
......

/* Ora le funzioni per la distinzione dei vari possibili eventi Midi ricevuti, */
/* e per l'invio dei singoli Messaggi Midi all'output */
static void dump_event(const snd_seq_event_t *ev)
{
     switch (ev->type) {
     case SND_SEQ_EVENT_NOTEON:
               write(1, &ev->data.note.channel, sizeof(char));

fflush(stdout); write(1, &ev->data.note.note, sizeof(char)); fflush(stdout); write(1, &ev->data.note.velocity, sizeof(char)); fflush(stdout);

           break;




Programma principale in Gambas:

 ' Gambas class file


d As Process

PUBLIC Sub Form_Open()

Dim rob As String
Dim robTre as Integer
Dim client_id As Integer


 ' Assicura comunque la chiusura del programma in C di supporto
Shell "killall supporto" Wait

 ' Avvia il programma in C di supporto.
d = Exec ["/supporto"] For Read As "prova"

 ' Attende che si sia certamente avviato il programma di supporto.
Wait 0.5

 ' Verifica che il programma di supporto sia stato avviato e sia presente fra i client.
 ' Poi carica l'output nella variabile "rob".
Shell "cat /proc/asound/seq/clients | grep supporto" To rob

 ' Estrapola l'ottavo, il nono ed il decimo carattere dalla stringa memorizzata nella variabile "rob".
 ' Si tratta del numero identificativo del Client/programma di supporto.
robTre = Mid$(rob, 8, 3)

 ' Converte la variabile "rob" in un numero intero.
client_id = Val(robTre)

 ' Connette lo strumento Midi esterno al programma in C di supporto,
 ' individuandolo con il suo Id come client.
Shell "aconnect 24:0 " & client_id & ":0"

END


 ' Se viene inviato dal programma di supporto almeno un dato al suo output,
 ' e quindi se c'è qualcosa da leggere, viene scatenata questa sub-routine.
PUBLIC Sub prova_Read()

Dim vRacc As Byte

 ' Vengono letti i dati provenienti dallo standard output del programma di supporto.
 Read #Last, vRacc

 ' Per fini didattici qui viene soltanto stampato in console in contenuto della variabile vRacc.
 Print vRacc
   
END


PUBLIC Sub Button1_Click()

 ' Viene disconnesso il client di supporto dal dispositivo Midi esterno,
Shell "aconnect -d 24:0 128:0" Wait

 ' Viene quindi chiuso il client di supporto; ed in fine il programma stesso di Gambas.
Exec ["killall supporto"] Wait 

Me.Close()

END


< Pagina in costruzione >