Differenze tra le versioni di "Creare un semplice Client di Jack con le risorse della libreria libjack"
(Creata pagina con "'''JACK''' Audio Connection Kit è un server audio a bassa latenza sia per dati audio che per dati Midi. ''Jack'' consente di connettere svariate applicazioni ''client'' ad un...") |
|||
Riga 366: | Riga 366: | ||
=Riferimenti= | =Riferimenti= | ||
* http://jackaudio.org Jack Audio Connection Kit | * http://jackaudio.org Jack Audio Connection Kit | ||
− | |||
* https://github.com/jackaudio/jackaudio.github.com/wiki/Q_difference_jack1_jack2 | * https://github.com/jackaudio/jackaudio.github.com/wiki/Q_difference_jack1_jack2 | ||
* https://github.com/jackaudio/example-clients | * https://github.com/jackaudio/example-clients | ||
− | |||
* https://www.crudebyte.com/jack-ios/sdk/doc/getting_started.html | * https://www.crudebyte.com/jack-ios/sdk/doc/getting_started.html |
Versione delle 07:03, 2 apr 2021
JACK Audio Connection Kit è un server audio a bassa latenza sia per dati audio che per dati Midi. Jack consente di connettere svariate applicazioni client ad un dispositivo audio, ed anche con altri client. I Client di Jack possono funzionare sia come applicazioni con processi separati rispetto al server audio, sia come plugin all'interno dello stesso Jack.
Indice
Creare un semplice Client di Jack con Gambas
Per creare in Gambas un semplice Client di Jack, e connettere le sue porte con il server Jack, bisognerà servirsi delle risorse offerte dalla libreria dinamica condivisa: "libjack.so.0.1.0"
Ogni porta audio in Jack è un canale audio mono in formato Single, quindi a 32-bit.
V'è da precisare che Jack in tal caso prevede una chiamata ad una routine callback, ma Gambas - almeno allo stato attuale - non è in grado di funzionare in un altro thread, causando così il crash dell'applicativo. Pertanto, bisognerà far funzionare la procedura di callback all'interno di una libreria C esterna da noi appositamente creata, che chiameremo ad esempio jk.c . Il codice sorgente di tale nostra apposita libreria dinamica condivisa potrà essere inserito nel codice Gambas; lì sarà prevista anche la riga di comando con Shell per compilare la libreria.
Creazione di un Client e connessione di tipo mono al server jack
Viene creato un Client di Jack, e vengono generate connessioni audio di tipo mono.
Private Const JackNullOption As Byte = 0 ' Private Const JACK_DEFAULT_MIDI_TYPE As String = "8 bit raw midi" Private Const JACK_DEFAULT_AUDIO_TYPE As String = "32 bit float mono audio" Private Const JackPortIsInput As Byte = 1 Private Const JackPortIsOutput As Byte = 2 Private Const JackPortIsPhysical As Byte = 4 Private err As Integer Private client As Pointer Private input_port As Pointer Private output_port As Pointer Library "libjack:0.1.0" ' jack_client_t * jack_client_open (const char *client_name, jack_options_t options, jack_status_t *status,...) ' Open an external client session with a JACK server. Private Extern jack_client_open(client_name As String, options As Integer, status As Pointer, server_name As String) As Pointer ' char * jack_get_client_name (jack_client_t *client) ' Returns a pointer to actual client name. Private Extern jack_get_client_name(jack_client As Pointer) As String ' jack_nframes_t jack_get_sample_rate (jack_client_t *) ' Returns the sample rate of the jack system, as set by the user when jackd was started. Private Extern jack_get_sample_rate(jack_client As Pointer) As Integer ' jack_port_t * jack_port_register (jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) ' Create a new port for the client. Private Extern jack_port_register(jack_client As Pointer, port_name As String, port_type As String, flags As Integer, buffer_size As Integer) As Pointer ' int jack_activate (jack_client_t *client) ' Tell the Jack server that the program is ready to start processing audio. Private Extern jack_activate(jack_client As Pointer) As Integer ' const char ** jack_get_ports (jack_client_t *, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags) ' Returns a NULL-terminated array of ports that match the specified arguments. Private Extern jack_get_ports(jack_client As Pointer, port_name_pattern As String, type_name_pattern As String, flags As Integer) As Pointer ' const char * jack_port_name (const jack_port_t *port) ' Returns the full name of the jack_port_t (including the "client_name:" prefix). Private Extern jack_port_name(jack_port As Pointer) As String ' int jack_connect (jack_client_t *, const char *source_port, const char *destination_port) ' Establish a connection between two ports. Private Extern jack_connect(jack_client As Pointer, src_port As String, dest_port As String) As Integer ' int jack_client_close (jack_client_t *client) ' Disconnects an external client from a JACK server. Private Extern jack_client_close(jack_client As Pointer) As Integer ' void Invoca_Callback (jack_client_t *cl, jack_port_t *it, jack_port_t *ot) ' Invoca la funzione principale della libreria ad hoc per la funzione "callback" Private Extern Invoca_Callback(Pclient As Pointer, it As Pointer, ot As Pointer) As Integer In "/tmp/libjk" Public Sub Form_Open() ' Invoca la sotto-procedura per salvare in apposto file .c il codice sorgente della nostra libreria "ad hoc" e per crearla: CreaLibjk() End Public Sub Button1_Click() Dim nomeClient As String = "Client_1" Dim ports As Pointer Dim sample As Integer Dim porta, nome_porta As String Dim status As Single client = jack_client_open(nomeClient, JackNullOption, VarPtr(status), Null) If IsNull(client) Then Print "Impossibile aprire una sessione del Client con il server Jack !" nomeClient = jack_get_client_name(client) Print "\nNome del Client = "; nomeClient sample = jack_get_sample_rate(client) Print "Campionamento = hz "; sample Print "\n=========================================\n" input_port = jack_port_register(client, "input_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0) output_port = jack_port_register(client, "output_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0) If (input_port = 0) Or (output_port = 0) Then Print "Nessuna porta di Jack disponibile !" Invoca_Callback(client, input_port, output_port) err = jack_activate(client) If err <> 0 Then Print "Impossibile attivare il Client !" ' Connette le porte: ports = jack_get_ports(client, "system:capture_1", Null, JackPortIsPhysical Or JackPortIsOutput) If ports = 0 Then Print "Impossibile agganciare alcuna porta fisica !" Free(Object.Address(Button1)) Quit Endif porta = String@(Pointer@(ports)) nome_porta = jack_port_name(input_port) Print porta, nome_porta err = jack_connect(client, porta, nome_porta) If err <> 0 Then Print "Impossibile connettere la porta d'Entrata !" ' Connette le porte: ports = jack_get_ports(client, Null, Null, JackPortIsPhysical Or JackPortIsInput) If ports = 0 Then Print "Impossibile agganciare alcuna porta fisica !" porta = String@(Pointer@(ports)) nome_porta = jack_port_name(output_port) Print nome_porta, porta err = jack_connect(client, nome_porta, porta) If err <> 0 Then Print "Impossibile connettere la porta d'Uscita !", err Print End Private Procedure CreaLibjk() ' Salva il codice sorgente della nostra libreria dinamica .so, e poi la crea File.Save("/tmp/jk.c", "#include <string.h>\n" & "#include <jack/jack.h>" & "\n\n" & "jack_port_t *input_port;\n" & "jack_port_t *output_port;\n" & "jack_client_t *client;" & "\n\n" & "int process (jack_nframes_t, void *);" & "\n\n" & "void Invoca_Callback (jack_client_t *cl, jack_port_t *it, jack_port_t *ot) {\n" & " client = cl;\n" & " input_port = it;\n" & " output_port = ot;\n\n" & " jack_set_process_callback (client, process, 0);\n}" & "\n\n" & "int process (jack_nframes_t nframes, void *arg) {\n" " jack_default_audio_sample_t *in, *out;\n" & " in = jack_port_get_buffer (input_port, nframes);\n" & " out = jack_port_get_buffer (output_port, nframes);\n\n" & " memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);\n\n" & " return 0;\n}\n") Shell "gcc -o /tmp/libjk.so /tmp/jk.c -shared -fPIC -ljack" Wait End Public Sub Button2_Click() jack_client_close(client) End
Creazione di un Client e connessione di tipo stereo al server jack
Vediamo ora un possibile codice per creare un Client ed effettuare una connessione di tipo stereo al server jack:
Private Const JackNullOption As Byte = 0 ' Private Const JACK_DEFAULT_MIDI_TYPE As String = "8 bit raw midi" Private Const JACK_DEFAULT_AUDIO_TYPE As String = "32 bit float mono audio" Private Const JackPortIsInput As Byte = 1 Private Const JackPortIsOutput As Byte = 2 Private Const JackPortIsPhysical As Byte = 4 Private err As Integer Private client As Pointer Private porte_input As New Pointer[2] Private porte_output As New Pointer[2] Library "libjack:0.1.0" ' jack_client_t * jack_client_open (const char *client_name, jack_options_t options, jack_status_t *status,...) ' Open an external client session with a JACK server. Private Extern jack_client_open(client_name As String, options As Integer, status As Pointer, server_name As String) As Pointer ' char * jack_get_client_name (jack_client_t *client) ' Returns a pointer to actual client name. Private Extern jack_get_client_name(jack_client As Pointer) As String ' jack_nframes_t jack_get_sample_rate (jack_client_t *) ' Returns the sample rate of the jack system, as set by the user when jackd was started. Private Extern jack_get_sample_rate(jack_client As Pointer) As Integer ' jack_port_t * jack_port_register (jack_client_t *client, const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) ' Create a new port for the client. Private Extern jack_port_register(jack_client As Pointer, port_name As String, port_type As String, flags As Integer, buffer_size As Integer) As Pointer ' int jack_activate (jack_client_t *client) ' Tell the Jack server that the program is ready to start processing audio. Private Extern jack_activate(jack_client As Pointer) As Integer ' const char ** jack_get_ports (jack_client_t *, const char *port_name_pattern, const char *type_name_pattern, unsigned long flags) ' Returns a NULL-terminated array of ports that match the specified arguments. Private Extern jack_get_ports(jack_client As Pointer, port_name_pattern As String, type_name_pattern As String, flags As Integer) As Pointer ' const char * jack_port_name (const jack_port_t *port) ' Returns the full name of the jack_port_t (including the "client_name:" prefix). Private Extern jack_port_name(jack_port As Pointer) As String ' int jack_connect (jack_client_t *, const char *source_port, const char *destination_port) ' Establish a connection between two ports. Private Extern jack_connect(jack_client As Pointer, src_port As String, dest_port As String) As Integer ' int jack_client_close (jack_client_t *client) ' Disconnects an external client from a JACK server. Private Extern jack_client_close(jack_client As Pointer) As Integer ' void Invoca_Callback (jack_client_t *cl, jack_port_t *it, jack_port_t *ot) ' Invoca la funzione principale della libreria ad hoc per la funzione "callback" Private Extern Invoca_Callback(Pclient As Pointer, it As Pointer[], ot As Pointer[]) As Integer In "/tmp/libjk" Public Sub Form_Open() ' Invoca la sotto-procedura per salvare in apposto file .c il codice sorgente della nostra libreria "ad hoc" e per crearla: CreaLibjk() End Public Sub Button1_Click() Dim nomeClient, nome_porta As String Dim porte As Pointer Dim b As Byte Dim sample As Integer Dim status As Single nomeClient = "Client_1" client = jack_client_open(nomeClient, JackNullOption, VarPtr(status), Null) If IsNull(client) Then Print "Impossibile aprire una sessione del Client con il server Jack !" nomeClient = jack_get_client_name(client) Print "\nNome del Client = "; nomeClient sample = jack_get_sample_rate(client) Print "Campionamento = hz "; sample Print "\n=========================================\n" For b = 0 To 1 nome_porta = "input_" & CStr(b + 1) porte_input[b] = jack_port_register(client, nome_porta, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0) nome_porta = "output_" & CStr(b + 1) porte_output[b] = jack_port_register(client, nome_porta, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0) If (porte_input[b] = 0) Or (porte_output[b] = 0) Then Print "Nessuna porta di Jack disponibile !" Next Invoca_Callback(client, porte_input, porte_output) err = jack_activate(client) If err <> 0 Then Print "Impossibile attivare il Client !" ' ''''''''''''''''''''''''''''' Print "Connessione delle porte\n" ' Connette le porte: porte = jack_get_ports(client, Null, Null, JackPortIsPhysical Or JackPortIsOutput) nome_porta = String@(Pointer@(porte)) Print nome_porta, "--->", jack_port_name(porte_input[0]) Print String@(Pointer@(porte + SizeOf(gb.Pointer))), "--->", jack_port_name(porte_input[1]) Print If porte = 0 Then Print "Impossibile ottenere i nomi delle porte !" Free(Object.Address(Button1)) Quit Endif For b = 0 To 1 err = jack_connect(client, String@(Pointer@(porte + (CInt(b) * SizeOf(gb.Pointer)))), jack_port_name(porte_input[b])) If err <> 0 Then Print "Impossibile connettere le porte !" Next porte = jack_get_ports(client, Null, Null, JackPortIsPhysical Or JackPortIsInput) nome_porta = String@(Pointer@(porte)) Print jack_port_name(porte_output[0]), "--->", nome_porta, nome_porta Print jack_port_name(porte_output[1]), "--->", nome_porta, String@(Pointer@(porte + SizeOf(gb.Pointer))) If porte = 0 Then Print "Impossibile ottenere i nomi delle porte !" Free(Object.Address(Button1)) Quit Endif For b = 0 To 1 err = jack_connect(client, jack_port_name(porte_output[b]), String@(Pointer@(porte + (CInt(b) * SizeOf(gb.Pointer))))) If err <> 0 Then Print "Impossibile connettere le porte !" Next End Private Procedure CreaLibjk() ' Salva il codice sorgente della nostra libreria dinamica .so, e poi la crea File.Save("/tmp/jk.c", "#include <string.h>\n" & "#include <jack/jack.h>" & "\n\n" & "jack_port_t **input_port;\n" & "jack_port_t **output_port;\n" & "jack_client_t *client;" & "\n\n" & "int process (jack_nframes_t, void *);" & "\n\n" & "int process (jack_nframes_t nframes, void *arg) {\n" " int i;\n" & " jack_default_audio_sample_t *in, *out;\n" & " for (i = 0; i < 2; i++) {\n" & " in = jack_port_get_buffer (input_port[i], nframes);\n" & " out = jack_port_get_buffer (output_port[i], nframes);\n\n" & " memcpy (out, in, sizeof (jack_default_audio_sample_t) * nframes);\n}\n\n" & " return 0;\n}\n" & "\n\n" & "void Invoca_Callback (jack_client_t *cl, jack_port_t **it, jack_port_t **ot) {\n" & " client = cl;\n" & " input_port = it;\n" & " output_port = ot;\n\n" & " jack_set_process_callback (client, process, 0);\n}") Shell "gcc -o /tmp/libjk.so /tmp/jk.c -shared -fPIC -ljack" Wait End Public Sub Button2_Click() jack_client_close(client) End