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 
235 // ----- pop up a dialog for starting jack
236 bool GxJack::gx_jack_init(bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
237  AVOIDDENORMALS();
238  int jackopt = (startserver ? JackNullOption : JackNoStartServer);
239  client_instance = opt.get_jack_instancename();
240  if (client_instance.empty()) {
241  client_instance = get_default_instancename();
242  } else {
243  jackopt |= JackUseExactName;
244  }
245 
246  std::string ServerName = opt.get_jack_servername();
247 
248  set_jack_down(false);
249  set_jack_exit(true);
251 
252  //ports = JackPorts(); //FIXME
253 
254  client_name = client_instance + jack_amp_postfix;
255  client_insert_name = client_instance + jack_fx_postfix;
256  jack_status_t jackstat;
257 #ifdef HAVE_JACK_SESSION
258  // try to open jack gxjack.client
259  if (!opt.get_jack_uuid().empty()) {
260  client = jack_client_open(
261  client_name.c_str(), JackOptions(jackopt | JackSessionID),
262  &jackstat, opt.get_jack_uuid().c_str());
263  } else {
264  if (ServerName.empty()) {
265  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
266  } else {
267  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
268  &jackstat, ServerName.c_str());
269  }
270  }
271 #else
272  if (ServerName.empty()) {
273  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
274  } else {
275  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
276  &jackstat, ServerName.c_str());
277  }
278 #endif
279  // ----- only start the insert gxjack.client when the amp gxjack.client is true
280  if (client) {
281  // it is maybe not the 1st gx_head instance ?
282  // session handler can change name without setting JackNameNotUnique in return status; jack bug??
283  // this code depends on jackd only appending a suffix to make a client name unique
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;
288  client_name = name;
289  client_insert_name = base + jack_fx_postfix + generated_suffix;
290 #ifdef HAVE_JACK_SESSION
291  if (!opt.get_jack_uuid2().empty()) {
292  client_insert = jack_client_open(
293  client_insert_name.c_str(),
294  JackOptions(jackopt | JackSessionID | JackUseExactName),
295  &jackstat, opt.get_jack_uuid2().c_str());
296  } else {
297  if (ServerName.empty()) {
298  client_insert = jack_client_open(
299  client_insert_name.c_str(),
300  JackOptions(jackopt | JackUseExactName ), &jackstat);
301  } else {
302  client_insert = jack_client_open(
303  client_insert_name.c_str(),
304  JackOptions(jackopt | JackUseExactName | JackServerName),
305  &jackstat, ServerName.c_str());
306  }
307  }
308 #else
309  if (ServerName.empty()) {
310  client_insert = jack_client_open(
311  client_insert_name.c_str(),
312  JackOptions(jackopt | JackUseExactName), &jackstat);
313  } else {
314  client_insert = jack_client_open(
315  client_insert_name.c_str(),
316  JackOptions(jackopt | JackUseExactName | JackServerName),
317  &jackstat, ServerName.c_str());
318  }
319 #endif
320  if (!client_insert) {
321  jack_client_close(client);
322  client = 0;
323  }
324  }
325 
326  if (!client) {
327  if (!(jackstat & JackServerFailed)) {
328  if ((jackstat & JackServerError) && (jackopt & JackUseExactName)) {
330  _("Jack Init"),
331  boost::format(_("can't get requested jack instance name '%1%'"))
332  % client_instance);
333  } else {
335  _("Jack Init"),
336  _("unknown jack server communication error"));
337  }
338  }
339  return false;
340  }
341 
342  // ----------------------------------
343  set_jack_down(false);
344 
345  if (wait_after_connect) {
346  usleep(wait_after_connect);
347  }
348  jack_sr = jack_get_sample_rate(client); // jack sample rate
350  _("Jack init"),
351  boost::format(_("The jack sample rate is %1%/sec")) % jack_sr);
352 
353  jack_bs = jack_get_buffer_size(client); // jack buffer size
355  _("Jack init"),
356  boost::format(_("The jack buffer size is %1%/frames ... "))
357  % jack_bs);
358  // create buffer to bypass the insert ports
359  insert_buffer = new float[jack_bs];
360 
361  gx_jack_callbacks();
362  client_change(); // might load port connection definitions
363  if (opt.get_jack_uuid().empty() && !opt.get_jack_noconnect()) {
364  // when not loaded by session manager
365  gx_jack_init_port_connection(opt);
366  }
367  set_jack_exit(false);
368 
369  return true;
370 }
371 
372 void GxJack::cleanup_slot(bool otherthread) {
373  if (!otherthread) {
374  gx_jack_cleanup();
375  } else {
376  // called from other thread. Since most cleanup functions are
377  // not thread safe, just do minimal jack cleanup
378  if (client) {
379  if (!is_jack_down()) {
380  engine.start_ramp_down();
381  engine.wait_ramp_down_finished();
382  }
383  jack_deactivate(client);
384  jack_client_close(client);
385  client = 0;
386  }
387  if (client_insert) {
388  jack_deactivate(client_insert);
389  jack_client_close(client_insert);
390  client_insert = 0;
391  }
392  }
393 }
394 
395 // -----Function that cleans the jack stuff on shutdown
396 void GxJack::gx_jack_cleanup() {
397  if (!client || is_jack_down()) {
398  return;
399  }
400  engine.start_ramp_down();
401  engine.wait_ramp_down_finished();
402  set_jack_exit(true);
404  jack_deactivate(client);
405  jack_deactivate(client_insert);
406  jack_port_unregister(client, ports.input.port);
407  jack_port_unregister(client, ports.midi_input.port);
408  jack_port_unregister(client, ports.insert_out.port);
409 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
410  jack_port_unregister(client, ports.midi_output.port);
411 #endif
412  jack_port_unregister(client_insert, ports.insert_in.port);
413  jack_port_unregister(client_insert, ports.output1.port);
414  jack_port_unregister(client_insert, ports.output2.port);
415  jack_client_close(client);
416  client = 0;
417  jack_client_close(client_insert);
418  client_insert = 0;
419  delete[] insert_buffer;
420  insert_buffer = NULL;
421  client_change();
422 }
423 
424 // ---- Jack server connection / disconnection
425 bool GxJack::gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
426  if (connect) {
427  if (client) {
428  return true;
429  }
430  if (!gx_jack_init(startserver, wait_after_connect, opt)) {
431  return false;
432  }
433  engine.set_rack_changed();
435  } else {
436  if (!client) {
437  return true;
438  }
439  gx_jack_cleanup();
440  }
441  connection();
442  connection_queue.portchange();
443  return true;
444 }
445 
446 
447 /****************************************************************
448  ** port connections
449  */
450 
451 std::string GxJack::make_clientvar(const std::string& s) {
452  std::size_t n = s.find(':');
453  if (n == s.npos) {
454  return s; // no ':' in jack port name??
455  }
456  if (s.compare(0, n, client_name) == 0) {
457  return "%A" + s.substr(n);
458  }
459  if (s.compare(0, n, client_insert_name) == 0) {
460  return "%F" + s.substr(n);
461  }
462  return s;
463 }
464 
465 std::string GxJack::replace_clientvar(const std::string& s) {
466  if (s.compare(0, 3, "%A:") == 0) {
467  return client_name + s.substr(2);
468  }
469  if (s.compare(0, 3, "%F:") == 0) {
470  return client_insert_name + s.substr(2);
471  }
472  return s;
473 }
474 
475 // ----- connect ports if we know them
476 void GxJack::gx_jack_init_port_connection(const gx_system::CmdlineOptions& opt) {
477  // set autoconnect capture to user capture port
478  if (!opt.get_jack_input().empty()) {
479  jack_connect(client, opt.get_jack_input().c_str(),
480  jack_port_name(ports.input.port));
481  } else {
482  list<string>& l = ports.input.conn;
483  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
484  jack_connect(client, i->c_str(), jack_port_name(ports.input.port));
485  }
486  }
487 
488  // set autoconnect midi to user midi port
489  if (ports.midi_input.port && !opt.get_jack_midi().empty()) {
490  jack_connect(client, opt.get_jack_midi().c_str(),
491  jack_port_name(ports.midi_input.port));
492  } else {
493  list<string>& l = ports.midi_input.conn;
494  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
495  jack_connect(client, i->c_str(), jack_port_name(ports.midi_input.port));
496  }
497  }
498 
499  // set autoconnect to user playback ports
500  if (opt.get_jack_output(0).empty() && opt.get_jack_output(1).empty()) {
501  list<string>& l1 = ports.output1.conn;
502  for (list<string>::iterator i = l1.begin(); i != l1.end(); ++i) {
503  jack_connect(client_insert, jack_port_name(ports.output1.port), i->c_str());
504  }
505  list<string>& l2 = ports.output2.conn;
506  for (list<string>::iterator i = l2.begin(); i != l2.end(); ++i) {
507  jack_connect(client_insert, jack_port_name(ports.output2.port), i->c_str());
508  }
509  } else {
510  if (!opt.get_jack_output(0).empty()) {
511  jack_connect(client_insert,
512  jack_port_name(ports.output1.port),
513  opt.get_jack_output(0).c_str());
514  }
515  if (!opt.get_jack_output(1).empty()) {
516  jack_connect(client_insert,
517  jack_port_name(ports.output2.port),
518  opt.get_jack_output(1).c_str());
519  }
520  }
521 
522 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
523  // autoconnect midi output port
524  list<string>& lmo = ports.midi_output.conn;
525  for (list<string>::iterator i = lmo.begin(); i != lmo.end(); ++i) {
526  jack_connect(client, jack_port_name(ports.midi_output.port), i->c_str());
527  }
528 #endif
529 
530  // autoconnect to insert ports
531  list<string>& lins_in = ports.insert_in.conn;
532  list<string>& lins_out = ports.insert_out.conn;
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(),
536  jack_port_name(ports.insert_in.port));
537  if (rc == 0 || rc == EEXIST) {
538  ifound = true;
539  }
540  }
541  jack_port_t* port_a = jack_port_by_name(client, jack_port_name(ports.insert_out.port));
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())) {
545  int rc = jack_connect(client, jack_port_name(ports.insert_out.port),
546  port.c_str());
547  if (rc == 0 || rc == EEXIST) {
548  ofound = true;
549  }
550  } else {
551  ofound = true;
552  }
553  }
554  if (!ifound || !ofound) {
555  jack_connect(client_insert, jack_port_name(ports.insert_out.port),
556  (client_insert_name+":in_0").c_str());
557  }
558 }
559 
560 
561 /****************************************************************
562  ** callback installation and port registration
563  */
564 
565 // ----- set gxjack.client callbacks and activate gxjack.client
566 void GxJack::gx_jack_callbacks() {
567  // ----- set the 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);
579  }
580 #endif
581 
582  // register ports for gx_amp
583  ports.input.port = jack_port_register(
584  client, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
585  ports.midi_input.port = jack_port_register(
586  client, "midi_in_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
587  ports.insert_out.port = jack_port_register(
588  client, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
589 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
590  ports.midi_output.port = jack_port_register(
591  client, "midi_out_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
592 #else
593  ports.midi_output.port = 0;
594 #endif
595 
596  // register ports for gx_amp_fx
597  ports.insert_in.port = jack_port_register(
598  client_insert, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
599  ports.output1.port = jack_port_register(
600  client_insert, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
601  ports.output2.port = jack_port_register(
602  client_insert, "out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
603 
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")));
612  }
613  if (jack_activate(client_insert) != 0) {
614  gx_print_fatal(_("Jack Activation"),
615  string(_("Can't activate JACK gx_amp_fx client")));
616  }
617 }
618 
619 
620 /****************************************************************
621  ** jack process callbacks
622  */
623 
624 void __rt_func GxJack::process_midi_cc(void *buf, jack_nframes_t nframes) {
625  // midi CC output processing
626  for(int i = 0;i<5;i++) {
627  if (mmessage.send_cc[i]) {
628  unsigned char* midi_send = jack_midi_event_reserve(buf, i, mmessage.me_num[i]);
629 
630  if (midi_send) {
631  if (mmessage.me_num[i] == 2) {
632  // program value
633  midi_send[1] = mmessage.pg_num[i];
634  // controller+ channel
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];
638  // program value
639  midi_send[1] = mmessage.pg_num[i];
640  // controller+ channel
641  midi_send[0] = mmessage.cc_num[i] | 0;
642  }
643  }
644  mmessage.send_cc[i] = false;
645  }
646  }
647 }
648 
649 // must only be used inside gx_jack_process
650 void *GxJack::get_midi_buffer(jack_nframes_t nframes) {
651  if (!ports.midi_output.port) {
652  return 0;
653  }
654  void *midi_port_buf = jack_port_get_buffer(ports.midi_output.port, nframes);
655  if (midi_port_buf) {
656  jack_midi_clear_buffer(midi_port_buf);
657  }
658  return midi_port_buf;
659 }
660 
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));
663 }
664 
665 inline void GxJack::check_overload() {
666  if (!rt_watchdog_check_alive(jack_bs, jack_sr)) {
667  engine.overload(gx_engine::EngineControl::ov_User, "watchdog thread");
668  }
669 }
670 
671 // ----- main jack process method gx_amp, mono -> mono
672 // RT process thread
673 int __rt_func GxJack::gx_jack_process(jack_nframes_t nframes, void *arg) {
675  GxJack& self = *static_cast<GxJack*>(arg);
676  if (!self.is_jack_exit()) {
677  if (!self.engine.mono_chain.is_stopped()) {
678  self.check_overload();
679  }
680  self.transport_state = jack_transport_query (self.client, &self.current);
681  // gx_head DSP computing
682  float *obuf = get_float_buf(self.ports.insert_out.port, nframes);
683  self.engine.mono_chain.process(
684  nframes,
685  get_float_buf(self.ports.input.port, nframes),
686  obuf);
687 
688  if (self.bypass_insert) {
689  memcpy(self.insert_buffer, obuf, nframes*sizeof(float));
690  }
691  // midi input processing
692  if (self.ports.midi_input.port) {
693  self.engine.controller_map.compute_midi_in(
694  jack_port_get_buffer(self.ports.midi_input.port, nframes), arg);
695  }
696  // jack transport support
697  if ( self.transport_state != self.old_transport_state) {
698  self.engine.controller_map.process_trans(self.transport_state);
699  self.old_transport_state = self.transport_state;
700  }
701  }
702  // midi CC output processing
703  void *buf = self.get_midi_buffer(nframes);
704  self.process_midi_cc(buf, nframes);
705 
707  self.engine.mono_chain.post_rt_finished();
708  return 0;
709 }
710 
711 // ----- main jack process method, gx_fx_amp, mono -> stereo
712 // RT process_insert thread
713 int __rt_func GxJack::gx_jack_insert_process(jack_nframes_t nframes, void *arg) {
714  GxJack& self = *static_cast<GxJack*>(arg);
716  if (!self.is_jack_exit()) {
717  if (!self.engine.stereo_chain.is_stopped()) {
718  self.check_overload();
719  }
720  // gx_head DSP computing
721  float *ibuf = NULL;
722  if (!self.bypass_insert) {
723  ibuf = get_float_buf(self.ports.insert_in.port, nframes);
724  } else {
725  ibuf = self.insert_buffer;
726  }
727  self.engine.stereo_chain.process(
728  nframes, ibuf, ibuf,
729  get_float_buf(self.ports.output1.port, nframes),
730  get_float_buf(self.ports.output2.port, nframes));
731  }
733  self.engine.stereo_chain.post_rt_finished();
734  return 0;
735 }
736 
737 
738 /****************************************************************
739  ** port connection callback
740  */
741 
743  : ring(jack_ringbuffer_create(20*sizeof(PortConnData))), // just a number...
744  send_changes(false),
745  overflow(false),
746  new_data(),
747  portchange() {
748  if (!ring) {
750  _("Jack init"), _("can't get memory for ringbuffer"));
751  }
752  jack_ringbuffer_mlock(ring);
753 }
754 
756  jack_ringbuffer_free(ring);
757 }
758 
759 void PortConnRing::push(const char *a, const char *b, bool conn) {
760  if (is_overflow()) {
761  return;
762  }
763  if (send_changes) {
764  PortConnData p(a, b, conn);
765  size_t sz = jack_ringbuffer_write(ring, reinterpret_cast<const char*>(&p), sizeof(p));
766  if (sz != sizeof(p)) {
767  set_overflow();
768  } else {
769  jack_ringbuffer_write_advance(ring, sz);
770  }
771  }
772  new_data();
773 }
774 
776  if (is_overflow()) {
777  jack_ringbuffer_reset(ring);
778  portchange();
779  clear_overflow();
780  return false;
781  }
782  size_t sz = jack_ringbuffer_read(ring, reinterpret_cast<char*>(p), sizeof(*p));
783  if (sz == 0) {
784  return false;
785  }
786  assert(sz == sizeof(*p));
787  jack_ringbuffer_read_advance(ring, sz);
788  return true;
789 }
790 
791 void GxJack::fetch_connection_data() {
792  // check if we are connected
793  if (client) {
794  const char** port = jack_port_get_connections(ports.input.port);
795  if (port) { // might be 0 (e.g. due to race conditions)
796  engine.clear_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
797  free(port);
798  } else {
799  engine.set_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
800  }
801  }
802  while (true) {
803  PortConnData p;
804  bool fetched = connection_queue.pop(&p);
805  if (!fetched) {
806  break;
807  }
808  if (client) {
809  connection_changed(p.name_a, p.name_b, p.connect);
810  }
811  }
812 }
813 
814 // jackd1: RT process thread
815 // jackd2: not RT thread
816 void GxJack::gx_jack_portconn_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) {
817  GxJack& self = *static_cast<GxJack*>(arg);
818  if (!self.client) {
819  return;
820  }
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) {
824  return;
825  }
826  self.connection_queue.push(jack_port_name(port_a), jack_port_name(port_b), connect);
827 }
828 
829 
830 /****************************************************************
831  ** callbacks: portreg, buffersize, samplerate, shutdown, xrun
832  */
833 
834 void GxJack::send_midi_cc(int _cc, int _pg, int _bgn, int _num) {
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;
842  return;
843  }
844  }
845 }
846 
847 // ----- fetch available jack ports other than gx_head ports
848 // jackd1: RT process thread
849 // jackd2: not RT thread
850 void GxJack::gx_jack_portreg_callback(jack_port_id_t pid, int reg, void* arg) {
851  GxJack& self = *static_cast<GxJack*>(arg);
852  if (!self.client) {
853  return;
854  }
855  jack_port_t* port = jack_port_by_id(self.client, pid);
856  if (!port || jack_port_is_mine(self.client, port)) {
857  return;
858  }
859  self.connection_queue.portchange();
860 }
861 
862 // ----jack sample rate change callback
863 // seems to be run in main thread (just once, no possibility
864 // to change the samplerate when jack is running?)
865 int GxJack::gx_jack_srate_callback(jack_nframes_t samplerate, void* arg) {
866  GxJack& self = *static_cast<GxJack*>(arg);
867  if (self.jack_sr == samplerate) {
868  return 0;
869  }
871  self.jack_sr = samplerate;
872  self.engine.set_samplerate(samplerate);
873  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
874  return 0;
875 }
876 
877 // ---- jack buffer size change callback
878 // RT process thread
879 int GxJack::gx_jack_buffersize_callback(jack_nframes_t nframes, void* arg) {
880  GxJack& self = *static_cast<GxJack*>(arg);
881  if (self.jack_bs == nframes) {
882  return 0;
883  }
885  self.jack_bs = nframes;
886  self.engine.set_buffersize(nframes);
887  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
888  self.buffersize_change();
889  // create buffer to bypass the insert ports
890  delete[] self.insert_buffer;
891  self.insert_buffer = NULL;
892  self.insert_buffer = new float[self.jack_bs];
893  return 0;
894 }
895 
896 // ---- jack shutdown callback in case jackd shuts down on us
897 void GxJack::gx_jack_shutdown_callback() {
898  set_jack_exit(true);
899  engine.set_stateflag(gx_engine::GxEngine::SF_INITIALIZING);
900  shutdown();
901 }
902 
903 void GxJack::shutdown_callback_client(void *arg) {
904  GxJack& self = *static_cast<GxJack*>(arg);
905  if (self.client) {
906  self.client = 0;
907  self.client_change_rt();
908  }
909  if (self.client_insert) {
910  jack_client_close(self.client_insert);
911  self.client_insert = 0;
912  }
913  self.gx_jack_shutdown_callback();
914 }
915 
916 void GxJack::shutdown_callback_client_insert(void *arg) {
917  GxJack& self = *static_cast<GxJack*>(arg);
918  self.client_insert = 0;
919  if (self.client) {
920  jack_client_close(self.client);
921  self.client = 0;
922  self.client_change_rt();
923  }
924  self.gx_jack_shutdown_callback();
925 }
926 
927 void GxJack::report_xrun_clear() {
928  xrun_msg_blocked = false;
929 }
930 
931 void GxJack::report_xrun() {
932  if (xrun_msg_blocked) {
933  return;
934  }
935  xrun_msg_blocked = true;
936  Glib::signal_timeout().connect_once(
937  sigc::mem_fun(this, &GxJack::report_xrun_clear), 100);
939  _("Jack XRun"),
940  (boost::format(_(" delay of at least %1% microsecs")) % last_xrun).str());
941 }
942 
943 // ---- jack xrun callback
944 int GxJack::gx_jack_xrun_callback(void* arg) {
945  GxJack& self = *static_cast<GxJack*>(arg);
946  if (!self.client) {
947  return 0;
948  }
949  self.last_xrun = jack_get_xrun_delayed_usecs(self.client);
950  if (!self.engine.mono_chain.is_stopped()) {
951  self.engine.overload(gx_engine::EngineControl::ov_XRun, "xrun");
952  }
953  self.xrun();
954  return 0;
955 }
956 
957 /****************************************************************
958  ** jack session
959  */
960 
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"));
971 
972 int GxJack::return_last_session_event() {
973  jack_session_event_t *event = get_last_session_event();
974  if (event) {
975  session_callback_seen += 1;
976  jack_session_reply(client, event);
977  jack_session_event_free(event);
978  gx_system::atomic_set_0(&session_event);
979  }
980  return session_callback_seen;
981 }
982 
983 int GxJack::return_last_session_event_ins() {
984  jack_session_event_t *event = get_last_session_event_ins();
985  if (event) {
986  session_callback_seen -= 1;
987  jack_session_reply(client_insert, event);
988  jack_session_event_free(event);
989  gx_system::atomic_set_0(&session_event_ins);
990  }
991  return session_callback_seen;
992 }
993 
994 string GxJack::get_uuid_insert() {
995  // should be const char* but jack_free doesn't like it
996  char* uuid;
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());
1002  } else {
1003  assert(false);
1004  gx_print_error(_("session save"), _("can't get client uuid"));
1005  return "";
1006  }
1007  string ret(uuid);
1008  jack_free(uuid);
1009  return ret;
1010 }
1011 
1012 void GxJack::gx_jack_session_callback(jack_session_event_t *event, void *arg) {
1013  GxJack& self = *static_cast<GxJack*>(arg);
1014  jack_session_event_t *np = 0;
1015  if (!gx_system::atomic_compare_and_exchange(&self.session_event, np, event)) {
1016  gx_print_error("jack","last session not cleared");
1017  return;
1018  }
1019  self.session();
1020 }
1021 
1022 void GxJack::gx_jack_session_callback_ins(jack_session_event_t *event, void *arg) {
1023  GxJack& self = *static_cast<GxJack*>(arg);
1024  jack_session_event_t *np = 0;
1025  if (!gx_system::atomic_compare_and_exchange(&self.session_event_ins, np, event)) {
1026  gx_print_error("jack","last session not cleared");
1027  return;
1028  }
1029  self.session_ins();
1030 }
1031 #endif
1032 
1033 } /* end of gx_jack namespace */
Glib::Dispatcher session
Definition: gx_jack.h:204
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
void set_jack_down(bool v)
Definition: gx_jack.h:187
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:493
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:759
void process_midi_cc(void *buf, jack_nframes_t nframes)
Definition: gx_jack.cpp:624
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:208
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:498
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:170
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:650
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:209
bool is_jack_down()
Definition: gx_jack.h:207
void set_jack_exit(bool v)
Definition: gx_jack.h:188
void send_midi_cc(int cc_num, int pgm_num, int bgn, int num)
Definition: gx_jack.cpp:834
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:497
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:173
Glib::ustring get_jack_output(unsigned int n) const
Definition: gx_system.cpp:832
bool get_jack_noconnect() const
Definition: gx_system.h:499
list< string > conn
Definition: gx_jack.h:79
jack_transport_state_t transport_state
Definition: gx_jack.h:174
const char * name_a
Definition: gx_jack.h:48
JackPorts ports
Definition: gx_jack.h:168
jack_client_t * client_insert
Definition: gx_jack.h:171
const Glib::ustring & get_jack_uuid2() const
Definition: gx_system.h:495
const Glib::ustring & get_jack_midi() const
Definition: gx_system.h:496
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:206
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:494
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:425
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:205
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:202
jack_transport_state_t old_transport_state
Definition: gx_jack.h:175
string client_insert_name
Definition: gx_jack.h:203
bool pop(PortConnData *)
Definition: gx_jack.cpp:775
void AVOIDDENORMALS()
Definition: gx_system.h:73
void end_object(bool nl=false)
Definition: gx_json.cpp:176