Differenze tra le versioni di "Alsa e Gambas: Creazione del Client e delle sue porte"

Da Gambas-it.org - Wikipedia.
Riga 1: Riga 1:
Per creare, ossia per rendere ''client'' il nostro programma sperimentale, è necessario utilizzare la funzione all'uopo dedicata di ALSA: '''snd_seq_open'''. Questa, come abbiamo già detto, è un ''handle'' che consente al programma di relazionarsi con ALSA. Nello specifico ''apre'' il sequencer di ALSA, creando un nuovo ''handle''. Essa apre cioè una connessione all'interfaccia del kernel del sequencer ALSA. Crea dunque un ''client'', e - per quanto ci riguarda - possiamo dire che ''rende client'' il nostro progetto.
+
====Funzione per la connessione del programma Midi con ALSA====
<P>La documentazione ufficiale di ALSA ci dice che la dichiarazione di questa funzione in C è: ''int snd_seq_open (snd_seq_t **seqp, const char *name, int streams, int mode)'' [ [[#Note|1]] ].</p>
+
Per creare, ossia per rendere ''client'' il nostro programma, è necessario utilizzare la funzione all'uopo dedicata di ALSA:
<p>L'impostazione dei parametri di detta funzione è la seguente:</p>
+
'''snd_seq_open'''
 +
Questa, come abbiamo già detto, è un ''handle'' che consente al programma di relazionarsi con ALSA. Nello specifico ''apre'' il sequencer di ALSA, creando un nuovo ''handle''. Essa apre cioè una connessione all'interfaccia del kernel del sequencer ALSA. Crea dunque un ''client'', e - per quanto ci riguarda - possiamo dire che ''rende client'' il nostro progetto.
 +
 
 +
 
 +
La documentazione ufficiale di ALSA ci dice che la dichiarazione di questa funzione in C è:
 +
''int snd_seq_open (snd_seq_t **seqp, const char *name, int streams, int mode)'' |[[#Note|1]]|
 +
L'impostazione dei parametri di detta funzione è la seguente:
 
* '''seqp''' : un puntatore [ [[#Note|2]] ] al puntatore ''snd_seq_t'' (per questo ''**seqp'' è appunto un puntatore ad un puntatore e presenta due asterischi);
 
* '''seqp''' : un puntatore [ [[#Note|2]] ] al puntatore ''snd_seq_t'' (per questo ''**seqp'' è appunto un puntatore ad un puntatore e presenta due asterischi);
 
* '''name''' : il nome del nostro sequencer. E' un nome stringa che possiede uno speciale significato in ALSA, e solitamente è necessario usare il termine "''default''". Solo successivamente si potrà porre un nome stringa di nostra scelta.
 
* '''name''' : il nome del nostro sequencer. E' un nome stringa che possiede uno speciale significato in ALSA, e solitamente è necessario usare il termine "''default''". Solo successivamente si potrà porre un nome stringa di nostra scelta.
Riga 10: Riga 16:
 
*'''mode''' : può assumere il valore di 0, oppure SND_SEQ_NONBLOCK. Esso rappresenta l'apertura del sequencer ALSA in modalità ''non-blocking'', cioè ''non-bloccante'': i dati non bloccheranno in entrata l'esecuzione del programma.
 
*'''mode''' : può assumere il valore di 0, oppure SND_SEQ_NONBLOCK. Esso rappresenta l'apertura del sequencer ALSA in modalità ''non-blocking'', cioè ''non-bloccante'': i dati non bloccheranno in entrata l'esecuzione del programma.
  
<p>Nella scrittura del nostro codice dobbiamo, come abbiamo imparato, richiamare tale funzione con ''Extern'':</p>
 
<p><Font Color= #B22222>''PRIVATE '''EXTERN''' snd_seq_open(seq AS Pointer, name as String, streams as Integer, mode as Integer) as Integer''</Font></p>
 
<p>La chiamata ci restituirà un integer, poiché - come abbiamo già detto - <span style= "text-decoration:underline">ogni funzione esterna di ALSA ritorna un codice di errore</span> (anche quando non si deve necessariamente creare un oggetto/handle). Questa funzione sarà riportata in gambas così:</p>
 
<p><Font Color= #B22222>''err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)''</font color>; la porta ha carateristica DUPLEX. <span style= "text-decoration:underline">In Gambas 3</span> utilizziamo ''VarPtr(Pointer as Pointer) AS Pointer'', il quale passa l'indirizzo del puntatore alla variabile "''handle''"; esso ritorna cioè un puntatore alla variabile "''handle''".</p>
 
<BR>Quindi aggiungeremo la gestione dell'errore.
 
  
<P>Potremo poi, volendo, attribuire al "Client" un nome da noi scelto (che avremo scelto già nella chiamata della funzione di apertura di ALSA effettuata nella classe principale). Per fare questo è necessario richiamare una funzione esterna di ALSA - che in C è: ''int snd_seq_set_client_name(snd_seq_t *seq, const char *name)'' - con il solito Extern:</p>
+
Nella scrittura del nostro codice dobbiamo, come abbiamo imparato, richiamare tale funzione con ''Extern'':
<p><Font Color= #B22222>''PRIVATE '''EXTERN''' snd_seq_client_name(seq AS Pointer, name AS String) AS Integer''</Font Color>. Questa funzione sarà espressa in Gambas come segue:<Font Color= #B22222> ''snd_seq_client_name(handle, myname)</font color></p>
+
<Font Color= #B22222>''Private '''EXTERN''' snd_seq_open(seq AS Pointer, name as String, streams as Integer, mode as Integer) as Integer''</Font>
<p>Possiamo inoltre ottenere il valore numerico identificativo del nostro Client. Questo identificativo numerico risulta indispensabile per conoscere od impostare le informazioni sul client. Solitamente ad un client-utente viene attribuito un identificativo tra 128 e 191. Richiamiamo ancora una funzione esterna di ALSA - che in C è: ''int snd_seq_client_id(snd_seq_t *seq)'' - :</p>
+
La chiamata ci restituirà un integer, poiché - come abbiamo già detto - <span style= "text-decoration:underline">ogni funzione esterna di ALSA ritorna un codice di errore</span> (anche quando non si deve necessariamente creare un oggetto/handle). Questa funzione sarà riportata in gambas così:
<p><Font Color= #B22222>''PRIVATE '''EXTERN''' snd_seq_client_id(seq As Pointer) As Integer''</Font Color>. Questa funzione sarà espressa in Gambas come segue:<Font Color= #B22222> ''id = snd_seq_client_id(handle)</font color>.</p>
+
<Font Color= #B22222>''err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)''</font color>
 +
la porta ha carateristica DUPLEX.
  
<p>Dopo aver dato il nome al Client, creiamo effettivamente la sua porta conferendogli la capacità. Per creare una porta di normale uso si richiamerà la funzione esterna di ALSA - che in C è: ''int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)'' - :</p>
+
In <span style= "text-decoration:underline">Gambas 3</span> utilizziamo ''VarPtr(Pointer as Pointer) AS Pointer'', il quale passa l'indirizzo del puntatore alla variabile "''handle''"; esso ritorna cioè un puntatore alla variabile "''handle''".
<p><Font Color= #B22222>''PRIVATE '''EXTERN'''  snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer''</Font Color>.</p>
+
 
<p>Questa funzione sarà espressa in Gambas come segue:<Font Color= #B22222>'' err = snd_seq_create_simple_port(handle, "Seq-Out", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)''</font color>. Creiamo la porta del Client con capacità generica di interpretare i dati Midi, ed in più la dichiariamo appartenente alla nostra applicazione, cioè il nostro sequencer-client.
+
 
<BR>Laddove le costanti:
+
====Gestione dell'errore====
 +
Quindi aggiungeremo la gestione dell'errore.
 +
 
 +
 
 +
====Attribuire al "Client" un nome====
 +
Potremo poi, volendo, attribuire al "Client" un nome da noi scelto (che avremo scelto già nella chiamata della funzione di apertura di ALSA effettuata nella classe principale). Per fare questo è necessario richiamare una funzione esterna di ALSA - che in C è:
 +
''int snd_seq_set_client_name(snd_seq_t *seq, const char *name)''
 +
con il solito Extern:
 +
<Font Color= #B22222>''Private '''EXTERN''' snd_seq_client_name(seq AS Pointer, name AS String) AS Integer''</Font Color>
 +
Questa funzione sarà espressa in Gambas come segue:
 +
<Font Color= #B22222> ''err = snd_seq_client_name(handle, myname)</font color>
 +
 
 +
 
 +
====Ottenere il numero identificativo del Client====
 +
Possiamo inoltre ottenere il valore numerico identificativo del nostro Client. Questo identificativo numerico risulta indispensabile per conoscere od impostare le informazioni sul client. Solitamente ad un client-utente viene attribuito un identificativo tra 128 e 191. Richiamiamo ancora una funzione esterna di ALSA - che in C è:
 +
''int snd_seq_client_id(snd_seq_t *seq)''
 +
ovviamente dichiarata in Gambas così:
 +
<Font Color= #B22222>''Private '''EXTERN''' snd_seq_client_id(seq As Pointer) As Integer''</Font Color>
 +
Questa funzione sarà espressa in Gambas come segue:
 +
<Font Color= #B22222> ''id = snd_seq_client_id(handle)</font color>
 +
 
 +
 
 +
====Creazione della Porta e sua ''capacità''====
 +
Dopo aver dato il nome al Client, creiamo effettivamente la sua porta conferendogli la capacità. Per creare una porta di normale uso si richiamerà la funzione esterna di ALSA - che in C è:
 +
''int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)''
 +
in Gambas tale dichiarazione sarà:
 +
<Font Color= #B22222>''Private '''EXTERN'''  snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer''</Font Color>.</p>
 +
 
 +
Questa funzione sarà espressa in Gambas come segue:
 +
<Font Color= #B22222>'' err = snd_seq_create_simple_port(handle, "Seq-Out", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)''</font color>
 +
 
 +
Creiamo la porta del Client con capacità generica di interpretare i dati Midi, ed in più la dichiariamo appartenente alla nostra applicazione, cioè il nostro sequencer-client.
 +
 
 +
Laddove le costanti:
 
* SND_SEQ_PORT_CAP_READ = 1;
 
* SND_SEQ_PORT_CAP_READ = 1;
 
* SND_SEQ_PORT_TYPE_MIDI_GENERIC = 2;
 
* SND_SEQ_PORT_TYPE_MIDI_GENERIC = 2;
 
* SND_SEQ_PORT_TYPE_APPLICATION = 1048576  (1<<20).
 
* SND_SEQ_PORT_TYPE_APPLICATION = 1048576  (1<<20).
<BR>Quindi aggiungeremo la consueta gestione dell'errore.</p>
 
<BR>
 
Procediamo in conclusione alla connessione delle porte del nostro applicativo con quella del softsynth [ [[#Note|3]] ] per ottenere i suoni, ponendo nella classe principale la chiamata alla funzione di ALSA, e trasferendole i valori dell'identificativo del nostro dispositivo-client e della sua porta. Detta funzione in C é:  ''int snd_seq_connect_to(snd_seq_t *seq, int myport, int src_client, int src_port)''.
 
<p>Nel nostro codice la richiameremo con la consueta funzione Extern: <Font Color= #B22222>''PRIVATE '''EXTERN'''  snd_seq_connect_to(seq As Pointer, myport As Integer, src_client As Integer, src_port As Integer) As Integer''</Font Color>.</p>
 
<p>Questa funzione sarà espressa in Gambas come segue:<Font Color= #B22222> ''err = snd_seq_connect_to(handle, outport, dclient, dport)''</font color></p>
 
  
<BR>
+
Quindi aggiungeremo la consueta gestione dell'errore.</p>
 +
 
 +
 
 +
====Connessione delle porta del programma con il ''Softsynth''====
 +
Procediamo in conclusione alla connessione delle porte del nostro applicativo con quella del softsynth |[[#Note|3]]| per ottenere i suoni, ponendo nella classe principale la chiamata alla funzione di ALSA, e trasferendole i valori dell'identificativo del nostro dispositivo-client e della sua porta.
 +
 
 +
Detta funzione in C é:
 +
''int snd_seq_connect_to(snd_seq_t *seq, int myport, int src_client, int src_port)''
 +
 
 +
Nel nostro codice la richiameremo con la consueta funzione Extern:
 +
<Font Color= #B22222>''Private '''EXTERN'''  snd_seq_connect_to(seq As Pointer, myport As Integer, src_client As Integer, src_port As Integer) As Integer''</Font Color>
 +
 
 +
Questa funzione sarà espressa in Gambas come segue:
 +
<Font Color= #B22222> ''err = snd_seq_connect_to(handle, outport, dclient, dport)''</font color>
 +
 
 
A questo punto, lanciando da terminale il comando: ''cat /proc/asound/seq/clients'', possiamo verificare:
 
A questo punto, lanciando da terminale il comando: ''cat /proc/asound/seq/clients'', possiamo verificare:
 
* il numero identificativo e il nome del nostro Client;
 
* il numero identificativo e il nome del nostro Client;
 
* il numero ed il nome della porta del nostro Client;
 
* il numero ed il nome della porta del nostro Client;
 
* il numero identificativo del device (come QSynth) e della sua porta (con relativa indicazione delle ''capacità''), al quale il client si è connesso.
 
* il numero identificativo del device (come QSynth) e della sua porta (con relativa indicazione delle ''capacità''), al quale il client si è connesso.
<p>Cercando il nostro client avremo infatti informazioni simili alle seguenti:</p>
+
 
<p>''Client 129 : "Progetto sequencer in Gambas-3" [User]''</p>
+
 
<p>''Port  0 : "Seq-Out" (--e-)''</p>
+
Cercando il nostro client avremo infatti informazioni simili alle seguenti:
<p>''Connecting To: 128:0''</p>
+
 
<BR>
+
- ''Client 129 : "Progetto sequencer in Gambas-3" [User]''
<p>Sguardo alle Routine necessarie per la ''gestione dell'errore''.</p>
+
 
<p>L'intera funzione per gestire gli errori sarà così concepita:</p>
+
- ''Port  0 : "Seq-Out" (--e-)''
<p>1. Come sappiamo, Alsa restituisce codici di errore numerici;</p>
+
 
<p>2. Otteniamo quindi il codice di errore, e lo passiamo ad Alsa usando ''snd_strerror()'', che per essere utilizzata ovviamente sarà debitamente richiamata con il solito ''Extern''. La funzione ''snd_strerror()'', quindi, ritorna un messaggio di spiegazione.</p>
+
- ''Connecting To: 128:0''
<p>3. Alsa ritorna una stringa del "C", che Gambas non può utilizzare; lo '''String@''' serve a convertire tale stringa. La sintassi della funzione String@ è: String@(Pointer as Pointer) as String</p>
+
 
 +
 
 +
====Sguardo alle Routine necessarie per la ''gestione dell'errore''====
 +
L'intera funzione per gestire gli errori sarà così concepita:
 +
 
 +
1. Come sappiamo, Alsa restituisce codici di errore numerici;
 +
 
 +
2. Otteniamo quindi il codice di errore, e lo passiamo ad Alsa usando la funzione esterna
 +
const char * snd_strerror (int errnum)
 +
 
 +
<Font Color= #B22222>''snd_strerror()''</font>
 +
che per essere utilizzata ovviamente sarà debitamente richiamata con il solito ''Extern'':
 +
<Font Color= #B22222>''Private Extern snd_strerror(err As Integer) As Pointer''</font>
 +
Si passerà alla funzione ''snd_strerror()'' un valore integer. La funzione in base al valore passato ritornerà un messaggio di spiegazione;
 +
 
 +
3. Alsa ritorna una stringa del "C", che Gambas non può utilizzare. Più precisamente ALSA passa un ''Pointer'' che deve essere dereferenziato. La funzione '''String@''' serve per dereferenziare quel ''Pointer'' passato da ALSA, consentendo così di leggere la stringa.
 +
<BR>La sintassi della funzione String@ è:
 +
String@(Pointer as Pointer) as String
 +
 
 +
La routine potrà essere come questa descritta di seguito:
 +
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'''
 +
 
  
 
====Vedere il codice====
 
====Vedere il codice====
<p>Per vedere in ordine il nostro codice sin qui descritto, cliccare sul collegamento alla sua pagina: [[Alsa_e_Gambas_Codice_1|1° CODICE]].</p>
+
Per vedere in ordine il nostro codice sin qui descritto, cliccare sul collegamento alla sua pagina: [[Alsa_e_Gambas_Codice_1|1° CODICE]].
 +
 
  
  
 +
=Note=
 +
[1] Vedi D. Blengino: [[Traduzione_della_comunità_di_Gambas-it#Iniziare_un_dialogo_con_ALSA|Iniziare un dialogo con ALSA]].
  
==Note==
+
[2] I Puntatori (Pointer) sono variabili sulle quali si leggono e si scrivono indirizzi (i pointer contengono indirizzi). Ottenere un valore tramite un pointer si dice "''dereferenziare il pointer''", nel senso che il pointer viene interrogato, ed esso dice dove andare a cercare. Così viene dereferenziato (cioé, si scarta il pointer e si usa invece il suo risultato). Il pointer ad un determinato indirizzo si chiama, poniamo, ''var_point_p (nome a caso)'', e leggendolo dentro vi si trova scritto il valore. Solitamente ai pointer è possibile assegnare il valore NULL, che significa "''non esiste alcun indirizzo''". Se i pointer sono NULL, non devono essere dereferenziati, pena (di solito) un errore del sistema operativo.
  
<p>[1] Vedi D. Blengino: [[Traduzione_della_comunità_di_Gambas-it#Iniziare_un_dialogo_con_ALSA|Iniziare un dialogo con ALSA]].</p>
 
<p>[2] I Puntatori (Pointer) sono variabili sulle quali si leggono e si scrivono indirizzi (i pointer contengono indirizzi). Ottenere un valore tramite un pointer si dice "''dereferenziare il pointer''", nel senso che il pointer viene interrogato, ed esso dice dove andare a cercare. Così viene dereferenziato (cioé, si scarta il pointer e si usa invece il suo risultato). Il pointer ad un determinato indirizzo si chiama, poniamo, ''var_point_p (nome a caso)'', e leggendolo dentro vi si trova scritto il valore. Solitamente ai pointer è possibile assegnare il valore NULL, che significa "''non esiste alcun indirizzo''". Se i pointer sono NULL, non devono essere dereferenziati, pena (di solito) un errore del sistema operativo.</p>
 
 
[3] Qualora la connessione sia invece impostata con il subsistema ALSA (solitamente 14:0), bisognerà ricordare, dopo aver lanciato il nostro applicativo, di connettere - ad esempio con il comando ''aconnect'' da terminale - il sistema ALSA con il softsynth. In sostanza la catena di connessione risulterà in questo caso essere la seguente: Applicativo-->ALSA-->Softsynth.
 
[3] Qualora la connessione sia invece impostata con il subsistema ALSA (solitamente 14:0), bisognerà ricordare, dopo aver lanciato il nostro applicativo, di connettere - ad esempio con il comando ''aconnect'' da terminale - il sistema ALSA con il softsynth. In sostanza la catena di connessione risulterà in questo caso essere la seguente: Applicativo-->ALSA-->Softsynth.

Versione delle 18:45, 23 feb 2013

Funzione per la connessione del programma Midi con ALSA

Per creare, ossia per rendere client il nostro programma, è necessario utilizzare la funzione all'uopo dedicata di ALSA:

snd_seq_open

Questa, come abbiamo già detto, è un handle che consente al programma di relazionarsi con ALSA. Nello specifico apre il sequencer di ALSA, creando un nuovo handle. Essa apre cioè una connessione all'interfaccia del kernel del sequencer ALSA. Crea dunque un client, e - per quanto ci riguarda - possiamo dire che rende client il nostro progetto.


La documentazione ufficiale di ALSA ci dice che la dichiarazione di questa funzione in C è:

int snd_seq_open (snd_seq_t **seqp, const char *name, int streams, int mode) |1|

L'impostazione dei parametri di detta funzione è la seguente:

  • seqp : un puntatore [ 2 ] al puntatore snd_seq_t (per questo **seqp è appunto un puntatore ad un puntatore e presenta due asterischi);
  • name : il nome del nostro sequencer. E' un nome stringa che possiede uno speciale significato in ALSA, e solitamente è necessario usare il termine "default". Solo successivamente si potrà porre un nome stringa di nostra scelta.
  • streams : la modalità in lettura e/o scrittura del nostro client. Questa modalità può essere:

- SND_SEQ_OPEN_OUTPUT: apre il sequencer solo per l'output. Tale modalità è identificata con un valore costante di tipo integer = 1;

- SND_SEQ_OPEN_INPUT: apre il sequencer solo per l'input. Tale modalità è identificata con un valore costante di tipo integer = 2;

- SND_SEQ_OPEN_DUPLEX: apre il sequencer sia per l'output che per l'input. Tale modalità è identificata con un valore costante di tipo integer = 3.

  • mode : può assumere il valore di 0, oppure SND_SEQ_NONBLOCK. Esso rappresenta l'apertura del sequencer ALSA in modalità non-blocking, cioè non-bloccante: i dati non bloccheranno in entrata l'esecuzione del programma.


Nella scrittura del nostro codice dobbiamo, come abbiamo imparato, richiamare tale funzione con Extern:

Private EXTERN snd_seq_open(seq AS Pointer, name as String, streams as Integer, mode as Integer) as Integer

La chiamata ci restituirà un integer, poiché - come abbiamo già detto - ogni funzione esterna di ALSA ritorna un codice di errore (anche quando non si deve necessariamente creare un oggetto/handle). Questa funzione sarà riportata in gambas così:

err = snd_seq_open(VarPtr(handle), "default", SND_SEQ_OPEN_DUPLEX, 0)

la porta ha carateristica DUPLEX.

In Gambas 3 utilizziamo VarPtr(Pointer as Pointer) AS Pointer, il quale passa l'indirizzo del puntatore alla variabile "handle"; esso ritorna cioè un puntatore alla variabile "handle".


Gestione dell'errore

Quindi aggiungeremo la gestione dell'errore.


Attribuire al "Client" un nome

Potremo poi, volendo, attribuire al "Client" un nome da noi scelto (che avremo scelto già nella chiamata della funzione di apertura di ALSA effettuata nella classe principale). Per fare questo è necessario richiamare una funzione esterna di ALSA - che in C è:

int snd_seq_set_client_name(snd_seq_t *seq, const char *name)

con il solito Extern:

Private EXTERN snd_seq_client_name(seq AS Pointer, name AS String) AS Integer

Questa funzione sarà espressa in Gambas come segue:

 err = snd_seq_client_name(handle, myname)


Ottenere il numero identificativo del Client

Possiamo inoltre ottenere il valore numerico identificativo del nostro Client. Questo identificativo numerico risulta indispensabile per conoscere od impostare le informazioni sul client. Solitamente ad un client-utente viene attribuito un identificativo tra 128 e 191. Richiamiamo ancora una funzione esterna di ALSA - che in C è:

int snd_seq_client_id(snd_seq_t *seq)

ovviamente dichiarata in Gambas così:

Private EXTERN snd_seq_client_id(seq As Pointer) As Integer

Questa funzione sarà espressa in Gambas come segue:

 id = snd_seq_client_id(handle)


Creazione della Porta e sua capacità

Dopo aver dato il nome al Client, creiamo effettivamente la sua porta conferendogli la capacità. Per creare una porta di normale uso si richiamerà la funzione esterna di ALSA - che in C è:

int snd_seq_create_simple_port(snd_seq_t *seq, const char *name, unsigned int caps, unsigned int type)

in Gambas tale dichiarazione sarà:

Private EXTERN  snd_seq_create_simple_port(seq As Pointer, name As String, caps As Integer, type As Integer) As Integer.</p>

Questa funzione sarà espressa in Gambas come segue:

 err = snd_seq_create_simple_port(handle, "Seq-Out", SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC + SND_SEQ_PORT_TYPE_APPLICATION)

Creiamo la porta del Client con capacità generica di interpretare i dati Midi, ed in più la dichiariamo appartenente alla nostra applicazione, cioè il nostro sequencer-client.

Laddove le costanti:

  • SND_SEQ_PORT_CAP_READ = 1;
  • SND_SEQ_PORT_TYPE_MIDI_GENERIC = 2;
  • SND_SEQ_PORT_TYPE_APPLICATION = 1048576 (1<<20).

Quindi aggiungeremo la consueta gestione dell'errore.</p>


Connessione delle porta del programma con il Softsynth

Procediamo in conclusione alla connessione delle porte del nostro applicativo con quella del softsynth |3| per ottenere i suoni, ponendo nella classe principale la chiamata alla funzione di ALSA, e trasferendole i valori dell'identificativo del nostro dispositivo-client e della sua porta.

Detta funzione in C é:

int snd_seq_connect_to(snd_seq_t *seq, int myport, int src_client, int src_port)

Nel nostro codice la richiameremo con la consueta funzione Extern:

Private EXTERN  snd_seq_connect_to(seq As Pointer, myport As Integer, src_client As Integer, src_port As Integer) As Integer

Questa funzione sarà espressa in Gambas come segue:

 err = snd_seq_connect_to(handle, outport, dclient, dport)

A questo punto, lanciando da terminale il comando: cat /proc/asound/seq/clients, possiamo verificare:

  • il numero identificativo e il nome del nostro Client;
  • il numero ed il nome della porta del nostro Client;
  • il numero identificativo del device (come QSynth) e della sua porta (con relativa indicazione delle capacità), al quale il client si è connesso.


Cercando il nostro client avremo infatti informazioni simili alle seguenti:

- Client 129 : "Progetto sequencer in Gambas-3" [User]

- Port 0 : "Seq-Out" (--e-)

- Connecting To: 128:0


Sguardo alle Routine necessarie per la gestione dell'errore

L'intera funzione per gestire gli errori sarà così concepita:

1. Come sappiamo, Alsa restituisce codici di errore numerici;

2. Otteniamo quindi il codice di errore, e lo passiamo ad Alsa usando la funzione esterna

const char * snd_strerror (int errnum)
snd_strerror()

che per essere utilizzata ovviamente sarà debitamente richiamata con il solito Extern:

Private Extern snd_strerror(err As Integer) As Pointer

Si passerà alla funzione snd_strerror() un valore integer. La funzione in base al valore passato ritornerà un messaggio di spiegazione;

3. Alsa ritorna una stringa del "C", che Gambas non può utilizzare. Più precisamente ALSA passa un Pointer che deve essere dereferenziato. La funzione String@ serve per dereferenziare quel Pointer passato da ALSA, consentendo così di leggere la stringa.
La sintassi della funzione String@ è:

String@(Pointer as Pointer) as String

La routine potrà essere come questa descritta di seguito:

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


Vedere il codice

Per vedere in ordine il nostro codice sin qui descritto, cliccare sul collegamento alla sua pagina: 1° CODICE.


Note

[1] Vedi D. Blengino: Iniziare un dialogo con ALSA.

[2] I Puntatori (Pointer) sono variabili sulle quali si leggono e si scrivono indirizzi (i pointer contengono indirizzi). Ottenere un valore tramite un pointer si dice "dereferenziare il pointer", nel senso che il pointer viene interrogato, ed esso dice dove andare a cercare. Così viene dereferenziato (cioé, si scarta il pointer e si usa invece il suo risultato). Il pointer ad un determinato indirizzo si chiama, poniamo, var_point_p (nome a caso), e leggendolo dentro vi si trova scritto il valore. Solitamente ai pointer è possibile assegnare il valore NULL, che significa "non esiste alcun indirizzo". Se i pointer sono NULL, non devono essere dereferenziati, pena (di solito) un errore del sistema operativo.

[3] Qualora la connessione sia invece impostata con il subsistema ALSA (solitamente 14:0), bisognerà ricordare, dopo aver lanciato il nostro applicativo, di connettere - ad esempio con il comando aconnect da terminale - il sistema ALSA con il softsynth. In sostanza la catena di connessione risulterà in questo caso essere la seguente: Applicativo-->ALSA-->Softsynth.