aboutsummaryrefslogtreecommitdiff
path: root/pd/src/s_audio_jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'pd/src/s_audio_jack.c')
-rw-r--r--pd/src/s_audio_jack.c517
1 files changed, 328 insertions, 189 deletions
diff --git a/pd/src/s_audio_jack.c b/pd/src/s_audio_jack.c
index 990a7a8c..79d4692e 100644
--- a/pd/src/s_audio_jack.c
+++ b/pd/src/s_audio_jack.c
@@ -11,25 +11,24 @@
#include <jack/jack.h>
#include <regex.h>
-
#define MAX_CLIENTS 100
-#define NUM_JACK_PORTS 128 /* seems like higher values give bad xrun problems */
+#define MAX_JACK_PORTS 128 /* seems like higher values give bad xrun problems */
#define BUF_JACK 4096
static jack_nframes_t jack_out_max;
#define JACK_OUT_MAX 64
static jack_nframes_t jack_filled = 0;
-static t_sample jack_outbuf[NUM_JACK_PORTS*BUF_JACK];
-static t_sample jack_inbuf[NUM_JACK_PORTS*BUF_JACK];
+static t_sample *jack_outbuf;
+static t_sample *jack_inbuf;
static int jack_started = 0;
-static jack_port_t *input_port[NUM_JACK_PORTS];
-static jack_port_t *output_port[NUM_JACK_PORTS];
+static jack_port_t *input_port[MAX_JACK_PORTS];
+static jack_port_t *output_port[MAX_JACK_PORTS];
static int outport_count = 0;
static jack_client_t *jack_client = NULL;
char *jack_client_names[MAX_CLIENTS];
static int jack_dio_error;
-
+static t_audiocallback jack_callback;
pthread_mutex_t jack_mutex;
pthread_cond_t jack_sem;
@@ -38,56 +37,114 @@ pthread_cond_t jack_sem;
static int
process (jack_nframes_t nframes, void *arg)
{
- int j;
- jack_default_audio_sample_t *out, *in;
-
- if (nframes > JACK_OUT_MAX) jack_out_max = nframes;
- else jack_out_max = JACK_OUT_MAX;
- if (jack_filled >= nframes) {
- if (jack_filled != nframes) fprintf(stderr,"Partial read");
- /* hmm, how to find out whether 't_sample' and 'jack_default_audio_sample_t' are actually the same type??? */
- if(sizeof(t_sample)==sizeof(jack_default_audio_sample_t))
+ int j;
+ jack_default_audio_sample_t *out, *in;
+
+ pthread_mutex_lock(&jack_mutex);
+ if (nframes > JACK_OUT_MAX) jack_out_max = nframes;
+ else jack_out_max = JACK_OUT_MAX;
+ if (jack_filled >= nframes)
+ {
+ if (jack_filled != nframes)
+ fprintf(stderr,"Partial read\n");
+ /* hmm, how to find out whether 't_sample' and
+ 'jack_default_audio_sample_t' are actually the same type??? */
+ if (sizeof(t_sample)==sizeof(jack_default_audio_sample_t))
+ {
+ for (j = 0; j < sys_outchannels; j++)
+ {
+ out = jack_port_get_buffer (output_port[j], nframes);
+ memcpy(out, jack_outbuf + (j * BUF_JACK),
+ sizeof (jack_default_audio_sample_t) * nframes);
+ }
+ for (j = 0; j < sys_inchannels; j++)
+ {
+ in = jack_port_get_buffer( input_port[j], nframes);
+ memcpy(jack_inbuf + (j * BUF_JACK), in,
+ sizeof (jack_default_audio_sample_t) * nframes);
+ }
+ }
+ else
+ {
+ unsigned int frame=0;
+ t_sample*data;
+ for (j = 0; j < sys_outchannels; j++)
+ {
+ out = jack_port_get_buffer (output_port[j], nframes);
+ data = jack_outbuf + (j * BUF_JACK);
+ for(frame=0; frame<nframes; frame++)
{
- for (j = 0; j < sys_outchannels; j++) {
- out = jack_port_get_buffer (output_port[j], nframes);
- memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof (jack_default_audio_sample_t) * nframes);
- }
- for (j = 0; j < sys_inchannels; j++) {
- in = jack_port_get_buffer( input_port[j], nframes);
- memcpy(jack_inbuf + (j * BUF_JACK), in, sizeof (jack_default_audio_sample_t) * nframes);
- }
- }
- else
+ *out++=*data++;
+ }
+ }
+ for (j = 0; j < sys_inchannels; j++)
+ {
+ in = jack_port_get_buffer( input_port[j], nframes);
+ data = jack_inbuf + (j * BUF_JACK);
+ for(frame=0; frame<nframes; frame++)
{
- unsigned int frame=0;
- t_sample*data;
- for (j = 0; j < sys_outchannels; j++) {
- out = jack_port_get_buffer (output_port[j], nframes);
- data=jack_outbuf + (j * BUF_JACK);
- for(frame=0; frame<nframes; frame++) {
- *out++=*data++;
- }
- }
- for (j = 0; j < sys_inchannels; j++) {
- in = jack_port_get_buffer( input_port[j], nframes);
- data=jack_inbuf+(j*BUF_JACK);
- for(frame=0; frame<nframes; frame++) {
- *data++=*in++;
- }
- }
+ *data++=*in++;
}
- jack_filled -= nframes;
- } else { /* PD could not keep up ! */
- if (jack_started) jack_dio_error = 1;
- for (j = 0; j < outport_count; j++) {
- out = jack_port_get_buffer (output_port[j], nframes);
- memset(out, 0, sizeof (float) * nframes);
- }
- memset(jack_outbuf,0,sizeof(jack_outbuf));
- jack_filled = 0;
+ }
}
- pthread_cond_broadcast(&jack_sem);
- return 0;
+ jack_filled -= nframes;
+ }
+ else
+ { /* PD could not keep up ! */
+ if (jack_started) jack_dio_error = 1;
+ for (j = 0; j < outport_count; j++)
+ {
+ out = jack_port_get_buffer (output_port[j], nframes);
+ memset(out, 0, sizeof (float) * nframes);
+ memset(jack_outbuf + j * BUF_JACK, 0, BUF_JACK * sizeof(t_sample));
+ }
+ jack_filled = 0;
+ }
+ pthread_cond_broadcast(&jack_sem);
+ pthread_mutex_unlock(&jack_mutex);
+ return 0;
+}
+
+static int callbackprocess(jack_nframes_t nframes, void *arg)
+{
+ int chan, j, k;
+ unsigned int n;
+ jack_default_audio_sample_t *out[MAX_JACK_PORTS], *in[MAX_JACK_PORTS], *jp;
+
+ if (nframes % DEFDACBLKSIZE)
+ {
+ fprintf(stderr, "jack: nframes %d not a multiple of blocksize %d\n",
+ nframes, DEFDACBLKSIZE);
+ nframes -= (nframes % DEFDACBLKSIZE);
+ }
+ for (chan = 0; chan < sys_inchannels; chan++)
+ in[chan] = jack_port_get_buffer(input_port[chan], nframes);
+ for (chan = 0; chan < sys_outchannels; chan++)
+ out[chan] = jack_port_get_buffer(output_port[chan], nframes);
+ for (n = 0; n < nframes; n += DEFDACBLKSIZE)
+ {
+ t_sample *fp;
+ for (chan = 0; chan < sys_inchannels; chan++)
+ {
+ for (fp = sys_soundin + chan*DEFDACBLKSIZE,
+ jp = in[chan] + n, j=0; j < DEFDACBLKSIZE; j++)
+ *fp++ = *jp++;
+ }
+ for (chan = 0; chan < sys_outchannels; chan++)
+ {
+ for (fp = sys_soundout + chan*DEFDACBLKSIZE,
+ j = 0; j < DEFDACBLKSIZE; j++)
+ *fp++ = 0;
+ }
+ (*jack_callback)();
+ for (chan = 0; chan < sys_outchannels; chan++)
+ {
+ for (fp = sys_soundout + chan*DEFDACBLKSIZE, jp = out[chan] + n,
+ j=0; j < DEFDACBLKSIZE; j++)
+ *jp++ = *fp++;
+ }
+ }
+ return 0;
}
static int
@@ -97,11 +154,19 @@ jack_srate (jack_nframes_t srate, void *arg)
return 0;
}
+
+void glob_audio_setapi(void *dummy, t_floatarg f);
+
static void
jack_shutdown (void *arg)
{
- /* Ignore for now */
- // exit (1);
+ error("JACK: server shut down");
+
+ jack_deactivate (jack_client);
+ //jack_client_close(jack_client); /* likely to hang if the server shut down */
+ jack_client = NULL;
+
+ glob_audio_setapi(NULL, API_NONE); // set pd_whichapi 0
}
static int jack_xrun(void* arg) {
@@ -128,6 +193,9 @@ static char** jack_get_clients(void)
regmatch_t match_info;
char tmp_client_name[100];
+ if(num_clients>=MAX_CLIENTS)break;
+
+
/* 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 );
@@ -166,7 +234,6 @@ static char** jack_get_clients(void)
strcpy( jack_client_names[ num_clients ], tmp_client_name );
}
num_clients++;
-
}
}
@@ -196,7 +263,7 @@ static int jack_connect_ports(char* client)
if (jack_ports)
for (i=0;jack_ports[i] != NULL && i < sys_inchannels;i++)
if (jack_connect (jack_client, jack_ports[i], jack_port_name (input_port[i])))
- fprintf (stderr, "cannot connect input ports %s -> %s\n", jack_ports[i],jack_port_name (input_port[i]));
+ error ("JACK: cannot connect input ports %s -> %s", jack_ports[i],jack_port_name (input_port[i]));
@@ -205,7 +272,7 @@ static int jack_connect_ports(char* client)
if (jack_ports)
for (i=0;jack_ports[i] != NULL && i < sys_outchannels;i++)
if (jack_connect (jack_client, jack_port_name (output_port[i]), jack_ports[i]))
- fprintf (stderr, "cannot connect output ports %s -> %s\n", jack_port_name (output_port[i]),jack_ports[i]);
+ error( "JACK: cannot connect output ports %s -> %s", jack_port_name (output_port[i]),jack_ports[i]);
@@ -214,172 +281,244 @@ static int jack_connect_ports(char* client)
}
-void pd_jack_error_callback(const char *desc) {
+static void pd_jack_error_callback(const char *desc) {
+ error("JACKerror: %s", desc);
return;
}
-
int
-jack_open_audio(int inchans, int outchans, int rate)
-
+jack_open_audio(int inchans, int outchans, int rate, t_audiocallback callback)
{
- int j;
- char port_name[80] = "";
- int client_iterator = 0;
- int new_jack = 0;
- int srate;
+ int j;
+ char port_name[80] = "";
+ char client_name[80] = "";
- jack_dio_error = 0;
-
- if ((inchans == 0) && (outchans == 0)) return 0;
+ int client_iterator = 0;
+ int new_jack = 0;
+ int srate;
+ jack_status_t status;
- if (outchans > NUM_JACK_PORTS) {
- fprintf(stderr,"%d output ports not supported, setting to %d\n",outchans, NUM_JACK_PORTS);
- outchans = NUM_JACK_PORTS;
- }
+ if (NULL==jack_client_new)
+ {
+ fprintf(stderr,"JACK framework not available\n");
+ return 1;
+ }
+
+ jack_dio_error = 0;
+
+ if ((inchans == 0) && (outchans == 0)) return 0;
- if (inchans > NUM_JACK_PORTS) {
- fprintf(stderr,"%d input ports not supported, setting to %d\n",inchans, NUM_JACK_PORTS);
- inchans = NUM_JACK_PORTS;
+ if (outchans > MAX_JACK_PORTS) {
+ error("JACK: %d output ports not supported, setting to %d",
+ outchans, MAX_JACK_PORTS);
+ outchans = MAX_JACK_PORTS;
+ }
+
+ if (inchans > MAX_JACK_PORTS) {
+ error("JACK: %d input ports not supported, setting to %d",
+ inchans, MAX_JACK_PORTS);
+ inchans = MAX_JACK_PORTS;
+ }
+ /* try to become a client of the JACK server */
+ /* if no JACK server exists, start a default one (jack_client_open() does that for us... */
+ if (!jack_client) {
+ do {
+ sprintf(client_name,"pure_data_%d",client_iterator);
+ client_iterator++;
+ jack_client = jack_client_open (client_name, JackNullOption, &status, NULL);
+ if (status & JackServerFailed) {
+ error("JACK: unable to connect to JACK server");
+ jack_client=NULL;
+ break;
+ }
+ } while (status & JackNameNotUnique);
+
+ if(status) {
+ if (status & JackServerStarted) {
+ verbose(1, "JACK: started server");
+ } else {
+ error("JACK: server returned status %d", status);
+ }
}
+ verbose(1, "JACK: started server as '%s'", client_name);
- /* try to become a client of the JACK server (we allow two pd's)*/
if (!jack_client) {
- do {
- sprintf(port_name,"pure_data_%d",client_iterator);
- client_iterator++;
- } while (((jack_client = jack_client_new (port_name)) == 0) && client_iterator < 2);
-
-
- if (!jack_client) { // jack spits out enough messages already, do not warn
+ /* jack spits out enough messages already, do not warn */
sys_inchannels = sys_outchannels = 0;
return 1;
- }
-
- jack_get_clients();
-
- /* tell the JACK server to call `process()' whenever
- there is work to be done.
- */
-
- jack_set_process_callback (jack_client, process, 0);
-
- jack_set_error_function (pd_jack_error_callback);
-
+ }
+
+ sys_inchannels = inchans;
+ sys_outchannels = outchans;
+ if (jack_inbuf)
+ free(jack_inbuf);
+ if (sys_inchannels)
+ jack_inbuf = calloc(sizeof(t_sample), sys_inchannels * BUF_JACK);
+ if (jack_outbuf)
+ free(jack_outbuf);
+ if (sys_outchannels)
+ jack_outbuf = calloc(sizeof(t_sample), sys_outchannels * BUF_JACK);
+
+ jack_get_clients();
+
+ /* tell the JACK server to call `process()' whenever
+ there is work to be done.
+ */
+ jack_callback = callback;
+ jack_set_process_callback (jack_client,
+ (callback? callbackprocess : process), 0);
+
+ jack_set_error_function (pd_jack_error_callback);
+
#ifdef JACK_XRUN
- jack_set_xrun_callback (jack_client, jack_xrun, NULL);
+ jack_set_xrun_callback (jack_client, jack_xrun, NULL);
#endif
-
- /* 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 (j=0;j<NUM_JACK_PORTS;j++) {
- input_port[j]=NULL;
- output_port[j] = NULL;
- }
-
- 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.
+ /* tell the JACK server to call `srate()' whenever
+ the sample rate of the system changes.
*/
-
- srate = jack_get_sample_rate (jack_client);
- sys_dacsr = srate;
-
- /* create the ports */
-
- for (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);
+
+ 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 (j=0; j<sys_inchannels; j++)
+ input_port[j]=NULL;
+ for (j=0; j<sys_outchannels; j++)
+ output_port[j] = NULL;
+
+ 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.
+ */
+
+ srate = jack_get_sample_rate (jack_client);
+ sys_dacsr = srate;
+
+ /* create the ports */
+
+ for (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);
+ if (!input_port[j]) {
+ error("JACK: can only register %d input ports (instead of requested %d)", j, inchans);
+ sys_inchannels = inchans = j;
+ break;
}
+ }
- for (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;
+ for (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);
+ if (!output_port[j]) {
+ error("JACK: can only register %d output ports (instead of requested %d)", j, outchans);
+ sys_outchannels = outchans = j;
+ break;
+ }
+ }
+ outport_count = outchans;
- /* tell the JACK server that we are ready to roll */
-
- if (new_jack) {
- if (jack_activate (jack_client)) {
- fprintf (stderr, "cannot activate client\n");
+ /* 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])
+ }
+
+ for (j = 0; j < outchans; j++)
+ memset(jack_outbuf + j * BUF_JACK, 0,
+ BUF_JACK * sizeof(t_sample));
+
+ if (jack_client_names[0])
jack_connect_ports(jack_client_names[0]);
- pthread_mutex_init(&jack_mutex,NULL);
- pthread_cond_init(&jack_sem,NULL);
- }
- return 0;
+ pthread_mutex_init(&jack_mutex, NULL);
+ pthread_cond_init(&jack_sem, NULL);
+ }
+ return 0;
}
void jack_close_audio(void)
-
{
- jack_started = 0;
+ if (jack_client){
+ jack_deactivate (jack_client);
+ jack_client_close(jack_client);
+ }
+
+ jack_client=NULL;
+ jack_started = 0;
+
+ pthread_cond_broadcast(&jack_sem);
+
+ pthread_cond_destroy(&jack_sem);
+ pthread_mutex_destroy(&jack_mutex);
+ if (jack_inbuf)
+ free(jack_inbuf), jack_inbuf = 0;
+ if (jack_outbuf)
+ free(jack_outbuf), jack_outbuf = 0;
+
}
int jack_send_dacs(void)
{
- t_sample * fp;
- int j;
- int rtnval = SENDDACS_YES;
- int timenow;
- int timeref = 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)
- pthread_cond_wait(&jack_sem,&jack_mutex);
-
- jack_started = 1;
-
- fp = sys_soundout;
- for (j = 0; j < sys_outchannels; j++) {
- memcpy(jack_outbuf + (j * BUF_JACK) + jack_filled,fp, DEFDACBLKSIZE*sizeof(t_sample));
- fp += DEFDACBLKSIZE;
- }
- fp = sys_soundin;
- for (j = 0; j < sys_inchannels; j++) {
- memcpy(fp, jack_inbuf + (j * BUF_JACK) + jack_filled, DEFDACBLKSIZE*sizeof(t_sample));
- fp += DEFDACBLKSIZE;
- }
+ t_sample * fp;
+ int j;
+ int rtnval = SENDDACS_YES;
+ int timenow;
+ int timeref = 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;
+ }
+ pthread_mutex_lock(&jack_mutex);
+ if (jack_filled >= jack_out_max)
+ pthread_cond_wait(&jack_sem,&jack_mutex);
- if ((timenow = sys_getrealtime()) - timeref > 0.002)
- {
- rtnval = SENDDACS_SLEPT;
- }
+ if (!jack_client)
+ {
+ pthread_mutex_unlock(&jack_mutex);
+ return SENDDACS_NO;
+ }
+ jack_started = 1;
- memset(sys_soundout,0,DEFDACBLKSIZE*sizeof(t_sample)*sys_outchannels);
- jack_filled += DEFDACBLKSIZE;
- return rtnval;
+ fp = sys_soundout;
+ for (j = 0; j < sys_outchannels; j++)
+ {
+ memcpy(jack_outbuf + (j * BUF_JACK) + jack_filled, fp,
+ DEFDACBLKSIZE*sizeof(t_sample));
+ fp += DEFDACBLKSIZE;
+ }
+ fp = sys_soundin;
+ for (j = 0; j < sys_inchannels; j++)
+ {
+ memcpy(fp, jack_inbuf + (j * BUF_JACK) + jack_filled,
+ DEFDACBLKSIZE*sizeof(t_sample));
+ fp += DEFDACBLKSIZE;
+ }
+ jack_filled += DEFDACBLKSIZE;
+ pthread_mutex_unlock(&jack_mutex);
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ rtnval = SENDDACS_SLEPT;
+ }
+ memset(sys_soundout, 0, DEFDACBLKSIZE*sizeof(t_sample)*sys_outchannels);
+ return rtnval;
}
void jack_getdevs(char *indevlist, int *nindevs,