aboutsummaryrefslogtreecommitdiff
path: root/desiredata/src/s_audio_jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'desiredata/src/s_audio_jack.c')
-rw-r--r--desiredata/src/s_audio_jack.c354
1 files changed, 0 insertions, 354 deletions
diff --git a/desiredata/src/s_audio_jack.c b/desiredata/src/s_audio_jack.c
deleted file mode 100644
index 8f851e2c..00000000
--- a/desiredata/src/s_audio_jack.c
+++ /dev/null
@@ -1,354 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#define PD_PLUSPLUS_FACE
-#include "desire.h"
-using namespace desire;
-#include "m_simd.h"
-#include <jack/jack.h>
-#include <regex.h>
-#include <errno.h>
-#define MAX_CLIENTS 100
-#define NUM_JACK_PORTS 32
-#define BUF_JACK 4096
-static jack_nframes_t jack_out_max;
-#define JACK_OUT_MAX 64
-static jack_nframes_t jack_filled = 0;
-static float jack_outbuf[NUM_JACK_PORTS*BUF_JACK];
-static float jack_inbuf[NUM_JACK_PORTS*BUF_JACK];
-static int jack_started = 0;
-static jack_port_t * input_port[NUM_JACK_PORTS];
-static jack_port_t *output_port[NUM_JACK_PORTS];
-static int outport_count = 0;
-static jack_client_t *jack_client = 0;
-char *jack_client_names[MAX_CLIENTS];
-static int jack_dio_error;
-static int jack_scheduler;
-pthread_mutex_t jack_mutex;
-pthread_cond_t jack_sem;
-t_int jack_save_connection_state(t_int* dummy);
-static void jack_restore_connection_state();
-void run_all_idle_callbacks();
-
-static int process (jack_nframes_t nframes, void *arg) {
- jack_out_max = max(int(nframes),JACK_OUT_MAX);
- if (jack_filled >= nframes) {
- if (jack_filled != nframes) post("Partial read");
- for (int j=0; j<sys_outchannels; j++) {
- float *out = (float *)jack_port_get_buffer(output_port[j], nframes);
- memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof(float)*nframes);
- }
- for (int j=0; j<sys_inchannels; j++) {
- float *in = (float *)jack_port_get_buffer( input_port[j], nframes);
- memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof(float)*nframes);
- }
- jack_filled -= nframes;
- } else { /* PD could not keep up ! */
- if (jack_started) jack_dio_error = 1;
- for (int j=0; j<outport_count; j++) {
- float *out = (float *)jack_port_get_buffer (output_port[j], nframes);
- memset(out, 0, sizeof (float) * nframes);
- }
- memset(jack_outbuf,0,sizeof(jack_outbuf));
- jack_filled = 0;
- }
- /* tb: wait in the scheduler: pthread_cond_broadcast(&jack_sem); */
- return 0;
-}
-
-void sys_peakmeters();
-extern int sys_meters; /* true if we're metering */
-static int dspticks_per_jacktick;
-static void (*copyblock)(t_sample *dst,t_sample *src,int n);
-static void (*zeroblock)(t_sample *dst,int n);
-extern int canvas_dspstate;
-
-static int cb_process (jack_nframes_t nframes, void *arg) {
- int timeout = int(nframes * 1e6 / sys_dacsr);
- if (canvas_dspstate == 0) {
- /* dsp is switched off, the audio is open ... */
- for (int j=0; j<sys_outchannels; j++) {
- t_sample *out = (t_sample *)jack_port_get_buffer (output_port[j], nframes);
- zeroblock(out, dspticks_per_jacktick * sys_dacblocksize);
- }
- return 0;
- }
- int status = sys_timedlock(timeout);
- if (status) {
- if (status == ETIMEDOUT) {error("timeout %d", (timeout)); sys_log_error(ERR_SYSLOCK); return 0;}
- else {post("sys_timedlock returned %d", status); return 0;}
- }
- for (int i = 0; i != dspticks_per_jacktick; ++i) {
- for (int j=0; j<sys_inchannels; j++) {
- t_sample *in = (t_sample *)jack_port_get_buffer(input_port[j], nframes);
- copyblock(sys_soundin + j * sys_dacblocksize, in + i * sys_dacblocksize, sys_dacblocksize);
- }
- sched_tick(sys_time + sys_time_per_dsp_tick);
- for (int j=0; j<sys_outchannels; j++) {
- t_sample *out = (t_sample *)jack_port_get_buffer(output_port[j], nframes);
- copyblock(out + i * sys_dacblocksize, sys_soundout + j * sys_dacblocksize, sys_dacblocksize);
- }
- if (sys_meters) sys_peakmeters();
- zeroblock(sys_soundout, sys_outchannels * sys_dacblocksize);
- }
- run_all_idle_callbacks();
- sys_unlock();
- return 0;
-}
-
-static int jack_srate (jack_nframes_t srate, void *arg) {
- sys_dacsr = srate;
- return 0;
-}
-
-static void jack_close_audio(void);
-static int jack_ignore_graph_callback = 0;
-static t_int jack_shutdown_handler(t_int* none) {
- error("jack kicked us out ... trying to reconnect");
- jack_ignore_graph_callback = 1;
- jack_close_audio();
- /* try to reconnect to jack server */
- jack_open_audio(sys_inchannels, sys_outchannels, int(sys_dacsr), jack_scheduler);
- jack_restore_connection_state();
- jack_ignore_graph_callback = 0;
- return 0;
-}
-
-/* register idle callback in scheduler */
-static void jack_shutdown (void *arg) {sys_callback(jack_shutdown_handler,0,0);}
-static int jack_graph_order_callback(void* arg) {sys_callback(jack_save_connection_state,0,0); return 0;}
-
-static char** jack_get_clients() {
- int num_clients = 0;
- regex_t port_regex;
- const char **jack_ports = jack_get_ports(jack_client, "", "", 0);
- regcomp(&port_regex, "^[^:]*", REG_EXTENDED);
- jack_client_names[0] = 0;
- /* Build a list of clients from the list of ports */
- for (int i=0; jack_ports[i] != 0; i++) {
- regmatch_t match_info;
- char tmp_client_name[100];
- /* extract the client name from the port name, using a regex that parses the clientname:portname syntax */
- regexec(&port_regex, jack_ports[i], 1, &match_info, 0);
- memcpy(tmp_client_name, &jack_ports[i][match_info.rm_so], match_info.rm_eo-match_info.rm_so);
- tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0';
- /* do we know about this port's client yet? */
- int client_seen = 0;
- for (int j=0; j<num_clients; j++) if (strcmp(tmp_client_name, jack_client_names[j])==0) client_seen = 1;
- if (!client_seen) {
- jack_client_names[num_clients] = (char*)getbytes(strlen(tmp_client_name) + 1);
- /* The alsa_pcm client should go in spot 0. If this is the alsa_pcm client AND we are NOT about to put
- it in spot 0 put it in spot 0 and move whatever was already in spot 0 to the end. */
- if (strcmp("alsa_pcm",tmp_client_name)==0 && num_clients>0) {
- /* alsa_pcm goes in spot 0 */
- char* tmp = jack_client_names[num_clients];
- jack_client_names[num_clients] = jack_client_names[0];
- jack_client_names[0] = tmp;
- strcpy(jack_client_names[0], tmp_client_name);
- } else {
- /* put the new client at the end of the client list */
- strcpy(jack_client_names[num_clients], tmp_client_name);
- }
- num_clients++;
- }
- }
- /* for (int i=0; i<num_clients; i++) post("client: %s",jack_client_names[i]); */
- free(jack_ports);
- return jack_client_names;
-}
-
-/* Wire up all the ports of one client. */
-static int jack_connect_ports(char *client) {
- char regex_pattern[100];
- static int entered = 0;
- if (entered) return 0;
- entered = 1;
- if (strlen(client) > 96) return -1;
- sprintf(regex_pattern, "%s:.*", client);
- const char **jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsOutput);
- if (jack_ports)
- for (int i=0;jack_ports[i] != 0 && i < sys_inchannels;i++)
- if (jack_connect(jack_client, jack_ports[i], jack_port_name(input_port[i])))
- error("cannot connect input ports %s -> %s", jack_ports[i],jack_port_name(input_port[i]));
- free(jack_ports);
- jack_ports = jack_get_ports(jack_client, regex_pattern, 0, JackPortIsInput);
- if (jack_ports)
- for (int i=0;jack_ports[i] != 0 && i < sys_outchannels;i++)
- if (jack_connect(jack_client, jack_port_name(output_port[i]), jack_ports[i]))
- error("cannot connect output ports %s -> %s",jack_port_name(output_port[i]),jack_ports[i]);
- free(jack_ports);
- return 0;
-}
-
-static void jack_error(const char *desc) {}
-
-int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler);
-int jack_open_audio( int inchans, int outchans, int rate, int scheduler) {
- jack_dio_error = 0;
- if (inchans==0 && outchans==0) return 0;
- int ret = jack_open_audio_2(inchans,outchans,rate,scheduler);
- if (ret) sys_setscheduler(0);
- return ret;
-}
-
-int jack_open_audio_2(int inchans, int outchans, int rate, int scheduler) {
- char port_name[80] = "";
- int new_jack = 0;
- if (outchans > NUM_JACK_PORTS) {post("%d output ports not supported, setting to %d",outchans, NUM_JACK_PORTS); outchans = NUM_JACK_PORTS;}
- if ( inchans > NUM_JACK_PORTS) {post( "%d input ports not supported, setting to %d", inchans, NUM_JACK_PORTS); inchans = NUM_JACK_PORTS;}
- if (jack_client && scheduler != sys_getscheduler()) {jack_client_close(jack_client); jack_client = 0;}
- sys_setscheduler(scheduler);
- jack_scheduler = scheduler;
- /* set block copy/zero functions */
- if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) {
- copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec_simd;
- zeroblock = &zerovec_simd;
- } else {
- copyblock = (void (*)(t_sample *,t_sample *,int))&copyvec;
- zeroblock = &zerovec;
- }
- /* try to become a client of the JACK server (we allow two pd's)*/
- if (!jack_client) {
- int client_iterator = 0;
- do {
- sprintf(port_name,"pure_data_%d",client_iterator);
- client_iterator++;
- } while (((jack_client = jack_client_new (port_name)) == 0) && client_iterator < 2);
- // jack spits out enough messages already, do not warn
- if (!jack_client) {sys_inchannels = sys_outchannels = 0; return 1;}
- jack_get_clients();
- /* tell the JACK server to call `process()' whenever there is work to be done.
- tb: adapted for callback based scheduling */
- if (scheduler == 1) {
- dspticks_per_jacktick = jack_get_buffer_size(jack_client) / sys_schedblocksize;
- jack_set_process_callback (jack_client, cb_process, 0);
- } else jack_set_process_callback (jack_client, process, 0);
- jack_set_error_function (jack_error);
-#ifdef JACK_XRUN
- jack_set_xrun_callback (jack_client, jack_xrun, 0);
-#endif
- jack_set_graph_order_callback(jack_client, jack_graph_order_callback, 0);
- /* tell the JACK server to call `srate()' whenever the sample rate of the system changes. */
- jack_set_sample_rate_callback (jack_client, jack_srate, 0);
- /* tell the JACK server to call `jack_shutdown()' if
- it ever shuts down, either entirely, or if it just decides to stop calling us. */
- jack_on_shutdown (jack_client, jack_shutdown, 0);
- for (int j=0;j<NUM_JACK_PORTS;j++) {input_port[j]=0; output_port[j]=0;}
- new_jack = 1;
- }
- /* display the current sample rate. once the client is activated
- (see below), you should rely on your own sample rate callback (see above) for this value. */
- int srate = jack_get_sample_rate (jack_client);
- sys_dacsr = srate;
- /* create the ports */
- for (int j=0; j<inchans; j++) {
- sprintf(port_name, "input%d", j);
- if (!input_port[j]) input_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
- }
- for (int j=0; j<outchans; j++) {
- sprintf(port_name, "output%d", j);
- if (!output_port[j]) output_port[j] = jack_port_register(jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
- }
- outport_count = outchans;
- /* tell the JACK server that we are ready to roll */
- if (new_jack) {
- if (jack_activate (jack_client)) {error("cannot activate client"); sys_inchannels = sys_outchannels = 0; return 1;}
- memset(jack_outbuf,0,sizeof(jack_outbuf));
- if (jack_client_names[0]) jack_connect_ports(jack_client_names[0]);
- pthread_mutex_init(&jack_mutex,0);
- pthread_cond_init(&jack_sem,0);
- }
- /* tb: get advance from jack server */
- sys_schedadvance = int((float)jack_port_get_total_latency(jack_client,output_port[0]) * 1000. / sys_dacsr * 1000);
- return 0;
-}
-
-static void jack_close_audio() {
- if (!jack_client) return;
- jack_deactivate(jack_client);
- jack_started = 0;
- jack_client_close(jack_client);
- jack_client = 0;
- for (int i=0; i<NUM_JACK_PORTS; i++) {input_port[i] = 0; output_port[i] = 0;}
-}
-
-int jack_send_dacs() {
- int rtnval = SENDDACS_YES;
- int timeref = int(sys_getrealtime());
- if (!jack_client) return SENDDACS_NO;
- if (!sys_inchannels && !sys_outchannels) return SENDDACS_NO;
- if (jack_dio_error) {sys_log_error(ERR_RESYNC); jack_dio_error = 0;}
- if (jack_filled >= jack_out_max) return SENDDACS_NO;
- /* tb: wait in the scheduler: pthread_cond_wait(&jack_sem,&jack_mutex); */
- jack_started = 1;
- float *fp = sys_soundout;
- for (int j=0; j<sys_outchannels; j++, fp += sys_dacblocksize)
- memcpy(jack_outbuf + j*BUF_JACK + jack_filled, fp, sys_dacblocksize*sizeof(float));
- fp = sys_soundin;
- for (int j=0; j<sys_inchannels; j++, fp += sys_dacblocksize)
- memcpy(fp, jack_inbuf + j*BUF_JACK + jack_filled, sys_dacblocksize*sizeof(float));
- int timenow = int(sys_getrealtime());
- if (timenow-timeref > sys_sleepgrain*1e-6) rtnval = SENDDACS_SLEPT;
- memset(sys_soundout,0,sys_dacblocksize*sizeof(float)*sys_outchannels);
- jack_filled += sys_dacblocksize;
- return rtnval;
-}
-
-void jack_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) {
- *canmulti = 0; /* supports multiple devices */
- int ndev = 1;
- for (int i=0; i<ndev; i++) {
- sprintf( indevlist + i*devdescsize, "JACK");
- sprintf(outdevlist + i*devdescsize, "JACK");
- }
- *nindevs = *noutdevs = ndev;
-}
-
-void jack_listdevs () {error("device listing not implemented for jack yet");}
-
-static const char ** jack_in_connections[NUM_JACK_PORTS]; /* ports connected to the inputs */
-static const char **jack_out_connections[NUM_JACK_PORTS]; /* ports connected to the outputs */
-
-/* tb: save the current state of pd's jack connections */
-t_int jack_save_connection_state(t_int* dummy) {
- if (jack_ignore_graph_callback) return 0;
- for (int i=0; i<NUM_JACK_PORTS; i++) {
- if ( jack_in_connections[i]) free( jack_in_connections[i]);
- jack_in_connections[i] = i< sys_inchannels ? jack_port_get_all_connections(jack_client, input_port[i]) : 0;
- if (jack_out_connections[i]) free(jack_out_connections[i]);
- jack_out_connections[i]= i<sys_outchannels ? jack_port_get_all_connections(jack_client, output_port[i]) : 0;
- }
- return 0;
-}
-
-/* todo: don't try to connect twice if we're both input and output host */
-static void jack_restore_connection_state() {
- post("restoring connections");
- for (int i=0; i<NUM_JACK_PORTS; i++) {
- /* restoring the inputs connections */
- if (jack_in_connections[i]) {
- for (int j=0;;j++) {
- const char *port = jack_in_connections[i][j];
- if (!port) break; /* we've connected all incoming ports */
- int status = jack_connect(jack_client, port, jack_port_name(input_port[i]));
- if (status) error("cannot connect input ports %s -> %s", port, jack_port_name(input_port[i]));
- }
- }
- /* restoring the output connections */
- if (jack_out_connections[i]) {
- for (int j=0;;j++) {
- const char *port = jack_out_connections[i][j];
- if (!port) break; /* we've connected all outgoing ports */
- int status = jack_connect(jack_client, jack_port_name(output_port[i]), port);
- if (status) error("cannot connect output ports %s -> %s", jack_port_name(output_port[i]), port);
- }
- }
- }
-}
-
-struct t_audioapi jack_api = {
- 0 /*jack_open_audio*/,
- jack_close_audio,
- jack_send_dacs,
- jack_getdevs,
-};