#include #include #include #define PD_PLUSPLUS_FACE #include "desire.h" using namespace desire; #include "m_simd.h" #include #include #include #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; j0) { /* 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 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))©vec_simd; zeroblock = &zerovec_simd; } else { copyblock = (void (*)(t_sample *,t_sample *,int))©vec; 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= 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_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 %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, };