26 #include <jack/statistics.h> 27 #include <jack/jack.h> 28 #include <jack/thread.h> 32 #ifdef HAVE_JACK_SESSION 43 static const char *jack_amp_postfix =
"_amp";
44 static const char *jack_fx_postfix =
"_fx";
47 static const char *default_jack_instancename =
"gx_head";
48 return default_jack_instancename;
56 static unsigned int rt_watchdog_counter;
59 #define SCHED_IDLE SCHED_OTHER // non-linux systems 62 static void *rt_watchdog_run(
void *p) {
63 struct sched_param spar;
64 spar.sched_priority = 0;
65 pthread_setschedparam(pthread_self(),
SCHED_IDLE, &spar);
73 static int rt_watchdog_limit = 0;
75 static void rt_watchdog_start() {
76 if (rt_watchdog_limit > 0) {
78 pthread_attr_init(&attr);
80 if (pthread_create(&pthr, &attr, rt_watchdog_run, 0)) {
83 pthread_attr_destroy(&attr);
87 static inline bool rt_watchdog_check_alive(
unsigned int bs,
unsigned int sr) {
88 if (rt_watchdog_limit > 0) {
107 bypass_insert(false),
108 #ifdef HAVE_JACK_SESSION
110 session_event_ins(0),
111 session_callback_seen(0),
114 connection_changed(),
124 xrun_msg_blocked(false),
134 for(
int i = 0;i<5;i++) mmessage.
send_cc[i] =
false;
135 connection_queue.
new_data.connect(sigc::mem_fun(*
this, &GxJack::fetch_connection_data));
136 client_change_rt.connect(client_change);
138 sigc::mem_fun(*
this, &GxJack::cleanup_slot));
139 xrun.connect(sigc::mem_fun(
this, &GxJack::report_xrun));
147 rt_watchdog_limit = limit;
194 void GxJack::write_jack_port_connections(
199 const char** pl = jack_port_get_connections(pc.
port);
201 for (
const char **p = pl; *p; p++) {
203 w.
write(make_clientvar(*p));
211 for (list<string>::const_iterator i = pc.
conn.begin(); i != pc.
conn.end(); ++i) {
220 write_jack_port_connections(w,
"input",
ports.
input);
221 write_jack_port_connections(w,
"output1",
ports.
output1);
222 write_jack_port_connections(w,
"output2",
ports.
output2);
226 write_jack_port_connections(w,
"insert_in",
ports.
insert_in,
true);
238 int jackopt = (startserver ? JackNullOption : JackNoStartServer);
240 if (client_instance.empty()) {
243 jackopt |= JackUseExactName;
256 jack_status_t jackstat;
257 #ifdef HAVE_JACK_SESSION 260 client = jack_client_open(
261 client_name.c_str(), JackOptions(jackopt | JackSessionID),
264 if (ServerName.empty()) {
267 client = jack_client_open(
client_name.c_str(), JackOptions(jackopt | JackServerName),
268 &jackstat, ServerName.c_str());
272 if (ServerName.empty()) {
275 client = jack_client_open(
client_name.c_str(), JackOptions(jackopt | JackServerName),
276 &jackstat, ServerName.c_str());
284 std::string name = jack_get_client_name(
client);
285 std::string generated_suffix = name.substr(
client_name.size());
286 std::string base = name.substr(0,
client_name.size()-strlen(jack_amp_postfix));
287 client_instance = base + generated_suffix;
290 #ifdef HAVE_JACK_SESSION 294 JackOptions(jackopt | JackSessionID | JackUseExactName),
297 if (ServerName.empty()) {
300 JackOptions(jackopt | JackUseExactName ), &jackstat);
304 JackOptions(jackopt | JackUseExactName | JackServerName),
305 &jackstat, ServerName.c_str());
309 if (ServerName.empty()) {
312 JackOptions(jackopt | JackUseExactName), &jackstat);
316 JackOptions(jackopt | JackUseExactName | JackServerName),
317 &jackstat, ServerName.c_str());
321 jack_client_close(
client);
327 if (!(jackstat & JackServerFailed)) {
328 if ((jackstat & JackServerError) && (jackopt & JackUseExactName)) {
331 boost::format(_(
"can't get requested jack instance name '%1%'"))
336 _(
"unknown jack server communication error"));
345 if (wait_after_connect) {
346 usleep(wait_after_connect);
348 jack_sr = jack_get_sample_rate(
client);
351 boost::format(_(
"The jack sample rate is %1%/sec")) % jack_sr);
353 jack_bs = jack_get_buffer_size(
client);
356 boost::format(_(
"The jack buffer size is %1%/frames ... "))
359 insert_buffer =
new float[jack_bs];
365 gx_jack_init_port_connection(opt);
372 void GxJack::cleanup_slot(
bool otherthread) {
384 jack_client_close(
client);
396 void GxJack::gx_jack_cleanup() {
409 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT) 415 jack_client_close(
client);
419 delete[] insert_buffer;
420 insert_buffer = NULL;
430 if (!gx_jack_init(startserver, wait_after_connect, opt)) {
451 std::string GxJack::make_clientvar(
const std::string& s) {
452 std::size_t n = s.find(
':');
457 return "%A" + s.substr(n);
460 return "%F" + s.substr(n);
465 std::string GxJack::replace_clientvar(
const std::string& s) {
466 if (s.compare(0, 3,
"%A:") == 0) {
469 if (s.compare(0, 3,
"%F:") == 0) {
483 for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
494 for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
502 for (list<string>::iterator i = l1.begin(); i != l1.end(); ++i) {
506 for (list<string>::iterator i = l2.begin(); i != l2.end(); ++i) {
522 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT) 525 for (list<string>::iterator i = lmo.begin(); i != lmo.end(); ++i) {
533 bool ifound =
false, ofound =
false;
534 for (list<string>::iterator i = lins_in.begin(); i != lins_in.end(); ++i) {
535 int rc = jack_connect(
client_insert, replace_clientvar(*i).c_str(),
537 if (rc == 0 || rc == EEXIST) {
542 for (list<string>::iterator i = lins_out.begin(); i != lins_out.end(); ++i) {
543 std::string port = replace_clientvar(*i);
544 if (!jack_port_connected_to(port_a, port.c_str())) {
547 if (rc == 0 || rc == EEXIST) {
554 if (!ifound || !ofound) {
566 void GxJack::gx_jack_callbacks() {
568 jack_set_xrun_callback(
client, gx_jack_xrun_callback,
this);
569 jack_set_sample_rate_callback(
client, gx_jack_srate_callback,
this);
570 jack_on_shutdown(
client, shutdown_callback_client,
this);
571 jack_on_shutdown(
client_insert, shutdown_callback_client_insert,
this);
572 jack_set_buffer_size_callback(
client, gx_jack_buffersize_callback,
this);
573 jack_set_port_registration_callback(
client, gx_jack_portreg_callback,
this);
574 jack_set_port_connect_callback(
client, gx_jack_portconn_callback,
this);
575 #ifdef HAVE_JACK_SESSION 576 if (jack_set_session_callback_fp) {
577 jack_set_session_callback_fp(
client, gx_jack_session_callback,
this);
578 jack_set_session_callback_fp(
client_insert, gx_jack_session_callback_ins,
this);
584 client,
"in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
586 client,
"midi_in_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
588 client,
"out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
589 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT) 591 client,
"midi_out_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
598 client_insert,
"in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
600 client_insert,
"out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
602 client_insert,
"out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
604 engine.
init(jack_sr, jack_bs, SCHED_FIFO,
605 jack_client_real_time_priority(
client));
606 jack_set_process_callback(
client, gx_jack_process,
this);
607 jack_set_process_callback(
client_insert, gx_jack_insert_process,
this);
608 if (jack_activate(
client) != 0) {
610 _(
"Jack Activation"),
611 string(_(
"Can't activate JACK gx_amp client")));
615 string(_(
"Can't activate JACK gx_amp_fx client")));
626 for(
int i = 0;i<5;i++) {
628 unsigned char* midi_send = jack_midi_event_reserve(buf, i, mmessage.
me_num[i]);
631 if (mmessage.
me_num[i] == 2) {
633 midi_send[1] = mmessage.
pg_num[i];
635 midi_send[0] = mmessage.
cc_num[i] | 0;
636 }
else if (mmessage.
me_num[i] == 3) {
637 midi_send[2] = mmessage.
bg_num[i];
639 midi_send[1] = mmessage.
pg_num[i];
641 midi_send[0] = mmessage.
cc_num[i] | 0;
656 jack_midi_clear_buffer(midi_port_buf);
658 return midi_port_buf;
661 static inline float *get_float_buf(jack_port_t *port, jack_nframes_t nframes) {
662 return static_cast<float *
>(jack_port_get_buffer(port, nframes));
665 inline void GxJack::check_overload() {
666 if (!rt_watchdog_check_alive(jack_bs, jack_sr)) {
673 int __rt_func GxJack::gx_jack_process(jack_nframes_t nframes,
void *arg) {
678 self.check_overload();
680 self.transport_state = jack_transport_query (
self.
client, &
self.
current);
683 self.engine.mono_chain.process(
688 if (
self.bypass_insert) {
689 memcpy(
self.insert_buffer, obuf, nframes*
sizeof(
float));
693 self.engine.controller_map.compute_midi_in(
699 self.old_transport_state =
self.transport_state;
703 void *buf =
self.get_midi_buffer(nframes);
704 self.process_midi_cc(buf, nframes);
707 self.engine.mono_chain.post_rt_finished();
713 int __rt_func GxJack::gx_jack_insert_process(jack_nframes_t nframes,
void *arg) {
718 self.check_overload();
722 if (!
self.bypass_insert) {
725 ibuf =
self.insert_buffer;
727 self.engine.stereo_chain.process(
733 self.engine.stereo_chain.post_rt_finished();
743 : ring(jack_ringbuffer_create(20*sizeof(
PortConnData))),
750 _(
"Jack init"), _(
"can't get memory for ringbuffer"));
752 jack_ringbuffer_mlock(ring);
756 jack_ringbuffer_free(ring);
765 size_t sz = jack_ringbuffer_write(ring, reinterpret_cast<const char*>(&p),
sizeof(p));
766 if (sz !=
sizeof(p)) {
769 jack_ringbuffer_write_advance(ring, sz);
777 jack_ringbuffer_reset(ring);
782 size_t sz = jack_ringbuffer_read(ring, reinterpret_cast<char*>(p),
sizeof(*p));
786 assert(sz ==
sizeof(*p));
787 jack_ringbuffer_read_advance(ring, sz);
791 void GxJack::fetch_connection_data() {
794 const char** port = jack_port_get_connections(ports.input.port);
804 bool fetched = connection_queue.pop(&p);
816 void GxJack::gx_jack_portconn_callback(jack_port_id_t a, jack_port_id_t b,
int connect,
void* arg) {
821 jack_port_t* port_a = jack_port_by_id(
self.client, a);
822 jack_port_t* port_b = jack_port_by_id(
self.client, b);
823 if (!port_a || !port_b) {
826 self.connection_queue.push(jack_port_name(port_a), jack_port_name(port_b), connect);
835 for(
int i = 0;i<5;i++) {
836 if (!mmessage.send_cc[i]) {
837 mmessage.send_cc[i] =
true;
838 mmessage.cc_num[i] = _cc;
839 mmessage.pg_num[i] = _pg;
840 mmessage.bg_num[i] = _bgn;
841 mmessage.me_num[i] = _num;
850 void GxJack::gx_jack_portreg_callback(jack_port_id_t pid,
int reg,
void* arg) {
855 jack_port_t* port = jack_port_by_id(
self.client, pid);
856 if (!port || jack_port_is_mine(
self.client, port)) {
859 self.connection_queue.portchange();
865 int GxJack::gx_jack_srate_callback(jack_nframes_t samplerate,
void* arg) {
867 if (
self.jack_sr == samplerate) {
871 self.jack_sr = samplerate;
872 self.engine.set_samplerate(samplerate);
879 int GxJack::gx_jack_buffersize_callback(jack_nframes_t nframes,
void* arg) {
881 if (
self.jack_bs == nframes) {
885 self.jack_bs = nframes;
886 self.engine.set_buffersize(nframes);
888 self.buffersize_change();
890 delete[]
self.insert_buffer;
891 self.insert_buffer = NULL;
892 self.insert_buffer =
new float[
self.jack_bs];
897 void GxJack::gx_jack_shutdown_callback() {
903 void GxJack::shutdown_callback_client(
void *arg) {
907 self.client_change_rt();
909 if (
self.client_insert) {
910 jack_client_close(
self.client_insert);
911 self.client_insert = 0;
913 self.gx_jack_shutdown_callback();
916 void GxJack::shutdown_callback_client_insert(
void *arg) {
920 jack_client_close(
self.client);
922 self.client_change_rt();
924 self.gx_jack_shutdown_callback();
927 void GxJack::report_xrun_clear() {
928 xrun_msg_blocked =
false;
931 void GxJack::report_xrun() {
932 if (xrun_msg_blocked) {
935 xrun_msg_blocked =
true;
936 Glib::signal_timeout().connect_once(
937 sigc::mem_fun(
this, &GxJack::report_xrun_clear), 100);
940 (boost::format(_(
" delay of at least %1% microsecs")) % last_xrun).str());
944 int GxJack::gx_jack_xrun_callback(
void* arg) {
949 self.last_xrun = jack_get_xrun_delayed_usecs(
self.client);
950 if (!
self.engine.mono_chain.is_stopped()) {
961 #ifdef HAVE_JACK_SESSION 962 jack_set_session_callback_type GxJack::jack_set_session_callback_fp =
963 reinterpret_cast<jack_set_session_callback_type
>(
964 dlsym(RTLD_DEFAULT,
"jack_set_session_callback"));
965 jack_get_uuid_for_client_name_type GxJack::jack_get_uuid_for_client_name_fp =
966 reinterpret_cast<jack_get_uuid_for_client_name_type
>(
967 dlsym(RTLD_DEFAULT,
"jack_get_uuid_for_client_name"));
968 jack_client_get_uuid_type GxJack::jack_client_get_uuid_fp =
969 reinterpret_cast<jack_client_get_uuid_type
>(
970 dlsym(RTLD_DEFAULT,
"jack_client_get_uuid"));
972 int GxJack::return_last_session_event() {
973 jack_session_event_t *
event = get_last_session_event();
975 session_callback_seen += 1;
976 jack_session_reply(client, event);
977 jack_session_event_free(event);
980 return session_callback_seen;
983 int GxJack::return_last_session_event_ins() {
984 jack_session_event_t *
event = get_last_session_event_ins();
986 session_callback_seen -= 1;
987 jack_session_reply(client_insert, event);
988 jack_session_event_free(event);
991 return session_callback_seen;
994 string GxJack::get_uuid_insert() {
997 if (jack_client_get_uuid_fp) {
998 uuid = jack_client_get_uuid_fp(client_insert);
999 }
else if (jack_get_uuid_for_client_name_fp) {
1000 uuid = jack_get_uuid_for_client_name_fp(
1001 client_insert, client_insert_name.c_str());
1012 void GxJack::gx_jack_session_callback(jack_session_event_t *event,
void *arg) {
1014 jack_session_event_t *np = 0;
1022 void GxJack::gx_jack_session_callback_ins(jack_session_event_t *event,
void *arg) {
1024 jack_session_event_t *np = 0;
void gx_print_info(const char *, const std::string &)
void set_jack_down(bool v)
void begin_array(bool nl=false)
StereoModuleChain stereo_chain
void end_array(bool nl=false)
virtual void wait_ramp_down_finished()
const Glib::ustring & get_jack_instancename() const
void read_connections(gx_system::JsonParser &jp)
void push(const char *a, const char *b, bool conn)
MonoModuleChain mono_chain
void process_midi_cc(void *buf, jack_nframes_t nframes)
void init(unsigned int samplerate, unsigned int buffersize, int policy, int priority)
static void rt_watchdog_set_limit(int limit)
PortConnection midi_output
GxJack(gx_engine::GxEngine &engine_)
PortConnection insert_out
Glib::Dispatcher connection
void write_key(const char *p, bool nl=false)
const Glib::ustring & get_jack_servername() const
int atomic_get(volatile int &p)
void gx_print_fatal(const char *, const std::string &)
Glib::Dispatcher new_data
void gx_print_error(const char *, const std::string &)
static string get_default_instancename()
void * get_midi_buffer(jack_nframes_t nframes)
void set_jack_exit(bool v)
void send_midi_cc(int cc_num, int pgm_num, int bgn, int num)
virtual void overload(OverloadType tp, const char *reason)
const Glib::ustring & get_jack_input() const
void write_connections(gx_system::JsonWriter &w)
void begin_object(bool nl=false)
static GxExit & get_instance()
Glib::ustring get_jack_output(unsigned int n) const
virtual void set_rack_changed()
bool get_jack_noconnect() const
jack_transport_state_t transport_state
jack_client_t * client_insert
const Glib::ustring & get_jack_uuid2() const
const Glib::ustring & get_jack_midi() const
PortConnection midi_input
void atomic_inc(volatile int *p)
void gx_print_warning(const char *, const std::string &)
virtual void start_ramp_down()
sigc::signal< void, bool > & signal_exit()
void atomic_set(volatile int *p, int v)
Glib::Dispatcher shutdown
string current_value() const
const Glib::ustring & get_jack_uuid() const
Glib::Dispatcher portchange
void set_stateflag(StateFlag flag)
bool atomic_compare_and_exchange(volatile int *p, int oldv, int newv)
bool gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions &opt)
void clear_stateflag(StateFlag flag)
Glib::Dispatcher session_ins
token next(token expect=no_token)
void write(float v, bool nl=false)
jack_transport_state_t old_transport_state
string client_insert_name
void end_object(bool nl=false)