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  single_client(false) {
135  for(int i = 0;i<5;i++) mmessage.send_cc[i] = false;
136  connection_queue.new_data.connect(sigc::mem_fun(*this, &GxJack::fetch_connection_data));
137  client_change_rt.connect(client_change);
138  GxExit::get_instance().signal_exit().connect(
139  sigc::mem_fun(*this, &GxJack::cleanup_slot));
140  xrun.connect(sigc::mem_fun(this, &GxJack::report_xrun));
141 }
142 
144  gx_jack_cleanup();
145 }
146 
148  rt_watchdog_limit = limit;
149  if (limit > 0) {
150  rt_watchdog_start();
151  }
152 }
153 
154 
155 /****************************************************************
156  ** load state, save state
157  */
158 
161  while (jp.peek() == gx_system::JsonParser::value_key) {
162  list<string> *i;
164  if (jp.current_value() == "input") {
165  i = &ports.input.conn;
166  } else if (jp.current_value() == "output1") {
167  i = &ports.output1.conn;
168  } else if (jp.current_value() == "output2") {
169  i = &ports.output2.conn;
170  } else if (jp.current_value() == "midi_input") {
171  i = &ports.midi_input.conn;
172  } else if (jp.current_value() == "midi_output") {
173  i = &ports.midi_output.conn;
174  } else if (jp.current_value() == "insert_out") {
175  i = &ports.insert_out.conn;
176  } else if (jp.current_value() == "insert_in") {
177  i = &ports.insert_in.conn;
178  } else {
180  _("recall state"),
181  _("unknown jack ports section: ") + jp.current_value());
182  jp.skip_object();
183  continue;
184  }
186  while (jp.peek() == gx_system::JsonParser::value_string) {
187  jp.next();
188  i->push_back(jp.current_value());
189  }
191  }
193 }
194 
195 void GxJack::write_jack_port_connections(
196  gx_system::JsonWriter& w, const char *key, const PortConnection& pc, bool replace) {
197  w.write_key(key);
198  w.begin_array();
199  if (client && pc.port) {
200  const char** pl = jack_port_get_connections(pc.port);
201  if (pl) {
202  for (const char **p = pl; *p; p++) {
203  if (replace) {
204  w.write(make_clientvar(*p));
205  } else {
206  w.write(*p);
207  }
208  }
209  free(pl);
210  }
211  } else {
212  for (list<string>::const_iterator i = pc.conn.begin(); i != pc.conn.end(); ++i) {
213  w.write(*i);
214  }
215  }
216  w.end_array(true);
217 }
218 
220  w.begin_object(true);
221  write_jack_port_connections(w, "input", ports.input);
222  write_jack_port_connections(w, "output1", ports.output1);
223  write_jack_port_connections(w, "output2", ports.output2);
224  write_jack_port_connections(w, "midi_input", ports.midi_input);
225  write_jack_port_connections(w, "midi_output", ports.midi_output);
226  if (!single_client) {
227  write_jack_port_connections(w, "insert_out", ports.insert_out, true);
228  write_jack_port_connections(w, "insert_in", ports.insert_in, true);
229  }
230  w.end_object(true);
231 }
232 
233 
234 /****************************************************************
235  ** client connection init and cleanup
236  */
237 int GxJack::is_power_of_two (unsigned int x)
238 {
239  return ((x != 0) && ((x & (~x + 1)) == x));
240 }
241 
242 // ----- pop up a dialog for starting jack
243 bool GxJack::gx_jack_init(bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
244  AVOIDDENORMALS();
245  single_client = opt.get_jack_single();
246  int jackopt = (startserver ? JackNullOption : JackNoStartServer);
247  client_instance = opt.get_jack_instancename();
248  if (client_instance.empty()) {
249  if (!single_client) {
250  client_instance = get_default_instancename();
251  } else {
252  client_instance = "guitarix";
253  }
254  } else {
255  jackopt |= JackUseExactName;
256  }
257 
258  std::string ServerName = opt.get_jack_servername();
259 
260  set_jack_down(false);
261  set_jack_exit(true);
263 
264  //ports = JackPorts(); //FIXME
265 
266  if (!single_client) {
267  client_name = client_instance + jack_amp_postfix;
268  } else {
269  client_name = client_instance;
270  }
271  client_insert_name = client_instance + jack_fx_postfix;
272  jack_status_t jackstat;
273 #ifdef HAVE_JACK_SESSION
274  // try to open jack gxjack.client
275  if (!opt.get_jack_uuid().empty()) {
276  client = jack_client_open(
277  client_name.c_str(), JackOptions(jackopt | JackSessionID),
278  &jackstat, opt.get_jack_uuid().c_str());
279  } else {
280  if (ServerName.empty()) {
281  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
282  } else {
283  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
284  &jackstat, ServerName.c_str());
285  }
286  }
287 #else
288  if (ServerName.empty()) {
289  client = jack_client_open(client_name.c_str(), JackOptions(jackopt), &jackstat);
290  } else {
291  client = jack_client_open(client_name.c_str(), JackOptions(jackopt | JackServerName),
292  &jackstat, ServerName.c_str());
293  }
294 #endif
295  // ----- only start the insert gxjack.client when the amp gxjack.client is true
296  if (client && !single_client) {
297  // it is maybe not the 1st gx_head instance ?
298  // session handler can change name without setting JackNameNotUnique in return status; jack bug??
299  // this code depends on jackd only appending a suffix to make a client name unique
300  std::string name = jack_get_client_name(client);
301  std::string generated_suffix = name.substr(client_name.size());
302  std::string base = name.substr(0, client_name.size()-strlen(jack_amp_postfix));
303  client_instance = base + generated_suffix;
304  client_name = name;
305  client_insert_name = base + jack_fx_postfix + generated_suffix;
306 #ifdef HAVE_JACK_SESSION
307  if (!opt.get_jack_uuid2().empty()) {
308  client_insert = jack_client_open(
309  client_insert_name.c_str(),
310  JackOptions(jackopt | JackSessionID | JackUseExactName),
311  &jackstat, opt.get_jack_uuid2().c_str());
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  }
324 #else
325  if (ServerName.empty()) {
326  client_insert = jack_client_open(
327  client_insert_name.c_str(),
328  JackOptions(jackopt | JackUseExactName), &jackstat);
329  } else {
330  client_insert = jack_client_open(
331  client_insert_name.c_str(),
332  JackOptions(jackopt | JackUseExactName | JackServerName),
333  &jackstat, ServerName.c_str());
334  }
335 #endif
336  if (!client_insert) {
337  jack_client_close(client);
338  client = 0;
339  }
340  }
341 
342  if (!client) {
343  if (!(jackstat & JackServerFailed)) {
344  if ((jackstat & JackServerError) && (jackopt & JackUseExactName)) {
346  _("Jack Init"),
347  boost::format(_("can't get requested jack instance name '%1%'"))
348  % client_instance);
349  } else {
351  _("Jack Init"),
352  _("unknown jack server communication error"));
353  }
354  }
355  return false;
356  }
357 
358  // ----------------------------------
359  set_jack_down(false);
360 
361  if (wait_after_connect) {
362  usleep(wait_after_connect);
363  }
364  jack_sr = jack_get_sample_rate(client); // jack sample rate
366  _("Jack init"),
367  boost::format(_("The jack sample rate is %1%/sec")) % jack_sr);
368 
369  jack_bs = jack_get_buffer_size(client); // jack buffer size
370  if (!is_power_of_two(jack_bs)) {
372  _("Jack init"),
373  boost::format(_("The jack buffer size is %1%/frames is not power of two, Convolver wont run"))
374  % jack_bs);
375  } else {
377  _("Jack init"),
378  boost::format(_("The jack buffer size is %1%/frames ... "))
379  % jack_bs);
380  }
381 
382  // create buffer to bypass the insert ports
383  insert_buffer = new float[jack_bs];
384 
385  gx_jack_callbacks();
386  client_change(); // might load port connection definitions
387  if (opt.get_jack_uuid().empty() && !opt.get_jack_noconnect()) {
388  // when not loaded by session manager
389  gx_jack_init_port_connection(opt);
390  }
391  set_jack_exit(false);
392  if (jack_sr > 96000) {
394  _("Jack Init"),
395  _("Sample rates above 96kHz ain't be supported"));
396  return false;
397  }
398  return true;
399 }
400 
401 void GxJack::cleanup_slot(bool otherthread) {
402  if (!otherthread) {
403  gx_jack_cleanup();
404  } else {
405  // called from other thread. Since most cleanup functions are
406  // not thread safe, just do minimal jack cleanup
407  if (client) {
408  if (!is_jack_down()) {
409  engine.start_ramp_down();
410  engine.wait_ramp_down_finished();
411  }
412  jack_deactivate(client);
413  jack_client_close(client);
414  client = 0;
415  }
416  if (client_insert) {
417  jack_deactivate(client_insert);
418  jack_client_close(client_insert);
419  client_insert = 0;
420  }
421  }
422 }
423 
424 // -----Function that cleans the jack stuff on shutdown
425 void GxJack::gx_jack_cleanup() {
426  if (!client || is_jack_down()) {
427  return;
428  }
429  engine.start_ramp_down();
430  engine.wait_ramp_down_finished();
431  set_jack_exit(true);
433  jack_deactivate(client);
434  if (!single_client) jack_deactivate(client_insert);
435  jack_port_unregister(client, ports.input.port);
436  jack_port_unregister(client, ports.midi_input.port);
437  if (!single_client) {
438  jack_port_unregister(client, ports.insert_out.port);
439  } else {
440  jack_port_unregister(client, ports.output1.port);
441  jack_port_unregister(client, ports.output2.port);
442  }
443 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
444  jack_port_unregister(client, ports.midi_output.port);
445 #endif
446  if (!single_client) {
447  jack_port_unregister(client_insert, ports.insert_in.port);
448  jack_port_unregister(client_insert, ports.output1.port);
449  jack_port_unregister(client_insert, ports.output2.port);
450  }
451  jack_client_close(client);
452  client = 0;
453  if (!single_client) jack_client_close(client_insert);
454  client_insert = 0;
455  delete[] insert_buffer;
456  insert_buffer = NULL;
457  client_change();
458 }
459 
460 // ---- Jack server connection / disconnection
461 bool GxJack::gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions& opt) {
462  if (connect) {
463  if (client) {
464  return true;
465  }
466  if (!gx_jack_init(startserver, wait_after_connect, opt)) {
467  return false;
468  }
469  engine.set_rack_changed();
471  } else {
472  if (!client) {
473  return true;
474  }
475  gx_jack_cleanup();
476  }
477  connection();
478  connection_queue.portchange();
479  return true;
480 }
481 
482 
483 /****************************************************************
484  ** port connections
485  */
486 
487 std::string GxJack::make_clientvar(const std::string& s) {
488  std::size_t n = s.find(':');
489  if (n == s.npos) {
490  return s; // no ':' in jack port name??
491  }
492  if (s.compare(0, n, client_name) == 0) {
493  return "%A" + s.substr(n);
494  }
495  if (s.compare(0, n, client_insert_name) == 0) {
496  return "%F" + s.substr(n);
497  }
498  return s;
499 }
500 
501 std::string GxJack::replace_clientvar(const std::string& s) {
502  if (s.compare(0, 3, "%A:") == 0) {
503  return client_name + s.substr(2);
504  }
505  if (s.compare(0, 3, "%F:") == 0) {
506  return client_insert_name + s.substr(2);
507  }
508  return s;
509 }
510 
511 // ----- connect ports if we know them
512 void GxJack::gx_jack_init_port_connection(const gx_system::CmdlineOptions& opt) {
513  // set autoconnect capture to user capture port
514  if (!opt.get_jack_input().empty()) {
515  jack_connect(client, opt.get_jack_input().c_str(),
516  jack_port_name(ports.input.port));
517  } else {
518  list<string>& l = ports.input.conn;
519  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
520  jack_connect(client, i->c_str(), jack_port_name(ports.input.port));
521  }
522  }
523 
524  // set autoconnect midi to user midi port
525  if (ports.midi_input.port && !opt.get_jack_midi().empty()) {
526  jack_connect(client, opt.get_jack_midi().c_str(),
527  jack_port_name(ports.midi_input.port));
528  } else {
529  list<string>& l = ports.midi_input.conn;
530  for (list<string>::iterator i = l.begin(); i != l.end(); ++i) {
531  jack_connect(client, i->c_str(), jack_port_name(ports.midi_input.port));
532  }
533  }
534 
535  if (!single_client) {
536  // set autoconnect to user playback ports
537  if (opt.get_jack_output(0).empty() && opt.get_jack_output(1).empty()) {
538  list<string>& l1 = ports.output1.conn;
539  for (list<string>::iterator i = l1.begin(); i != l1.end(); ++i) {
540  jack_connect(client_insert, jack_port_name(ports.output1.port), i->c_str());
541  }
542  list<string>& l2 = ports.output2.conn;
543  for (list<string>::iterator i = l2.begin(); i != l2.end(); ++i) {
544  jack_connect(client_insert, jack_port_name(ports.output2.port), i->c_str());
545  }
546  } else {
547  if (!opt.get_jack_output(0).empty()) {
548  jack_connect(client_insert,
549  jack_port_name(ports.output1.port),
550  opt.get_jack_output(0).c_str());
551  }
552  if (!opt.get_jack_output(1).empty()) {
553  jack_connect(client_insert,
554  jack_port_name(ports.output2.port),
555  opt.get_jack_output(1).c_str());
556  }
557  }
558 
559  } else {
560 // set autoconnect to user playback ports
561  if (opt.get_jack_output(0).empty() && opt.get_jack_output(1).empty()) {
562  list<string>& l1 = ports.output1.conn;
563  for (list<string>::iterator i = l1.begin(); i != l1.end(); ++i) {
564  jack_connect(client, jack_port_name(ports.output1.port), i->c_str());
565  }
566  list<string>& l2 = ports.output2.conn;
567  for (list<string>::iterator i = l2.begin(); i != l2.end(); ++i) {
568  jack_connect(client, jack_port_name(ports.output2.port), i->c_str());
569  }
570  } else {
571  if (!opt.get_jack_output(0).empty()) {
572  jack_connect(client,
573  jack_port_name(ports.output1.port),
574  opt.get_jack_output(0).c_str());
575  }
576  if (!opt.get_jack_output(1).empty()) {
577  jack_connect(client,
578  jack_port_name(ports.output2.port),
579  opt.get_jack_output(1).c_str());
580  }
581  }
582 
583  }
584 
585 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
586  // autoconnect midi output port
587  list<string>& lmo = ports.midi_output.conn;
588  for (list<string>::iterator i = lmo.begin(); i != lmo.end(); ++i) {
589  jack_connect(client, jack_port_name(ports.midi_output.port), i->c_str());
590  }
591 #endif
592 
593  if (!single_client) {
594  // autoconnect to insert ports
595  list<string>& lins_in = ports.insert_in.conn;
596  list<string>& lins_out = ports.insert_out.conn;
597  bool ifound = false, ofound = false;
598  for (list<string>::iterator i = lins_in.begin(); i != lins_in.end(); ++i) {
599  int rc = jack_connect(client_insert, replace_clientvar(*i).c_str(),
600  jack_port_name(ports.insert_in.port));
601  if (rc == 0 || rc == EEXIST) {
602  ifound = true;
603  }
604  }
605  jack_port_t* port_a = jack_port_by_name(client, jack_port_name(ports.insert_out.port));
606  for (list<string>::iterator i = lins_out.begin(); i != lins_out.end(); ++i) {
607  std::string port = replace_clientvar(*i);
608  if (!jack_port_connected_to(port_a, port.c_str())) {
609  int rc = jack_connect(client, jack_port_name(ports.insert_out.port),
610  port.c_str());
611  if (rc == 0 || rc == EEXIST) {
612  ofound = true;
613  }
614  } else {
615  ofound = true;
616  }
617  }
618  if (!ifound || !ofound) {
619  jack_connect(client_insert, jack_port_name(ports.insert_out.port),
620  (client_insert_name+":in_0").c_str());
621  }
622  }
623 }
624 
625 
626 /****************************************************************
627  ** callback installation and port registration
628  */
629 
630 // ----- set gxjack.client callbacks and activate gxjack.client
631 void GxJack::gx_jack_callbacks() {
632  // ----- set the jack callbacks
633  jack_set_xrun_callback(client, gx_jack_xrun_callback, this);
634  jack_set_sample_rate_callback(client, gx_jack_srate_callback, this);
635  jack_on_shutdown(client, shutdown_callback_client, this);
636  if (!single_client) {
637  jack_on_shutdown(client_insert, shutdown_callback_client_insert, this);
638  }
639  jack_set_buffer_size_callback(client, gx_jack_buffersize_callback, this);
640  jack_set_port_registration_callback(client, gx_jack_portreg_callback, this);
641  jack_set_port_connect_callback(client, gx_jack_portconn_callback, this);
642 #ifdef HAVE_JACK_SESSION
643  if (jack_set_session_callback_fp) {
644  jack_set_session_callback_fp(client, gx_jack_session_callback, this);
645  if (!single_client) jack_set_session_callback_fp(client_insert, gx_jack_session_callback_ins, this);
646  }
647 #endif
648 
649  // register ports for gx_amp
650  ports.input.port = jack_port_register(
651  client, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
652  ports.midi_input.port = jack_port_register(
653  client, "midi_in_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
654  if (!single_client) {
655  ports.insert_out.port = jack_port_register(
656  client, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
657  } else {
658  ports.output1.port = jack_port_register(
659  client, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
660  ports.output2.port = jack_port_register(
661  client, "out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
662  }
663 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
664  ports.midi_output.port = jack_port_register(
665  client, "midi_out_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
666 #else
667  ports.midi_output.port = 0;
668 #endif
669 
670  if (!single_client) {
671  // register ports for gx_amp_fx
672  ports.insert_in.port = jack_port_register(
673  client_insert, "in_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
674  ports.output1.port = jack_port_register(
675  client_insert, "out_0", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
676  ports.output2.port = jack_port_register(
677  client_insert, "out_1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
678  }
679 
680  engine.init(jack_sr, jack_bs, SCHED_FIFO,
681  jack_client_real_time_priority(client));
682  jack_set_process_callback(client, gx_jack_process, this);
683  if (!single_client) jack_set_process_callback(client_insert, gx_jack_insert_process, this);
684  if (jack_activate(client) != 0) {
686  _("Jack Activation"),
687  string(_("Can't activate JACK gx_amp client")));
688  }
689  if (!single_client) {
690  if (jack_activate(client_insert) != 0) {
691  gx_print_fatal(_("Jack Activation"),
692  string(_("Can't activate JACK gx_amp_fx client")));
693  }
694  }
695 }
696 
697 
698 /****************************************************************
699  ** jack process callbacks
700  */
701 
702 void __rt_func GxJack::process_midi_cc(void *buf, jack_nframes_t nframes) {
703  // midi CC output processing
704  for(int i = 0;i<5;i++) {
705  if (mmessage.send_cc[i]) {
706  unsigned char* midi_send = jack_midi_event_reserve(buf, i, mmessage.me_num[i]);
707 
708  if (midi_send) {
709  if (mmessage.me_num[i] == 2) {
710  // program value
711  midi_send[1] = mmessage.pg_num[i];
712  // controller+ channel
713  midi_send[0] = mmessage.cc_num[i] | 0;
714  } else if (mmessage.me_num[i] == 3) {
715  midi_send[2] = mmessage.bg_num[i];
716  // program value
717  midi_send[1] = mmessage.pg_num[i];
718  // controller+ channel
719  midi_send[0] = mmessage.cc_num[i] | 0;
720  }
721  }
722  mmessage.send_cc[i] = false;
723  }
724  }
725 }
726 
727 // must only be used inside gx_jack_process
728 void *GxJack::get_midi_buffer(jack_nframes_t nframes) {
729  if (!ports.midi_output.port) {
730  return 0;
731  }
732  void *midi_port_buf = jack_port_get_buffer(ports.midi_output.port, nframes);
733  if (midi_port_buf) {
734  jack_midi_clear_buffer(midi_port_buf);
735  }
736  return midi_port_buf;
737 }
738 
739 static inline float *get_float_buf(jack_port_t *port, jack_nframes_t nframes) {
740  return static_cast<float *>(jack_port_get_buffer(port, nframes));
741 }
742 
743 inline void GxJack::check_overload() {
744  if (!rt_watchdog_check_alive(jack_bs, jack_sr)) {
745  engine.overload(gx_engine::EngineControl::ov_User, "watchdog thread");
746  }
747 }
748 
749 // ----- main jack process method gx_amp, mono -> mono
750 // RT process thread
751 int __rt_func GxJack::gx_jack_process(jack_nframes_t nframes, void *arg) {
753  GxJack& self = *static_cast<GxJack*>(arg);
754  if (!self.is_jack_exit()) {
755  if (!self.engine.mono_chain.is_stopped()) {
756  self.check_overload();
757  }
758  self.transport_state = jack_transport_query (self.client, &self.current);
759  // gx_head DSP computing
760  float *obuf = self.insert_buffer;
761  if (!self.single_client) {
762  obuf = get_float_buf(self.ports.insert_out.port, nframes);
763  }
764  self.engine.mono_chain.process(
765  nframes,
766  get_float_buf(self.ports.input.port, nframes),
767  obuf);
768 
769  if (self.bypass_insert && !self.single_client) {
770  memcpy(self.insert_buffer, obuf, nframes*sizeof(float));
771  }
772 
773  // midi input processing
774  if (self.ports.midi_input.port) {
775  self.engine.controller_map.compute_midi_in(
776  jack_port_get_buffer(self.ports.midi_input.port, nframes), arg);
777  }
778  // jack transport support
779  if ( self.transport_state != self.old_transport_state) {
780  self.engine.controller_map.process_trans(self.transport_state);
781  self.old_transport_state = self.transport_state;
782  }
783  }
784  // midi CC output processing
785  void *buf = self.get_midi_buffer(nframes);
786  self.process_midi_cc(buf, nframes);
787 
789  self.engine.mono_chain.post_rt_finished();
790  if (self.single_client) {
791  self.gx_jack_insert_process(nframes, arg);
792  }
793  return 0;
794 }
795 
796 // ----- main jack process method, gx_fx_amp, mono -> stereo
797 // RT process_insert thread
798 int __rt_func GxJack::gx_jack_insert_process(jack_nframes_t nframes, void *arg) {
799  GxJack& self = *static_cast<GxJack*>(arg);
801  if (!self.is_jack_exit()) {
802  if (!self.engine.stereo_chain.is_stopped()) {
803  self.check_overload();
804  }
805  // gx_head DSP computing
806  float *ibuf = NULL;
807  if (!self.bypass_insert && !self.single_client) {
808  ibuf = get_float_buf(self.ports.insert_in.port, nframes);
809  } else {
810  ibuf = self.insert_buffer;
811  }
812  self.engine.stereo_chain.process(
813  nframes, ibuf, ibuf,
814  get_float_buf(self.ports.output1.port, nframes),
815  get_float_buf(self.ports.output2.port, nframes));
816  }
818  self.engine.stereo_chain.post_rt_finished();
819  return 0;
820 }
821 
822 
823 /****************************************************************
824  ** port connection callback
825  */
826 
828  : ring(jack_ringbuffer_create(20*sizeof(PortConnData))), // just a number...
829  send_changes(false),
830  overflow(false),
831  new_data(),
832  portchange() {
833  if (!ring) {
835  _("Jack init"), _("can't get memory for ringbuffer"));
836  }
837  jack_ringbuffer_mlock(ring);
838 }
839 
841  jack_ringbuffer_free(ring);
842 }
843 
844 void PortConnRing::push(const char *a, const char *b, bool conn) {
845  if (is_overflow()) {
846  return;
847  }
848  if (send_changes) {
849  PortConnData p(a, b, conn);
850  size_t sz = jack_ringbuffer_write(ring, reinterpret_cast<const char*>(&p), sizeof(p));
851  if (sz != sizeof(p)) {
852  set_overflow();
853  } else {
854  jack_ringbuffer_write_advance(ring, sz);
855  }
856  }
857  new_data();
858 }
859 
861  if (is_overflow()) {
862  jack_ringbuffer_reset(ring);
863  portchange();
864  clear_overflow();
865  return false;
866  }
867  size_t sz = jack_ringbuffer_read(ring, reinterpret_cast<char*>(p), sizeof(*p));
868  if (sz == 0) {
869  return false;
870  }
871  assert(sz == sizeof(*p));
872  jack_ringbuffer_read_advance(ring, sz);
873  return true;
874 }
875 
876 void GxJack::fetch_connection_data() {
877  // check if we are connected
878  if (client) {
879  const char** port = jack_port_get_connections(ports.input.port);
880  if (port) { // might be 0 (e.g. due to race conditions)
881  engine.clear_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
882  free(port);
883  } else {
884  engine.set_stateflag(gx_engine::GxEngine::SF_NO_CONNECTION);
885  }
886  }
887  while (true) {
888  PortConnData p;
889  bool fetched = connection_queue.pop(&p);
890  if (!fetched) {
891  break;
892  }
893  if (client) {
894  connection_changed(p.name_a, p.name_b, p.connect);
895  }
896  }
897 }
898 
899 // jackd1: RT process thread
900 // jackd2: not RT thread
901 void GxJack::gx_jack_portconn_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg) {
902  GxJack& self = *static_cast<GxJack*>(arg);
903  if (!self.client) {
904  return;
905  }
906  jack_port_t* port_a = jack_port_by_id(self.client, a);
907  jack_port_t* port_b = jack_port_by_id(self.client, b);
908  if (!port_a || !port_b) {
909  return;
910  }
911  self.connection_queue.push(jack_port_name(port_a), jack_port_name(port_b), connect);
912 }
913 
914 
915 /****************************************************************
916  ** callbacks: portreg, buffersize, samplerate, shutdown, xrun
917  */
918 
919 void GxJack::send_midi_cc(int _cc, int _pg, int _bgn, int _num) {
920  for(int i = 0;i<5;i++) {
921  if (!mmessage.send_cc[i]) {
922  mmessage.send_cc[i] = true;
923  mmessage.cc_num[i] = _cc;
924  mmessage.pg_num[i] = _pg;
925  mmessage.bg_num[i] = _bgn;
926  mmessage.me_num[i] = _num;
927  return;
928  }
929  }
930 }
931 
932 // ----- fetch available jack ports other than gx_head ports
933 // jackd1: RT process thread
934 // jackd2: not RT thread
935 void GxJack::gx_jack_portreg_callback(jack_port_id_t pid, int reg, void* arg) {
936  GxJack& self = *static_cast<GxJack*>(arg);
937  if (!self.client) {
938  return;
939  }
940  jack_port_t* port = jack_port_by_id(self.client, pid);
941  if (!port || jack_port_is_mine(self.client, port)) {
942  return;
943  }
944  self.connection_queue.portchange();
945 }
946 
947 // ----jack sample rate change callback
948 // seems to be run in main thread (just once, no possibility
949 // to change the samplerate when jack is running?)
950 int GxJack::gx_jack_srate_callback(jack_nframes_t samplerate, void* arg) {
951  GxJack& self = *static_cast<GxJack*>(arg);
952  if (self.jack_sr == samplerate) {
953  return 0;
954  }
956  self.jack_sr = samplerate;
957  self.engine.set_samplerate(samplerate);
958  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
959  return 0;
960 }
961 
962 // ---- jack buffer size change callback
963 // RT process thread
964 int GxJack::gx_jack_buffersize_callback(jack_nframes_t nframes, void* arg) {
965  GxJack& self = *static_cast<GxJack*>(arg);
966  if (self.jack_bs == nframes) {
967  return 0;
968  }
970  self.jack_bs = nframes;
971  self.engine.set_buffersize(nframes);
972  self.engine.clear_stateflag(gx_engine::GxEngine::SF_JACK_RECONFIG);
973  self.buffersize_change();
974  // create buffer to bypass the insert ports
975  delete[] self.insert_buffer;
976  self.insert_buffer = NULL;
977  self.insert_buffer = new float[self.jack_bs];
978  return 0;
979 }
980 
981 // ---- jack shutdown callback in case jackd shuts down on us
982 void GxJack::gx_jack_shutdown_callback() {
983  set_jack_exit(true);
984  engine.set_stateflag(gx_engine::GxEngine::SF_INITIALIZING);
985  shutdown();
986 }
987 
988 void GxJack::shutdown_callback_client(void *arg) {
989  GxJack& self = *static_cast<GxJack*>(arg);
990  if (self.client) {
991  self.client = 0;
992  self.client_change_rt();
993  }
994  if (!self.single_client) {
995  if (self.client_insert) {
996  jack_client_close(self.client_insert);
997  self.client_insert = 0;
998  }
999  }
1000  self.gx_jack_shutdown_callback();
1001 }
1002 
1003 void GxJack::shutdown_callback_client_insert(void *arg) {
1004  GxJack& self = *static_cast<GxJack*>(arg);
1005  self.client_insert = 0;
1006  if (self.client) {
1007  jack_client_close(self.client);
1008  self.client = 0;
1009  self.client_change_rt();
1010  }
1011  self.gx_jack_shutdown_callback();
1012 }
1013 
1014 void GxJack::report_xrun_clear() {
1015  xrun_msg_blocked = false;
1016 }
1017 
1018 void GxJack::report_xrun() {
1019  if (xrun_msg_blocked) {
1020  return;
1021  }
1022  xrun_msg_blocked = true;
1023  Glib::signal_timeout().connect_once(
1024  sigc::mem_fun(this, &GxJack::report_xrun_clear), 100);
1026  _("Jack XRun"),
1027  (boost::format(_(" delay of at least %1% microsecs")) % last_xrun).str());
1028 }
1029 
1030 // ---- jack xrun callback
1031 int GxJack::gx_jack_xrun_callback(void* arg) {
1032  GxJack& self = *static_cast<GxJack*>(arg);
1033  if (!self.client) {
1034  return 0;
1035  }
1036  self.last_xrun = jack_get_xrun_delayed_usecs(self.client);
1037  if (!self.engine.mono_chain.is_stopped()) {
1038  self.engine.overload(gx_engine::EngineControl::ov_XRun, "xrun");
1039  }
1040  self.xrun();
1041  return 0;
1042 }
1043 
1044 /****************************************************************
1045  ** jack session
1046  */
1047 
1048 #ifdef HAVE_JACK_SESSION
1049 jack_set_session_callback_type GxJack::jack_set_session_callback_fp =
1050  reinterpret_cast<jack_set_session_callback_type>(
1051  dlsym(RTLD_DEFAULT, "jack_set_session_callback"));
1052 jack_get_uuid_for_client_name_type GxJack::jack_get_uuid_for_client_name_fp =
1053  reinterpret_cast<jack_get_uuid_for_client_name_type>(
1054  dlsym(RTLD_DEFAULT, "jack_get_uuid_for_client_name"));
1055 jack_client_get_uuid_type GxJack::jack_client_get_uuid_fp =
1056  reinterpret_cast<jack_client_get_uuid_type>(
1057  dlsym(RTLD_DEFAULT, "jack_client_get_uuid"));
1058 
1059 int GxJack::return_last_session_event() {
1060  jack_session_event_t *event = get_last_session_event();
1061  if (event) {
1062  session_callback_seen += 1;
1063  jack_session_reply(client, event);
1064  jack_session_event_free(event);
1065  gx_system::atomic_set_0(&session_event);
1066  }
1067  return session_callback_seen;
1068 }
1069 
1070 int GxJack::return_last_session_event_ins() {
1071  jack_session_event_t *event = get_last_session_event_ins();
1072  if (event) {
1073  session_callback_seen -= 1;
1074  jack_session_reply(client_insert, event);
1075  jack_session_event_free(event);
1076  gx_system::atomic_set_0(&session_event_ins);
1077  }
1078  return session_callback_seen;
1079 }
1080 
1081 string GxJack::get_uuid_insert() {
1082  // should be const char* but jack_free doesn't like it
1083  char* uuid;
1084  if (jack_client_get_uuid_fp) {
1085  uuid = jack_client_get_uuid_fp(client_insert);
1086  } else if (jack_get_uuid_for_client_name_fp) {
1087  uuid = jack_get_uuid_for_client_name_fp(
1088  client_insert, client_insert_name.c_str());
1089  } else {
1090  assert(false);
1091  gx_print_error(_("session save"), _("can't get client uuid"));
1092  return "";
1093  }
1094  string ret(uuid);
1095  jack_free(uuid);
1096  return ret;
1097 }
1098 
1099 void GxJack::gx_jack_session_callback(jack_session_event_t *event, void *arg) {
1100  GxJack& self = *static_cast<GxJack*>(arg);
1101  jack_session_event_t *np = 0;
1102  if (!gx_system::atomic_compare_and_exchange(&self.session_event, np, event)) {
1103  gx_print_error("jack","last session not cleared");
1104  return;
1105  }
1106  self.session();
1107 }
1108 
1109 void GxJack::gx_jack_session_callback_ins(jack_session_event_t *event, void *arg) {
1110  GxJack& self = *static_cast<GxJack*>(arg);
1111  jack_session_event_t *np = 0;
1112  if (!gx_system::atomic_compare_and_exchange(&self.session_event_ins, np, event)) {
1113  gx_print_error("jack","last session not cleared");
1114  return;
1115  }
1116  self.session_ins();
1117 }
1118 #endif
1119 
1120 } /* 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:498
void read_connections(gx_system::JsonParser &jp)
Definition: gx_jack.cpp:159
int bg_num[5]
Definition: gx_jack.h:107
void push(const char *a, const char *b, bool conn)
Definition: gx_jack.cpp:844
void process_midi_cc(void *buf, jack_nframes_t nframes)
Definition: gx_jack.cpp:702
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:7
static void rt_watchdog_set_limit(int limit)
Definition: gx_jack.cpp:147
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:503
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
bool get_jack_single() const
Definition: gx_system.h:505
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:728
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:919
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:502
void write_connections(gx_system::JsonWriter &w)
Definition: gx_jack.cpp:219
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:846
bool get_jack_noconnect() const
Definition: gx_system.h:504
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:500
const Glib::ustring & get_jack_midi() const
Definition: gx_system.h:501
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:499
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:461
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:860
void AVOIDDENORMALS()
Definition: gx_system.h:73
void end_object(bool nl=false)
Definition: gx_json.cpp:176