Guitarix
gx_jack.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * --------------------------------------------------------------------------
19  *
20  * This is the gx_head interface to the jackd audio / midi server
21  *
22  * --------------------------------------------------------------------------
23  */
24 
25 #include <errno.h> // NOLINT
26 #include <jack/statistics.h> // NOLINT
27 #include <jack/jack.h> // NOLINT
28 #include <jack/thread.h> // NOLINT
29 
30 #include "engine.h" // NOLINT
31 
32 #ifdef HAVE_JACK_SESSION
33 #include <dlfcn.h>
34 #endif
35 
36 
37 namespace gx_jack {
38 
39 /****************************************************************
40  ** class GxJack
41  ****************************************************************/
42 
43 static const char *jack_amp_postfix = "_amp";
44 static const char *jack_fx_postfix = "_fx";
45 
47  static const char *default_jack_instancename = "gx_head";
48  return default_jack_instancename;
49 }
50 
51 
52 /****************************************************************
53  ** rt_watchdog
54  */
55 
56 static unsigned int rt_watchdog_counter;
57 
58 #ifndef SCHED_IDLE
59 #define SCHED_IDLE SCHED_OTHER // non-linux systems
60 #endif
61 
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);
66  while (true) {
67  gx_system::atomic_set(&rt_watchdog_counter, 0);
68  usleep(1000000);
69  }
70  return NULL;
71 }
72 
73 static int rt_watchdog_limit = 0;
74 
75 static void rt_watchdog_start() {
76  if (rt_watchdog_limit > 0) {
77  pthread_attr_t attr;
78  pthread_attr_init(&attr);
79  pthread_t pthr;
80  if (pthread_create(&pthr, &attr, rt_watchdog_run, 0)) {
81  gx_print_error("watchdog", _("can't create thread"));
82  }
83  pthread_attr_destroy(&attr);
84  }
85 }
86 
87 static inline bool rt_watchdog_check_alive(unsigned int bs, unsigned int sr) {
88  if (rt_watchdog_limit > 0) {
89  if (gx_system::atomic_get(rt_watchdog_counter) > rt_watchdog_limit*(2*sr)/bs) {
90  return false;
91  }
92  gx_system::atomic_inc(&rt_watchdog_counter);
93  }
94  return true;
95 }
96 
97 
98 /****************************************************************
99  ** GxJack ctor, dtor
100  */
101 
103  : sigc::trackable(),
104  engine(engine_),
105  jack_is_down(false),
106  jack_is_exit(true),
107  bypass_insert(false),
108 #ifdef HAVE_JACK_SESSION
109  session_event(0),
110  session_event_ins(0),
111  session_callback_seen(0),
112 #endif
113  connection_queue(),
114  connection_changed(),
115  buffersize_change(),
116  client_change_rt(),
117  client_change(),
118  client_instance(),
119  jack_sr(),
120  jack_bs(),
121  insert_buffer(NULL),
122  xrun(),
123  last_xrun(0),
124  xrun_msg_blocked(false),
125  ports(),
126  client(0),
127  client_insert(0),
128  client_name(),
130  session(),
131  session_ins(),
132  shutdown(),
133  connection() {
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);
137  GxExit::get_instance().signal_exit().connect(
138  sigc::mem_fun(*this, &GxJack::cleanup_slot));
139  xrun.connect(sigc::mem_fun(this, &GxJack::report_xrun));
140 }
141 
143  gx_jack_cleanup();
144 }
145 
147  rt_watchdog_limit = limit;
148  if (limit > 0) {
149  rt_watchdog_start();
150  }
151 }
152 
153 
154 /****************************************************************
155  ** load state, save state
156  */
157 
160  while (jp.peek() == gx_system::JsonParser::value_key) {
161  list<string> *i;
163  if (jp.current_value() == "input") {
164  i = &ports.input.conn;
165  } else if (jp.current_value() == "output1") {
166  i = &ports.output1.conn;
167  } else if (jp.current_value() == "output2") {
168  i = &ports.output2.conn;
169  } else if (jp.current_value() == "midi_input") {
170  i = &ports.midi_input.conn;
171  } else if (jp.current_value() == "midi_output") {
172  i = &ports.midi_output.conn;
173  } else if (jp.current_value() == "insert_out") {
174  i = &ports.insert_out.conn;
175  } else if (jp.current_value() == "insert_in") {
176  i = &ports.insert_in.conn;
177  } else {
179  _("recall state"),
180  _("unknown jack ports section: ") + jp.current_value());
181  jp.skip_object();
182  continue;
183  }
185  while (jp.peek() == gx_system::JsonParser::value_string) {
186  jp.next();
187  i->push_back(jp.current_value());
188  }
190  }
192 }
193 
194 void GxJack::write_jack_port_connections(
195  gx_system::JsonWriter& w, const char *key, const PortConnection& pc, bool replace) {
196  w.write_key(key);
197  w.begin_array();
198  if (client && pc.port) {
199  const char** pl = jack_port_get_connections(pc.port);
200  if (pl) {
201  for (const char **p = pl; *p; p++) {
202  if (replace) {
203  w.write(make_clientvar(*p));
204  } else {
205  w.write(*p);
206  }
207  }
208  free(pl);
209  }
210  } else {
211  for (list<string>::const_iterator i = pc.conn.begin(); i != pc.conn.end(); ++i) {
212  w.write(*i);
213  }
214  }
215  w.end_array(true);
216 }
217 
219  w.begin_object(true);
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);
223  write_jack_port_connections(w, "midi_input", ports.midi_input);
224  write_jack_port_connections(w, "midi_output", ports.midi_output);
225  write_jack_port_connections(w, "insert_out", ports.insert_out, true);
226  write_jack_port_connections(w, "insert_in", ports.insert_in, true);
227  w.end_object(true);
228 }
229 
230 
231 /****************************************************************
232  ** client connection init and cleanup
233  */
234 int GxJack::is_power_of_two (unsigned int x)
235 {
236  return ((x != 0) && ((x & (~x + 1)) == x));
237 }
238 
239 // ----- pop up a dialog for starting jack
240 bool GxJack::gx_jack_init(bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
241  AVOIDDENORMALS();
242  int jackopt = (startserver ? JackNullOption : JackNoStartServer);
243  client_instance = opt.get_jack_instancename();
244  if (client_instance.empty()) {
245  client_instance = get_default_instancename();
246  } else {
247  jackopt |= JackUseExactName;
248  }
249 
250  std::string ServerName = opt.get_jack_servername();
251 
252  set_jack_down(false);
253  set_jack_exit(true);
255 
256  //ports = JackPorts(); //FIXME
257 
258  client_name = client_instance + jack_amp_postfix;
259  client_insert_name = client_instance + jack_fx_postfix;
260  jack_status_t jackstat;
261 #ifdef HAVE_JACK_SESSION
262  // try to open jack gxjack.client
263  if (!opt.get_jack_uuid().empty()) {
264  client = jack_client_open(
265  client_name.c_str(), JackOptions(jackopt | JackSessionID),
266  &jackstat, opt.get_jack_uuid().c_str());
267  } else {
268  if (ServerName.empty()) {
269  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
270  } else {
271  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
272  &jackstat, ServerName.c_str());
273  }
274  }
275 #else
276  if (ServerName.empty()) {
277  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
278  } else {
279  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
280  &jackstat, ServerName.c_str());
281  }
282 #endif
283  // ----- only start the insert gxjack.client when the amp gxjack.client is true
284  if (client) {
285  // it is maybe not the 1st gx_head instance ?
286  // session handler can change name without setting JackNameNotUnique in return status; jack bug??
287  // this code depends on jackd only appending a suffix to make a client name unique
288  std::string name = jack_get_client_name(client);
289  std::string generated_suffix = name.substr(client_name.size());
290  std::string base = name.substr(0, client_name.size()-strlen(jack_amp_postfix));
291  client_instance = base + generated_suffix;
292  client_name = name;
293  client_insert_name = base + jack_fx_postfix + generated_suffix;
294 #ifdef HAVE_JACK_SESSION
295  if (!opt.get_jack_uuid2().empty()) {
296  client_insert = jack_client_open(
297  client_insert_name.c_str(),
298  JackOptions(jackopt | JackSessionID | JackUseExactName),
299  &jackstat, opt.get_jack_uuid2().c_str());
300  } else {
301  if (ServerName.empty()) {
302  client_insert = jack_client_open(
303  client_insert_name.c_str(),
304  JackOptions(jackopt | JackUseExactName ), &jackstat);
305  } else {
306  client_insert = jack_client_open(
307  client_insert_name.c_str(),
308  JackOptions(jackopt | JackUseExactName | JackServerName),
309  &jackstat, ServerName.c_str());
310  }
311  }
312 #else
313  if (ServerName.empty()) {
314  client_insert = jack_client_open(
315  client_insert_name.c_str(),
316  JackOptions(jackopt | JackUseExactName), &jackstat);
317  } else {
318  client_insert = jack_client_open(
319  client_insert_name.c_str(),
320  JackOptions(jackopt | JackUseExactName | JackServerName),
321  &jackstat, ServerName.c_str());
322  }
323 #endif
324  if (!client_insert) {
325  jack_client_close(client);
326  client = 0;
327  }
328  }
329 
330  if (!client) {
331  if (!(jackstat & JackServerFailed)) {
332  if ((jackstat & JackServerError) && (jackopt & JackUseExactName)) {
334  _("Jack Init"),
335  boost::format(_("can't get requested jack instance name '%1%'"))
336  % client_instance);
337  } else {
339  _("Jack Init"),
340  _("unknown jack server communication error"));
341  }
342  }
343  return false;
344  }
345 
346  // ----------------------------------
347  set_jack_down(false);
348 
349  if (wait_after_connect) {
350  usleep(wait_after_connect);
351  }
352  jack_sr = jack_get_sample_rate(client); // jack sample rate
354  _("Jack init"),
355  boost::format(_("The jack sample rate is %1%/sec")) % jack_sr);
356 
357  jack_bs = jack_get_buffer_size(client); // jack buffer size
358  if (!is_power_of_two(jack_bs)) {
360  _("Jack init"),
361  boost::format(_("The jack buffer size is %1%/frames is not power of two, Convolver wont run"))
362  % jack_bs);
363  } else {
365  _("Jack init"),
366  boost::format(_("The jack buffer size is %1%/frames ... "))
367  % jack_bs);
368  }
369 
370  // create buffer to bypass the insert ports
371  insert_buffer = new float[jack_bs];
372 
373  gx_jack_callbacks();
374  client_change(); // might load port connection definitions
375  if (opt.get_jack_uuid().empty() && !opt.get_jack_noconnect()) {
376  // when not loaded by session manager
377  gx_jack_init_port_connection(opt);
378  }
379  set_jack_exit(false);
380 
381  return true;
382 }
383 
384 void GxJack::cleanup_slot(bool otherthread) {
385  if (!otherthread) {
386  gx_jack_cleanup();
387  } else {
388  // called from other thread. Since most cleanup functions are
389  // not thread safe, just do minimal jack cleanup
390  if (client) {
391  if (!is_jack_down()) {
392  engine.start_ramp_down();
393  engine.wait_ramp_down_finished();
394  }
395  jack_deactivate(client);
396  jack_client_close(client);
397  client = 0;
398  }
399  if (client_insert) {
400  jack_deactivate(client_insert);
401  jack_client_close(client_insert);
402  client_insert = 0;
403  }
404  }
405 }
406 
407 // -----Function that cleans the jack stuff on shutdown
408 void GxJack::gx_jack_cleanup() {
409  if (!client || is_jack_down()) {
410  return;
411  }
412  engine.start_ramp_down();
413  engine.wait_ramp_down_finished();
414  set_jack_exit(true);
416  jack_deactivate(client);
417  jack_deactivate(client_insert);
418  jack_port_unregister(client, ports.input.port);
419  jack_port_unregister(client, ports.midi_input.port);
420  jack_port_unregister(client, ports.insert_out.port);
421 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
422  jack_port_unregister(client, ports.midi_output.port);
423 #endif
424  jack_port_unregister(client_insert, ports.insert_in.port);
425  jack_port_unregister(client_insert, ports.output1.port);
426  jack_port_unregister(client_insert, ports.output2.port);
427  jack_client_close(client);
428  client = 0;
429  jack_client_close(client_insert);
430  client_insert = 0;
431  delete[] insert_buffer;
432  insert_buffer = NULL;
433  client_change();
434 }
435 
436 // ---- Jack server connection / disconnection
437 bool GxJack::gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
438  if (connect) {
439  if (client) {
440  return true;
441  }
442  if (!gx_jack_init(startserver, wait_after_connect, opt)) {
443  return false;
444  }
445  engine.set_rack_changed();
447  } else {
448  if (!client) {
449  return true;
450  }
451  gx_jack_cleanup();
452  }
453  connection();
454  connection_queue.portchange();
455  return true;
456 }
457 
458 
459 /****************************************************************
460  ** port connections
461  */
462 
463 std::string GxJack::make_clientvar(const std::string& s) {
464  std::size_t n = s.find(':');
465  if (n == s.npos) {
466  return s; // no ':' in jack port name??
467  }
468  if (s.compare(0, n, client_name) == 0) {
469  return "%A" + s.substr(n);
470  }
471  if (s.compare(0, n, client_insert_name) == 0) {
472  return "%F" + s.substr(n);
473  }
474  return s;
475 }
476 
477 std::string GxJack::replace_clientvar(const std::string& s) {
478  if (s.compare(0, 3, "%A:") == 0) {
479  return client_name + s.substr(2);
480  }
481  if (s.compare(0, 3, "%F:") == 0) {
482  return client_insert_name + s.substr(2);
483  }
484  return s;
485 }
486 
487 // ----- connect ports if we know them
488 void GxJack::gx_jack_init_port_connection(const gx_system::CmdlineOptions& opt) {
489  // set autoconnect capture to user capture port
490  if (!opt.get_jack_input().empty()) {
491  jack_connect(client, opt.get_jack_input().c_str(),
492  jack_port_name(ports.input.port));
493  } else {
494  list<string>& l = ports.input.conn;
495  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
496  jack_connect(client, i->c_str(), jack_port_name(ports.input.port));
497  }
498  }
499 
500  // set autoconnect midi to user midi port
501  if (ports.midi_input.port && !opt.get_jack_midi().empty()) {
502  jack_connect(client, opt.get_jack_midi().c_str(),
503  jack_port_name(ports.midi_input.port));
504  } else {
505  list<string>& l = ports.midi_input.conn;
506  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
507  jack_connect(client, i->c_str(), jack_port_name(ports.midi_input.port));
508  }
509  }
510 
511  // set autoconnect to user playback ports
512  if (opt.get_jack_output(0).empty() && opt.get_jack_output(1).empty()) {
513  list<string>& l1 = ports.output1.conn;
514  for (list<string>::iterator i = l1.begin(); i != l1.end(); ++i) {
515  jack_connect(client_insert, jack_port_name(ports.output1.port), i->c_str());
516  }
517  list<string>& l2 = ports.output2.conn;
518  for (list<string>::iterator i = l2.begin(); i != l2.end(); ++i) {
519  jack_connect(client_insert, jack_port_name(ports.output2.port), i->c_str());
520  }
521  } else {
522  if (!opt.get_jack_output(0).empty()) {
523  jack_connect(client_insert,
524  jack_port_name(ports.output1.port),
525  opt.get_jack_output(0).c_str());
526  }
527  if (!opt.get_jack_output(1).empty()) {
528  jack_connect(client_insert,
529  jack_port_name(ports.output2.port),
530  opt.get_jack_output(1).c_str());
531  }
532  }
533 
534 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
535  // autoconnect midi output port
536  list<string>& lmo = ports.midi_output.conn;
537  for (list<string>::iterator i = lmo.begin(); i != lmo.end(); ++i) {
538  jack_connect(client, jack_port_name(ports.midi_output.port), i->c_str());
539  }
540 #endif
541 
542  // autoconnect to insert ports
543  list<string>& lins_in = ports.insert_in.conn;
544  list<string>& lins_out = ports.insert_out.conn;
545  bool ifound = false, ofound = false;
546  for (list<string>::iterator i = lins_in.begin(); i != lins_in.end(); ++i) {
547  int rc = jack_connect(client_insert, replace_clientvar(*i).c_str(),
548  jack_port_name(ports.insert_in.port));
549  if (rc == 0 || rc == EEXIST) {
550  ifound = true;
551  }
552  }
553  jack_port_t* port_a = jack_port_by_name(client, jack_port_name(ports.insert_out.port));
554  for (list<string>::iterator i = lins_out.begin(); i != lins_out.end(); ++i) {
555  std::string port = replace_clientvar(*i);
556  if (!jack_port_connected_to(port_a, port.c_str())) {
557  int rc = jack_connect(client, jack_port_name(ports.insert_out.port),
558  port.c_str());
559  if (rc == 0 || rc == EEXIST) {
560  ofound = true;
561  }
562  } else {
563  ofound = true;
564  }
565  }
566  if (!ifound || !ofound) {
567  jack_connect(client_insert, jack_port_name(ports.insert_out.port),
568  (client_insert_name+":in_0").c_str());
569  }
570 }
571 
572 
573 /****************************************************************
574  ** callback installation and port registration
575  */
576 
577 // ----- set gxjack.client callbacks and activate gxjack.client
578 void GxJack::gx_jack_callbacks() {
579  // ----- set the jack callbacks
580  jack_set_xrun_callback(client, gx_jack_xrun_callback, this);
581  jack_set_sample_rate_callback(client, gx_jack_srate_callback, this);
582  jack_on_shutdown(client, shutdown_callback_client, this);
583  jack_on_shutdown(client_insert, shutdown_callback_client_insert, this);
584  jack_set_buffer_size_callback(client, gx_jack_buffersize_callback, this);
585  jack_set_port_registration_callback(client, gx_jack_portreg_callback, this);
586  jack_set_port_connect_callback(client, gx_jack_portconn_callback, this);
587 #ifdef HAVE_JACK_SESSION
588  if (jack_set_session_callback_fp) {
589  jack_set_session_callback_fp(client, gx_jack_session_callback, this);
590  jack_set_session_callback_fp(client_insert, gx_jack_session_callback_ins, this);
591  }
592 #endif
593 
594  // register ports for gx_amp
595  ports.input.port = jack_port_register(
596  client, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
597  ports.midi_input.port = jack_port_register(
598  client, "midi_in_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
599  ports.insert_out.port = jack_port_register(
600  client, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
601 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
602  ports.midi_output.port = jack_port_register(
603  client, "midi_out_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
604 #else
605  ports.midi_output.port = 0;
606 #endif
607 
608  // register ports for gx_amp_fx
609  ports.insert_in.port = jack_port_register(
610  client_insert, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
611  ports.output1.port = jack_port_register(
612  client_insert, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
613  ports.output2.port = jack_port_register(
614  client_insert, "out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
615 
616  engine.init(jack_sr, jack_bs, SCHED_FIFO,
617  jack_client_real_time_priority(client));
618  jack_set_process_callback(client, gx_jack_process, this);
619  jack_set_process_callback(client_insert, gx_jack_insert_process, this);
620  if (jack_activate(client) != 0) {
622  _("Jack Activation"),
623  string(_("Can't activate JACK gx_amp client")));
624  }
625  if (jack_activate(client_insert) != 0) {
626  gx_print_fatal(_("Jack Activation"),
627  string(_("Can't activate JACK gx_amp_fx client")));
628  }
629 }
630 
631 
632 /****************************************************************
633  ** jack process callbacks
634  */
635 
636 void __rt_func GxJack::process_midi_cc(void *buf, jack_nframes_t nframes) {
637  // midi CC output processing
638  for(int i = 0;i<5;i++) {
639  if (mmessage.send_cc[i]) {
640  unsigned char* midi_send = jack_midi_event_reserve(buf, i, mmessage.me_num[i]);
641 
642  if (midi_send) {
643  if (mmessage.me_num[i] == 2) {
644  // program value
645  midi_send[1] = mmessage.pg_num[i];
646  // controller+ channel
647  midi_send[0] = mmessage.cc_num[i] | 0;
648  } else if (mmessage.me_num[i] == 3) {
649  midi_send[2] = mmessage.bg_num[i];
650  // program value
651  midi_send[1] = mmessage.pg_num[i];
652  // controller+ channel
653  midi_send[0] = mmessage.cc_num[i] | 0;
654  }
655  }
656  mmessage.send_cc[i] = false;
657  }
658  }
659 }
660 
661 // must only be used inside gx_jack_process
662 void *GxJack::get_midi_buffer(jack_nframes_t nframes) {
663  if (!ports.midi_output.port) {
664  return 0;
665  }
666  void *midi_port_buf = jack_port_get_buffer(ports.midi_output.port, nframes);
667  if (midi_port_buf) {
668  jack_midi_clear_buffer(midi_port_buf);
669  }
670  return midi_port_buf;
671 }
672 
673 static inline float *get_float_buf(jack_port_t *port, jack_nframes_t nframes) {
674  return static_cast<float *>(jack_port_get_buffer(port, nframes));
675 }
676 
677 inline void GxJack::check_overload() {
678  if (!rt_watchdog_check_alive(jack_bs, jack_sr)) {
679  engine.overload(gx_engine::EngineControl::ov_User, "watchdog thread");
680  }
681 }
682 
683 // ----- main jack process method gx_amp, mono -> mono
684 // RT process thread
685 int __rt_func GxJack::gx_jack_process(jack_nframes_t nframes, void *arg) {
687  GxJack& self = *static_cast<GxJack*>(arg);
688  if (!self.is_jack_exit()) {
689  if (!self.engine.mono_chain.is_stopped()) {
690  self.check_overload();
691  }
692  self.transport_state = jack_transport_query (self.client, &self.current);
693  // gx_head DSP computing
694  float *obuf = get_float_buf(self.ports.insert_out.port, nframes);
695  self.engine.mono_chain.process(
696  nframes,
697  get_float_buf(self.ports.input.port, nframes),
698  obuf);
699 
700  if (self.bypass_insert) {
701  memcpy(self.insert_buffer, obuf, nframes*sizeof(float));
702  }
703  // midi input processing
704  if (self.ports.midi_input.port) {
705  self.engine.controller_map.compute_midi_in(
706  jack_port_get_buffer(self.ports.midi_input.port, nframes), arg);
707  }
708  // jack transport support
709  if ( self.transport_state != self.old_transport_state) {
710  self.engine.controller_map.process_trans(self.transport_state);
711  self.old_transport_state = self.transport_state;
712  }
713  }
714  // midi CC output processing
715  void *buf = self.get_midi_buffer(nframes);
716  self.process_midi_cc(buf, nframes);
717 
719  self.engine.mono_chain.post_rt_finished();
720  return 0;
721 }
722 
723 // ----- main jack process method, gx_fx_amp, mono -> stereo
724 // RT process_insert thread
725 int __rt_func GxJack::gx_jack_insert_process(jack_nframes_t nframes, void *arg) {
726  GxJack& self = *static_cast<GxJack*>(arg);
728  if (!self.is_jack_exit()) {
729  if (!self.engine.stereo_chain.is_stopped()) {
730  self.check_overload();
731  }
732  // gx_head DSP computing
733  float *ibuf = NULL;
734  if (!self.bypass_insert) {
735  ibuf = get_float_buf(self.ports.insert_in.port, nframes);
736  } else {
737  ibuf = self.insert_buffer;
738  }
739  self.engine.stereo_chain.process(
740  nframes, ibuf, ibuf,
741  get_float_buf(self.ports.output1.port, nframes),
742  get_float_buf(self.ports.output2.port, nframes));
743  }
745  self.engine.stereo_chain.post_rt_finished();
746  return 0;
747 }
748 
749 
750 /****************************************************************
751  ** port connection callback
752  */
753 
755  : ring(jack_ringbuffer_create(20*sizeof(PortConnData))), // just a number...
756  send_changes(false),
757  overflow(false),
758  new_data(),
759  portchange() {
760  if (!ring) {
762  _("Jack init"), _("can't get memory for ringbuffer"));
763  }
764  jack_ringbuffer_mlock(ring);
765 }
766 
768  jack_ringbuffer_free(ring);
769 }
770 
771 void PortConnRing::push(const char *a, const char *b, bool conn) {
772  if (is_overflow()) {
773  return;
774  }
775  if (send_changes) {
776  PortConnData p(a, b, conn);
777  size_t sz = jack_ringbuffer_write(ring, reinterpret_cast<const char*>(&p), sizeof(p));
778  if (sz != sizeof(p)) {
779  set_overflow();
780  } else {
781  jack_ringbuffer_write_advance(ring, sz);
782  }
783  }
784  new_data();
785 }
786 
788  if (is_overflow()) {
789  jack_ringbuffer_reset(ring);
790  portchange();
791  clear_overflow();
792  return false;
793  }
794  size_t sz = jack_ringbuffer_read(ring, reinterpret_cast<char*>(p), sizeof(*p));
795  if (sz == 0) {
796  return false;
797  }
798  assert(sz == sizeof(*p));
799  jack_ringbuffer_read_advance(ring, sz);
800  return true;
801 }
802 
803 void GxJack::fetch_connection_data() {
804  // check if we are connected
805  if (client) {
806  const char** port = jack_port_get_connections(ports.input.port);
807  if (port) { // might be 0 (e.g. due to race conditions)
808  engine.clear_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
809  free(port);
810  } else {
811  engine.set_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
812  }
813  }
814  while (true) {
815  PortConnData p;
816  bool fetched = connection_queue.pop(&p);
817  if (!fetched) {
818  break;
819  }
820  if (client) {
821  connection_changed(p.name_a, p.name_b, p.connect);
822  }
823  }
824 }
825 
826 // jackd1: RT process thread
827 // jackd2: not RT thread
828 void GxJack::gx_jack_portconn_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) {
829  GxJack& self = *static_cast<GxJack*>(arg);
830  if (!self.client) {
831  return;
832  }
833  jack_port_t* port_a = jack_port_by_id(self.client, a);
834  jack_port_t* port_b = jack_port_by_id(self.client, b);
835  if (!port_a || !port_b) {
836  return;
837  }
838  self.connection_queue.push(jack_port_name(port_a), jack_port_name(port_b), connect);
839 }
840 
841 
842 /****************************************************************
843  ** callbacks: portreg, buffersize, samplerate, shutdown, xrun
844  */
845 
846 void GxJack::send_midi_cc(int _cc, int _pg, int _bgn, int _num) {
847  for(int i = 0;i<5;i++) {
848  if (!mmessage.send_cc[i]) {
849  mmessage.send_cc[i] = true;
850  mmessage.cc_num[i] = _cc;
851  mmessage.pg_num[i] = _pg;
852  mmessage.bg_num[i] = _bgn;
853  mmessage.me_num[i] = _num;
854  return;
855  }
856  }
857 }
858 
859 // ----- fetch available jack ports other than gx_head ports
860 // jackd1: RT process thread
861 // jackd2: not RT thread
862 void GxJack::gx_jack_portreg_callback(jack_port_id_t pid, int reg, void* arg) {
863  GxJack& self = *static_cast<GxJack*>(arg);
864  if (!self.client) {
865  return;
866  }
867  jack_port_t* port = jack_port_by_id(self.client, pid);
868  if (!port || jack_port_is_mine(self.client, port)) {
869  return;
870  }
871  self.connection_queue.portchange();
872 }
873 
874 // ----jack sample rate change callback
875 // seems to be run in main thread (just once, no possibility
876 // to change the samplerate when jack is running?)
877 int GxJack::gx_jack_srate_callback(jack_nframes_t samplerate, void* arg) {
878  GxJack& self = *static_cast<GxJack*>(arg);
879  if (self.jack_sr == samplerate) {
880  return 0;
881  }
883  self.jack_sr = samplerate;
884  self.engine.set_samplerate(samplerate);
885  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
886  return 0;
887 }
888 
889 // ---- jack buffer size change callback
890 // RT process thread
891 int GxJack::gx_jack_buffersize_callback(jack_nframes_t nframes, void* arg) {
892  GxJack& self = *static_cast<GxJack*>(arg);
893  if (self.jack_bs == nframes) {
894  return 0;
895  }
897  self.jack_bs = nframes;
898  self.engine.set_buffersize(nframes);
899  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
900  self.buffersize_change();
901  // create buffer to bypass the insert ports
902  delete[] self.insert_buffer;
903  self.insert_buffer = NULL;
904  self.insert_buffer = new float[self.jack_bs];
905  return 0;
906 }
907 
908 // ---- jack shutdown callback in case jackd shuts down on us
909 void GxJack::gx_jack_shutdown_callback() {
910  set_jack_exit(true);
911  engine.set_stateflag(gx_engine::GxEngine::SF_INITIALIZING);
912  shutdown();
913 }
914 
915 void GxJack::shutdown_callback_client(void *arg) {
916  GxJack& self = *static_cast<GxJack*>(arg);
917  if (self.client) {
918  self.client = 0;
919  self.client_change_rt();
920  }
921  if (self.client_insert) {
922  jack_client_close(self.client_insert);
923  self.client_insert = 0;
924  }
925  self.gx_jack_shutdown_callback();
926 }
927 
928 void GxJack::shutdown_callback_client_insert(void *arg) {
929  GxJack& self = *static_cast<GxJack*>(arg);
930  self.client_insert = 0;
931  if (self.client) {
932  jack_client_close(self.client);
933  self.client = 0;
934  self.client_change_rt();
935  }
936  self.gx_jack_shutdown_callback();
937 }
938 
939 void GxJack::report_xrun_clear() {
940  xrun_msg_blocked = false;
941 }
942 
943 void GxJack::report_xrun() {
944  if (xrun_msg_blocked) {
945  return;
946  }
947  xrun_msg_blocked = true;
948  Glib::signal_timeout().connect_once(
949  sigc::mem_fun(this, &GxJack::report_xrun_clear), 100);
951  _("Jack XRun"),
952  (boost::format(_(" delay of at least %1% microsecs")) % last_xrun).str());
953 }
954 
955 // ---- jack xrun callback
956 int GxJack::gx_jack_xrun_callback(void* arg) {
957  GxJack& self = *static_cast<GxJack*>(arg);
958  if (!self.client) {
959  return 0;
960  }
961  self.last_xrun = jack_get_xrun_delayed_usecs(self.client);
962  if (!self.engine.mono_chain.is_stopped()) {
963  self.engine.overload(gx_engine::EngineControl::ov_XRun, "xrun");
964  }
965  self.xrun();
966  return 0;
967 }
968 
969 /****************************************************************
970  ** jack session
971  */
972 
973 #ifdef HAVE_JACK_SESSION
974 jack_set_session_callback_type GxJack::jack_set_session_callback_fp =
975  reinterpret_cast<jack_set_session_callback_type>(
976  dlsym(RTLD_DEFAULT, "jack_set_session_callback"));
977 jack_get_uuid_for_client_name_type GxJack::jack_get_uuid_for_client_name_fp =
978  reinterpret_cast<jack_get_uuid_for_client_name_type>(
979  dlsym(RTLD_DEFAULT, "jack_get_uuid_for_client_name"));
980 jack_client_get_uuid_type GxJack::jack_client_get_uuid_fp =
981  reinterpret_cast<jack_client_get_uuid_type>(
982  dlsym(RTLD_DEFAULT, "jack_client_get_uuid"));
983 
984 int GxJack::return_last_session_event() {
985  jack_session_event_t *event = get_last_session_event();
986  if (event) {
987  session_callback_seen += 1;
988  jack_session_reply(client, event);
989  jack_session_event_free(event);
990  gx_system::atomic_set_0(&session_event);
991  }
992  return session_callback_seen;
993 }
994 
995 int GxJack::return_last_session_event_ins() {
996  jack_session_event_t *event = get_last_session_event_ins();
997  if (event) {
998  session_callback_seen -= 1;
999  jack_session_reply(client_insert, event);
1000  jack_session_event_free(event);
1001  gx_system::atomic_set_0(&session_event_ins);
1002  }
1003  return session_callback_seen;
1004 }
1005 
1006 string GxJack::get_uuid_insert() {
1007  // should be const char* but jack_free doesn't like it
1008  char* uuid;
1009  if (jack_client_get_uuid_fp) {
1010  uuid = jack_client_get_uuid_fp(client_insert);
1011  } else if (jack_get_uuid_for_client_name_fp) {
1012  uuid = jack_get_uuid_for_client_name_fp(
1013  client_insert, client_insert_name.c_str());
1014  } else {
1015  assert(false);
1016  gx_print_error(_("session save"), _("can't get client uuid"));
1017  return "";
1018  }
1019  string ret(uuid);
1020  jack_free(uuid);
1021  return ret;
1022 }
1023 
1024 void GxJack::gx_jack_session_callback(jack_session_event_t *event, void *arg) {
1025  GxJack& self = *static_cast<GxJack*>(arg);
1026  jack_session_event_t *np = 0;
1027  if (!gx_system::atomic_compare_and_exchange(&self.session_event, np, event)) {
1028  gx_print_error("jack","last session not cleared");
1029  return;
1030  }
1031  self.session();
1032 }
1033 
1034 void GxJack::gx_jack_session_callback_ins(jack_session_event_t *event, void *arg) {
1035  GxJack& self = *static_cast<GxJack*>(arg);
1036  jack_session_event_t *np = 0;
1037  if (!gx_system::atomic_compare_and_exchange(&self.session_event_ins, np, event)) {
1038  gx_print_error("jack","last session not cleared");
1039  return;
1040  }
1041  self.session_ins();
1042 }
1043 #endif
1044 
1045 } /* end of gx_jack namespace */
Glib::Dispatcher session
Definition: gx_jack.h:205
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
void set_jack_down(bool v)
Definition: gx_jack.h:188
void begin_array(bool nl=false)
Definition: gx_json.cpp:184
void end_array(bool nl=false)
Definition: gx_json.cpp:192
virtual void wait_ramp_down_finished()
const Glib::ustring & get_jack_instancename() const
Definition: gx_system.h:495
void read_connections(gx_system::JsonParser &jp)
Definition: gx_jack.cpp:158
int bg_num[5]
Definition: gx_jack.h:107
void push(const char *a, const char *b, bool conn)
Definition: gx_jack.cpp:771
void process_midi_cc(void *buf, jack_nframes_t nframes)
Definition: gx_jack.cpp:636
void init(unsigned int samplerate, unsigned int buffersize, int policy, int priority)
void measure_cont()
Definition: gx_system.h:260
#define __rt_func
Definition: gx_compiler.h:4
static void rt_watchdog_set_limit(int limit)
Definition: gx_jack.cpp:146
void measure_start()
Definition: gx_system.h:258
PortConnection midi_output
Definition: gx_jack.h:87
GxJack(gx_engine::GxEngine &engine_)
Definition: gx_jack.cpp:102
PortConnection output1
Definition: gx_jack.h:89
PortConnection insert_out
Definition: gx_jack.h:86
Glib::Dispatcher connection
Definition: gx_jack.h:209
const char * name_b
Definition: gx_jack.h:49
void write_key(const char *p, bool nl=false)
Definition: gx_json.cpp:200
const Glib::ustring & get_jack_servername() const
Definition: gx_system.h:500
int atomic_get(volatile int &p)
Definition: gx_system.h:98
void gx_print_fatal(const char *, const std::string &)
Definition: gx_logging.cpp:177
PortConnection output2
Definition: gx_jack.h:90
jack_port_t * port
Definition: gx_jack.h:78
Glib::Dispatcher new_data
Definition: gx_jack.h:62
jack_client_t * client
Definition: gx_jack.h:171
void measure_stop()
Definition: gx_system.h:261
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
static string get_default_instancename()
Definition: gx_jack.cpp:46
void * get_midi_buffer(jack_nframes_t nframes)
Definition: gx_jack.cpp:662
PortConnection insert_in
Definition: gx_jack.h:88
int pg_num[5]
Definition: gx_jack.h:106
bool is_jack_exit()
Definition: gx_jack.h:210
bool is_jack_down()
Definition: gx_jack.h:208
void set_jack_exit(bool v)
Definition: gx_jack.h:189
void send_midi_cc(int cc_num, int pgm_num, int bgn, int num)
Definition: gx_jack.cpp:846
virtual void overload(OverloadType tp, const char *reason)
PortConnection input
Definition: gx_jack.h:84
const Glib::ustring & get_jack_input() const
Definition: gx_system.h:499
void write_connections(gx_system::JsonWriter &w)
Definition: gx_jack.cpp:218
void begin_object(bool nl=false)
Definition: gx_json.cpp:168
static GxExit & get_instance()
Definition: gx_logging.cpp:205
jack_position_t current
Definition: gx_jack.h:174
Glib::ustring get_jack_output(unsigned int n) const
Definition: gx_system.cpp:834
bool get_jack_noconnect() const
Definition: gx_system.h:501
list< string > conn
Definition: gx_jack.h:79
jack_transport_state_t transport_state
Definition: gx_jack.h:175
const char * name_a
Definition: gx_jack.h:48
JackPorts ports
Definition: gx_jack.h:169
jack_client_t * client_insert
Definition: gx_jack.h:172
const Glib::ustring & get_jack_uuid2() const
Definition: gx_system.h:497
const Glib::ustring & get_jack_midi() const
Definition: gx_system.h:498
PortConnection midi_input
Definition: gx_jack.h:85
void atomic_inc(volatile int *p)
Definition: gx_system.h:106
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
sigc::signal< void, bool > & signal_exit()
Definition: gx_logging.h:116
void atomic_set(volatile int *p, int v)
Definition: gx_system.h:90
Glib::Dispatcher shutdown
Definition: gx_jack.h:207
int cc_num[5]
Definition: gx_jack.h:105
string current_value() const
Definition: gx_json.h:143
int me_num[5]
Definition: gx_jack.h:108
const Glib::ustring & get_jack_uuid() const
Definition: gx_system.h:496
Glib::Dispatcher portchange
Definition: gx_jack.h:63
void set_stateflag(StateFlag flag)
bool atomic_compare_and_exchange(volatile int *p, int oldv, int newv)
Definition: gx_system.h:114
bool gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions &opt)
Definition: gx_jack.cpp:437
bool send_cc[5]
Definition: gx_jack.h:104
#define SCHED_IDLE
Definition: gx_jack.cpp:59
void measure_pause()
Definition: gx_system.h:259
void clear_stateflag(StateFlag flag)
void atomic_set_0(T **p)
Definition: gx_system.h:124
Glib::Dispatcher session_ins
Definition: gx_jack.h:206
token next(token expect=no_token)
Definition: gx_json.cpp:496
void write(float v, bool nl=false)
Definition: gx_json.cpp:116
string client_name
Definition: gx_jack.h:203
jack_transport_state_t old_transport_state
Definition: gx_jack.h:176
string client_insert_name
Definition: gx_jack.h:204
bool pop(PortConnData *)
Definition: gx_jack.cpp:787
void AVOIDDENORMALS()
Definition: gx_system.h:73
void end_object(bool nl=false)
Definition: gx_json.cpp:176