aboutsummaryrefslogtreecommitdiff
path: root/pd/src/s_audio_jack.c
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2003-09-23 00:21:28 +0000
committerThomas Grill <xovo@users.sourceforge.net>2003-09-23 00:21:28 +0000
commit64fdb009695828b788fce074135b20a5e52c5fc4 (patch)
treea05144197dd339721b6d4a3a0927f7596e8872b6 /pd/src/s_audio_jack.c
parenta30193fcd726552364de74984b200be2c30723e7 (diff)
imported version 0.37-0
svn path=/trunk/; revision=1016
Diffstat (limited to 'pd/src/s_audio_jack.c')
-rw-r--r--pd/src/s_audio_jack.c350
1 files changed, 350 insertions, 0 deletions
diff --git a/pd/src/s_audio_jack.c b/pd/src/s_audio_jack.c
new file mode 100644
index 00000000..6f9937db
--- /dev/null
+++ b/pd/src/s_audio_jack.c
@@ -0,0 +1,350 @@
+
+
+/* ----------------------- Experimental routines for jack -------------- */
+#ifdef USEAPI_JACK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <m_pd.h>
+#include <s_stuff.h>
+#include <jack/jack.h>
+#include <regex.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 jack_client_t *jack_client;
+char *jack_client_names[MAX_CLIENTS];
+
+pthread_mutex_t jack_mutex;
+pthread_cond_t jack_sem;
+
+static int
+process (jack_nframes_t nframes, void *arg)
+{
+ int j;
+ float *out;
+ float *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");
+
+ for (j = 0; j < sys_outchannels; j++) {
+ out = jack_port_get_buffer (output_port[j], nframes);
+ memcpy(out, jack_outbuf + (j * BUF_JACK), sizeof (float) * 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 (float) * nframes);
+ }
+ jack_filled -= nframes;
+ } else { /* PD could not keep up ! */
+ if (jack_started) sys_log_error(ERR_RESYNC);
+ for (j = 0; j < sys_outchannels; 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;
+}
+
+static int
+srate (jack_nframes_t srate, void *arg)
+{
+ printf ("jack: sample rate %ld/sec\n", srate);
+ sys_dacsr = srate;
+ return 0;
+}
+
+static void
+jack_shutdown (void *arg)
+{
+ /* Ignore for now */
+ // exit (1);
+}
+
+static int jack_xrun(void* arg) {
+ sys_log_error(ERR_DACSLEPT);
+ return 0;
+}
+
+
+static char** jack_get_clients(void)
+{
+ const char **jack_ports;
+ int i,j;
+ int num_clients = 0;
+ regex_t port_regex;
+ jack_ports = jack_get_ports( jack_client, "", "", 0 );
+ regcomp( &port_regex, "^[^:]*", REG_EXTENDED );
+
+ jack_client_names[0] = NULL;
+
+ /* Build a list of clients from the list of ports */
+ for( i = 0; jack_ports[i] != NULL; i++ )
+ {
+ int client_seen;
+ 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? */
+ client_seen = 0;
+
+ for( j = 0; j < num_clients; j++ )
+ if( strcmp( tmp_client_name, jack_client_names[j] ) == 0 )
+ client_seen = 1;
+
+ if( client_seen == 0 )
+ {
+ 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 )
+ {
+ char* tmp;
+ /* alsa_pcm goes in spot 0 */
+ 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 (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]; /* its always the same, ... */
+ int i;
+ const char **jack_ports;
+
+ if (strlen(client) > 96) return -1;
+
+ sprintf( regex_pattern, "%s:.*", client );
+
+ jack_ports = jack_get_ports( jack_client, regex_pattern,
+ NULL, JackPortIsOutput);
+ 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]));
+
+
+
+ jack_ports = jack_get_ports( jack_client, regex_pattern,
+ NULL, JackPortIsInput);
+ 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]);
+
+
+
+ free(jack_ports);
+ return 0;
+}
+
+
+void jack_error(const char *desc) {
+ return;
+}
+
+
+int
+jack_open_audio(int inchans, int outchans, int rate)
+
+{
+ int j;
+ char port_name[80] = "";
+ int samplerate;
+ int client_iterator = 0;
+
+ if ((inchans == 0) && (outchans == 0)) return 0;
+
+ post("Testing for Jack");
+ 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 (inchans > NUM_JACK_PORTS) {
+ fprintf(stderr,"%d input ports not supported, setting to %d\n",inchans, NUM_JACK_PORTS);
+ inchans = NUM_JACK_PORTS;
+ }
+
+ /* try to become a client of the JACK server (we allow two pd's)*/
+
+ 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
+ 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 (jack_error);
+
+#ifdef JACK_XRUN
+ 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, 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);
+
+
+ /* 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.
+ */
+
+ samplerate = jack_get_sample_rate (jack_client);
+
+ /* create the ports */
+
+ for (j = 0; j < inchans; j++) {
+ sprintf(port_name, "input%d", j);
+ input_port[j] = jack_port_register (jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
+ }
+ for (j = 0; j < outchans; j++) {
+ sprintf(port_name, "output%d", j);
+ output_port[j] = jack_port_register (jack_client, port_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ }
+
+ /* tell the JACK server that we are ready to roll */
+
+ if (jack_activate (jack_client)) {
+ fprintf (stderr, "cannot activate client");
+ 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,NULL);
+ pthread_cond_init(&jack_sem,NULL);
+
+ post("using JACK audio interface");
+ return 0;
+}
+
+void jack_close_audio(void)
+
+{
+ jack_started = 0;
+ /* ignore for now */
+}
+
+int jack_send_dacs(void)
+
+{
+ float * 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_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(float));
+ fp += DEFDACBLKSIZE;
+ }
+ fp = sys_soundin;
+ for (j = 0; j < sys_inchannels; j++) {
+ memcpy(fp, jack_inbuf + (j * BUF_JACK) + jack_filled, DEFDACBLKSIZE*sizeof(float));
+ fp += DEFDACBLKSIZE;
+ }
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ rtnval = SENDDACS_SLEPT;
+ }
+
+ memset(sys_soundout,0,DEFDACBLKSIZE*sizeof(float)*sys_outchannels);
+ jack_filled += DEFDACBLKSIZE;
+ return rtnval;
+}
+
+void jack_listdevs( void)
+{
+ post("device listing not implemented for jack yet\n");
+}
+
+#endif /* JACK */