Guitarix
gx_system.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 system interface
21  *
22  * ----------------------------------------------------------------------------
23  */
24 
25 #include <dirent.h>
26 #include <iostream>
27 #include <iomanip> // NOLINT
28 
29 #include "engine.h"
30 
31 namespace gx_system {
32 
33 /****************************************************************
34  ** Measuring times (only when debugging)
35  */
36 
37 #ifndef NDEBUG
38 
40  period.reset();
41  duration.reset();
42  duration1.reset();
43  duration2.reset();
44  FPUStatus1 = 0;
45  FPUStatus2 = 0;
46  MXStatus1 = 0;
47  MXStatus2 = 0;
48 }
49 
50 void Measure::print_accum(const Accum& accum, const char* prefix, bool verbose, int total) const {
51  streamsize prec = cout.precision();
52  ios_base::fmtflags flags = cout.flags();
53  cout << prefix << "mean: " << fixed << setprecision(4) << ns2ms(accum.mean());
54  if (total > 0) {
55  cout << " (" << setprecision(2) << 100.0*accum.mean()/static_cast<float>(total) << "%)";
56  }
57  cout << ", min: " << setprecision(4) << ns2ms(accum.minimum())
58  << ", max: " << ns2ms(accum.maximum());
59  if (total > 0) {
60  cout << " (" << setprecision(2) << 100.0*accum.maximum()/static_cast<float>(total) << "%)";
61  }
62  if (verbose) {
63  cout << ", stddev: " << setprecision(4) << ns2ms(accum.stddev())
64  << ", n: " << accum.count();
65  }
66  cout << endl;
67  cout.precision(prec);
68  cout.flags(flags);
69 }
70 
71 static void print_status(const char *title, unsigned int status) {
72  // print list of names for active bits in "status"
73  // bits for mmx and x87 have different symbolic names in
74  // header files but are actually identical so that this function
75  // can be used for both types status word
76  Glib::ustring s;
77  if (status & FE_INVALID) {
78  if (!s.empty()) {
79  s += ",";
80  }
81  s += "invalid";
82  }
83 #ifdef FE_DENORM
84  if (status & FE_DENORM) {
85  if (!s.empty()) {
86  s += ",";
87  }
88  s += "denormal";
89  }
90 #endif
91  if (status & FE_DIVBYZERO) {
92  if (!s.empty()) {
93  s += ",";
94  }
95  s += "zerodivide";
96  }
97  if (status & FE_OVERFLOW) {
98  if (!s.empty()) {
99  s += ",";
100  }
101  s += "overflow";
102  }
103  if (status & FE_UNDERFLOW) {
104  if (!s.empty()) {
105  s += ",";
106  }
107  s += "underflow";
108  }
109  if (!s.empty()) {
110  cout << title << s << endl;
111  }
112 }
113 
114 void Measure::print(bool verbose) const {
115  if (verbose) {
116  print_accum(period, "period ", verbose);
117  print_accum(duration1, "duration1 ", verbose, period.mean());
118  print_accum(duration2, "duration2 ", verbose, period.mean());
119  print_accum(duration, "duration ", verbose, period.mean());
120  } else {
121  print_accum(duration, "duration ", false, period.mean());
122  }
123  print_status("FPU status: ", FPUStatus1 | FPUStatus2);
124  print_status("MX status: ", MXStatus1 | MXStatus2);
125 }
126 
128  : m(), pmeasure(m), t1s(), t1e(), t2s(), t1old(), FPUStatus(), MXStatus() {
129 }
130 
131 void MeasureThreadsafe::print(bool verbose) {
132  Measure *p = pmeasure;
133  Measure *pn;
134  if (p == m) {
135  pn = m+1;
136  } else {
137  pn = m;
138  }
139  atomic_set(&pmeasure, pn);
140  p->print(verbose);
141  p->reset();
142 }
143 
145 
147  char *p = getenv("GUITARIX_MEASURE");
148  if (!p) {
149  return;
150  }
151  bool verbose = false;
152  if (strcmp(p, "1") == 0) {
153  verbose = true;
154  }
155  Glib::signal_timeout().connect(
156  sigc::bind_return(
157  sigc::bind(
158  sigc::mem_fun(measure, &MeasureThreadsafe::print),
159  verbose),
160  true),
161  1000);
162 }
163 
164 #endif
165 
166 
167 /****************************************************************
168  ** class SkinHandling
169  */
170 
171 void SkinHandling::set_styledir(const string& style_dir) {
172  // fetch all skin names in directory
173  DIR *d;
174  d = opendir(style_dir.c_str());
175  if (!d) {
176  return;
177  }
178  // look for gx_head_*.rc and extract *-part
179  struct dirent *de;
180  skin_list.clear();
181  while ((de = readdir(d)) != 0) {
182  char *p = de->d_name;
183  if (strncmp(p, "gx_head_", 8) != 0) {
184  continue;
185  }
186  if (strncmp(p, "gx_head_gx", 10) == 0) {
187  continue;
188  }
189  p += 8;
190  int n = strlen(p) - 3;
191  if (strcmp(p+n, ".rc") != 0) {
192  continue;
193  }
194  skin_list.push_back(string(p, n));
195  }
196  closedir(d);
197  sort(skin_list.begin(), skin_list.end());
198 }
199 
200 bool SkinHandling::is_in_list(const string& name) {
201  return index(name) < skin_list.size();
202 }
203 
204 unsigned int SkinHandling::index(const Glib::ustring& name) {
205  unsigned int i = 0;
206  for (; i < skin_list.size(); ++i) {
207  if (skin_list[i] == name) {
208  break;
209  }
210  }
211  return i;
212 }
213 
214 const Glib::ustring& SkinHandling::operator[](unsigned int idx) {
215  if (idx < skin_list.size()) {
216  return skin_list[idx];
217  } else {
218  return empty;
219  }
220 }
221 
222 
223 /****************************************************************
224  ** class PathList
225  */
226 
227 PathList::PathList(const char *env_name): dirs() {
228  if (!env_name) {
229  return;
230  }
231  const char *p = getenv(env_name);
232  if (!p) {
233  return;
234  }
235  while (true) {
236  const char *q = strchr(p, ':');
237  if (q) {
238  int n = q - p;
239  if (n) {
240  add(std::string(p, n));
241  }
242  p = q+1;
243  } else {
244  if (*p) {
245  add(p);
246  }
247  break;
248  }
249  }
250 }
251 
252 bool PathList::contains(const string& d) const {
253  Glib::RefPtr<Gio::File> f = Gio::File::create_for_path(d);
254  for (pathlist::const_iterator i = dirs.begin();
255  i != dirs.end(); ++i) {
256  if (f->equal(*i)) {
257  return true;
258  }
259  }
260  return false;
261 }
262 
263 
264 bool PathList::find_dir(std::string* d, const std::string& filename) const {
265  for (pathlist::const_iterator i = dirs.begin();
266  i != dirs.end(); ++i) {
267  string p = (*i)->get_path();
268  string fn = Glib::build_filename(p, filename);
269  if (access(fn.c_str(), R_OK) == 0) {
270  *d = p;
271  return true;
272  }
273  }
274  return false;
275 }
276 
277 
278 /****************************************************************
279  ** class PrefixConverter
280  */
281 
282 void PrefixConverter::add(char s, const std::string& d) {
283  assert(s != '%');
284  dirs[s] = (d[d.size()-1] == '/' ? d.substr(0,d.size()-1) : d);
285 }
286 
287 std::string PrefixConverter::replace_symbol(const std::string& dir) const {
288  if (dir.size() < 2 || dir[0] != '%') {
289  return dir;
290  }
291  symbol_path_map::const_iterator i = dirs.find(dir[1]);
292  if (i != dirs.end()) {
293  return Glib::build_filename(i->second, dir.substr(2));
294  }
295  if (dir.compare(0, 2, "%%")) {
296  return dir.substr(1);
297  }
298  return dir;
299 }
300 
301 std::string PrefixConverter::replace_path(const std::string& dir) const {
302  for (symbol_path_map::const_iterator i = dirs.begin(); i != dirs.end(); ++i) {
303  size_t n = i->second.size();
304  if (dir.compare(0, n, i->second) == 0) {
305  std::string tail = dir.substr(n);
306  if (Glib::build_filename(i->second, tail) == dir) {
307  std::string sym = "%";
308  sym.push_back(i->first);
309  return sym + tail;
310  }
311  }
312  }
313  if (dir.size() < 2 || dir[0] != '%') {
314  return dir;
315  }
316  return "%" + dir;
317 }
318 
319 
320 /*****************************************************************
321  ** class DirectoryListing
322  */
323 
324 IRFileListing::IRFileListing(const std::string& path) {
325  Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(path);
326  if (file->query_exists()) {
327  Glib::RefPtr<Gio::FileEnumerator> child_enumeration =
328  file->enumerate_children(G_FILE_ATTRIBUTE_STANDARD_NAME
329  "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
330  "," G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
331  Glib::RefPtr<Gio::FileInfo> file_info;
332  while ((file_info = child_enumeration->next_file()) != 0) {
333  if (file_info->get_attribute_string(G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE) == "audio/x-wav") {
334  listing.push_back(
335  FileName(
336  file_info->get_attribute_byte_string(G_FILE_ATTRIBUTE_STANDARD_NAME),
337  file_info->get_attribute_string(G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)));
338  }
339  }
340  } else {
342  "jconvolver",
343  boost::format(_("Error reading file path %1%")) % path);
344  }
345 }
346 
347 static void list_subdirs(const Glib::RefPtr<Gio::File>& file, std::vector<FileName>& dirs, const Glib::ustring& prefix) {
348  Glib::RefPtr<Gio::FileEnumerator> child_enumeration =
349  file->enumerate_children(G_FILE_ATTRIBUTE_STANDARD_NAME
350  "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
351  Glib::RefPtr<Gio::FileInfo> file_info;
352  while ((file_info = child_enumeration->next_file()) != 0) {
353  if (file_info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) {
354  Glib::RefPtr<Gio::File> child = file->get_child(
355  file_info->get_attribute_byte_string(G_FILE_ATTRIBUTE_STANDARD_NAME));
356  dirs.push_back(
357  FileName(
358  child->get_path(),
359  prefix+file_info->get_attribute_string(G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)));
360  list_subdirs(child, dirs, prefix+" ");
361  }
362  }
363 }
364 
365 void list_subdirs(PathList pl, std::vector<FileName>& dirs) {
366  for (PathList::iterator i = pl.begin(); i != pl.end(); ++i) {
367  std::string fn = (*i)->get_path();
368  dirs.push_back(FileName(fn, fn));
369  list_subdirs(*i, dirs, " ");
370  }
371 }
372 
373 
374 /****************************************************************
375  ** class BasicOptions
376  */
377 
378 BasicOptions *BasicOptions::instance = 0;
379 
381  : user_dir(),
382  user_IR_dir(),
383  sys_IR_dir(GX_SOUND_DIR),
384  IR_pathlist(),
385  IR_prefixmap(),
386  builder_dir(GX_BUILDER_DIR) {
387  user_dir = Glib::build_filename(Glib::get_user_config_dir(), "guitarix");
388  user_IR_dir = Glib::build_filename(user_dir, "IR");
389 
390  make_ending_slash(user_dir);
391  make_ending_slash(user_IR_dir);
392  make_ending_slash(sys_IR_dir);
394 
395  // for legacy presets
396  IR_pathlist.add(get_user_IR_dir());
397  IR_pathlist.add(get_sys_IR_dir());
398 
399  // for current presets
400  IR_prefixmap.add('U', get_user_IR_dir());
401  IR_prefixmap.add('S', get_sys_IR_dir());
402 
403  instance = this;
404 }
405 
407  instance = 0;
408 }
409 
410 void BasicOptions::make_ending_slash(string& dirpath) {
411  if (dirpath.empty()) {
412  return;
413  }
414  if (dirpath[dirpath.size()-1] != '/') {
415  dirpath += "/";
416  }
417 }
418 
419 
420 /****************************************************************
421  ** class CmdlineOptions
422  */
423 
424 static inline const char *shellvar(const char *name) {
425  const char *p = getenv(name);
426  return p ? p : "";
427 }
428 
429 #define TCLR(s) "\033[1;32m" s "\033[0m" // light green
430 #define TCLR2(s) TCLR(s), s
431 
433  : BasicOptions(),
434  main_group("",""),
435  optgroup_style("style", TCLR2("GTK style configuration options")),
436  optgroup_jack("jack", TCLR2("JACK configuration options")),
437  optgroup_overload("overload", TCLR2("Switch to bypass mode on overload condition")),
438  optgroup_file("file", TCLR2("File options")),
439  optgroup_debug("debug", TCLR2("Debug options")),
440  version(false), clear(false),
441  jack_input(shellvar("GUITARIX2JACK_INPUTS")),
442  jack_midi(shellvar("GUITARIX2JACK_MIDI")),
443  jack_outputs(),
444  jack_uuid(),
445  jack_uuid2(),
446  jack_noconnect(false),
447  jack_servername(),
448  load_file(shellvar("GUITARIX_LOAD_FILE")),
449  style_dir(GX_STYLE_DIR),
450  factory_dir(GX_FACTORY_DIR),
451  pixmap_dir(GX_PIXMAPS_DIR),
452  old_user_dir(),
453  preset_dir(),
454  pluginpreset_dir(),
455  lv2_preset_dir(),
456  temp_dir(),
457  plugin_dir(),
458  loop_dir(),
459  rcset(shellvar("GUITARIX_RC_STYLE")),
460  nogui(false),
461  rpcport(RPCPORT_DEFAULT),
462  rpcaddress(),
463  onlygui(false),
464  liveplaygui(false),
465  mute(false),
466  setbank(),
467  tuner_tet(),
468  tuner_ref(),
469  sporadic_overload(0),
470  idle_thread_timeout(0),
471  convolver_watchdog(true),
472  xrun_watchdog(false),
473  lterminal(false),
474  a_save(false),
475  auto_save(false),
476 #ifndef NDEBUG
477  dump_parameter(false),
478 #endif
479  skin(style_dir),
480  mainwin_x(-1),
481  mainwin_y(-1),
482  mainwin_height(-1),
483  window_height(600),
484  preset_window_height(220),
485  mul_buffer(1),
486  skin_name("Guitarix"),
487  no_warn_latency(false),
488  system_order_rack_h(false),
489  system_show_value(false),
490  system_show_tooltips(true),
491  system_animations(true),
492  system_show_presets(false),
493  system_show_toolbar(false),
494  system_show_rack(false),
495  reload_lv2_presets(true) {
496  const char* home = getenv("HOME");
497  if (!home) {
498  throw GxFatalError(_("no HOME environment variable"));
499  }
500  old_user_dir = string(home) + "/.gx_head/";
501  plugin_dir = Glib::build_filename(get_user_dir(), "plugins");
502  preset_dir = Glib::build_filename(get_user_dir(), "banks");
503  pluginpreset_dir = Glib::build_filename(get_user_dir(), "pluginpresets");
504  lv2_preset_dir = Glib::build_filename(get_user_dir(), "pluginpresets/lv2");
505  loop_dir = Glib::build_filename(get_pluginpreset_dir(), "loops");
506  temp_dir = Glib::build_filename(get_user_dir(), "temp");
507  const char *tmp = getenv("GUITARIX2JACK_OUTPUTS1");
508  if (tmp && *tmp) {
509  jack_outputs.push_back(tmp);
510  }
511  tmp = getenv("GUITARIX2JACK_OUTPUTS2");
512  if (tmp && *tmp) {
513  jack_outputs.push_back(tmp);
514  }
515 
516  read_ui_vars();
517 
518  // ---- parse command line arguments
519  set_summary(
520  "All parameters are optional. Examples:\n"
521  "\tguitarix\n"
522  "\tguitarix -r gx4-black -i system:capture_3\n"
523  "\tguitarix -c -o system:playback_1 -o system:playback_2");
524 
525  // main group
526  Glib::OptionEntry opt_version;
527  opt_version.set_short_name('v');
528  opt_version.set_long_name("version");
529  opt_version.set_description("Print version string and exit");
530  Glib::OptionEntry opt_nogui;
531  opt_nogui.set_short_name('N');
532  opt_nogui.set_long_name("nogui");
533  opt_nogui.set_description("start without GUI");
534  Glib::OptionEntry opt_rpcport;
535  opt_rpcport.set_short_name('p');
536  opt_rpcport.set_long_name("rpcport");
537  opt_rpcport.set_description("start a JSON-RPC server listening on port PORT");
538  opt_rpcport.set_arg_description("PORT");
539  Glib::OptionEntry opt_rpchost;
540  opt_rpchost.set_short_name('H');
541  opt_rpchost.set_long_name("rpchost");
542  opt_rpchost.set_description("set hostname to connect to");
543  opt_rpchost.set_arg_description("HOSTNAME");
544  Glib::OptionEntry opt_onlygui;
545  opt_onlygui.set_short_name('G');
546  opt_onlygui.set_long_name("onlygui");
547  opt_onlygui.set_description("start only GUI");
548  Glib::OptionEntry opt_liveplaygui;
549  opt_liveplaygui.set_short_name('L');
550  opt_liveplaygui.set_long_name("liveplaygui");
551  opt_liveplaygui.set_description("start with Live Play GUI");
552  Glib::OptionEntry opt_mute;
553  opt_mute.set_short_name('M');
554  opt_mute.set_long_name("mute");
555  opt_mute.set_description("start with engine muted");
556  Glib::OptionEntry opt_bank;
557  opt_bank.set_short_name('b');
558  opt_bank.set_long_name("bank");
559  opt_bank.set_description("set bank and preset to load at startup");
560  opt_bank.set_arg_description("BANK:PRESET (A:0-Z:9)");
561  Glib::OptionEntry opt_tuner_tet;
562  opt_tuner_tet.set_short_name('t');
563  opt_tuner_tet.set_long_name("tuner_tet");
564  opt_tuner_tet.set_description("set tuner temperament at startup");
565  opt_tuner_tet.set_arg_description("tuner temperament (12, 19, 24, 31, 53)");
566  Glib::OptionEntry opt_tuner_ref;
567  opt_tuner_ref.set_short_name('F');
568  opt_tuner_ref.set_long_name("reference_pitch");
569  opt_tuner_ref.set_description("set tuner reference pitch at startup");
570  opt_tuner_ref.set_arg_description("tuner reference pitch (225 - 453)");
571  main_group.add_entry(opt_version, version);
572  main_group.add_entry(opt_nogui, nogui);
573  main_group.add_entry(opt_rpcport, rpcport);
574  main_group.add_entry(opt_rpchost, rpcaddress);
575  main_group.add_entry(opt_onlygui, onlygui);
576  main_group.add_entry(opt_liveplaygui, liveplaygui);
577  main_group.add_entry(opt_mute, mute);
578  main_group.add_entry(opt_bank, setbank);
579  main_group.add_entry(opt_tuner_tet, tuner_tet);
580  main_group.add_entry(opt_tuner_ref, tuner_ref);
581  set_main_group(main_group);
582 
583  // style options
584  Glib::OptionEntry opt_clear;
585  opt_clear.set_short_name('c');
586  opt_clear.set_long_name("clear");
587  opt_clear.set_description("Use 'default' GTK style");
588  Glib::OptionEntry opt_rcset;
589  opt_rcset.set_short_name('r');
590  opt_rcset.set_long_name("rcset");
591  opt_rcset.set_description(get_opskin());
592  opt_rcset.set_arg_description("STYLE");
593  optgroup_style.add_entry(opt_clear, clear);
594  optgroup_style.add_entry(opt_rcset, rcset);
595 
596  // JACK options
597  Glib::OptionEntry opt_jack_input;
598  opt_jack_input.set_short_name('i');
599  opt_jack_input.set_long_name("jack-input");
600  opt_jack_input.set_description("Guitarix JACK input");
601  opt_jack_input.set_arg_description("PORT");
602  Glib::OptionEntry opt_jack_output;
603  opt_jack_output.set_short_name('o');
604  opt_jack_output.set_long_name("jack-output");
605  opt_jack_output.set_description("Guitarix JACK outputs");
606  opt_jack_output.set_arg_description("PORT");
607  Glib::OptionEntry opt_jack_midi;
608  opt_jack_midi.set_short_name('m');
609  opt_jack_midi.set_long_name("jack-midi");
610  opt_jack_midi.set_description("Guitarix JACK midi control");
611  opt_jack_midi.set_arg_description("PORT");
612  Glib::OptionEntry opt_jack_noconnect;
613  opt_jack_noconnect.set_short_name('J');
614  opt_jack_noconnect.set_long_name("jack-no-conect");
615  opt_jack_noconnect.set_description("dissable self-connect JACK ports");
616  Glib::OptionEntry opt_jack_instance;
617  opt_jack_instance.set_short_name('n');
618  opt_jack_instance.set_long_name("name");
619  opt_jack_instance.set_description("instance name (default gx_head)");
620  opt_jack_instance.set_arg_description("NAME");
621  Glib::OptionEntry opt_jack_uuid;
622  opt_jack_uuid.set_short_name('U');
623  opt_jack_uuid.set_long_name("jack-uuid");
624  opt_jack_uuid.set_description("JackSession ID");
625  opt_jack_uuid.set_arg_description("UUID");
626  Glib::OptionEntry opt_jack_uuid2;
627  opt_jack_uuid2.set_short_name('A');
628  opt_jack_uuid2.set_long_name("jack-uuid2");
629  opt_jack_uuid2.set_description("JackSession ID");
630  opt_jack_uuid2.set_arg_description("UUID2");
631  Glib::OptionEntry opt_jack_servername;
632  opt_jack_servername.set_short_name('s');
633  opt_jack_servername.set_long_name("server-name");
634  opt_jack_servername.set_description("JACK server name to connect to");
635  opt_jack_servername.set_arg_description("NAME");
636  optgroup_jack.add_entry(opt_jack_input, jack_input);
637  optgroup_jack.add_entry(opt_jack_output, jack_outputs);
638  optgroup_jack.add_entry(opt_jack_midi, jack_midi);
639  optgroup_jack.add_entry(opt_jack_noconnect, jack_noconnect);
640  optgroup_jack.add_entry(opt_jack_instance, jack_instance);
641  optgroup_jack.add_entry(opt_jack_uuid, jack_uuid);
642  optgroup_jack.add_entry(opt_jack_uuid2, jack_uuid2);
643  optgroup_jack.add_entry(opt_jack_servername, jack_servername);
644 
645  // Engine overload options
646  Glib::OptionEntry opt_watchdog_idle;
647  opt_watchdog_idle.set_short_name('I');
648  opt_watchdog_idle.set_long_name("idle-timeout");
649  opt_watchdog_idle.set_description(
650  "starved idle thread probe (default: disabled)");
651  opt_watchdog_idle.set_arg_description("SECONDS");
652  Glib::OptionEntry opt_watchdog_convolver;
653  opt_watchdog_convolver.set_short_name('C');
654  opt_watchdog_convolver.set_long_name("no-convolver-overload");
655  opt_watchdog_convolver.set_description(
656  "disable overload on convolver missed deadline");
657  opt_watchdog_convolver.set_flags(Glib::OptionEntry::FLAG_REVERSE);
658  Glib::OptionEntry opt_watchdog_xrun;
659  opt_watchdog_xrun.set_short_name('X');
660  opt_watchdog_xrun.set_long_name("xrun-overload");
661  opt_watchdog_xrun.set_description(
662  "JACK xrun (default: false)");
663  Glib::OptionEntry opt_sporadic_overload;
664  opt_sporadic_overload.set_short_name('S');
665  opt_sporadic_overload.set_long_name("sporadic");
666  opt_sporadic_overload.set_description(
667  "allow single overload events per interval (default: disabled)");
668  opt_sporadic_overload.set_arg_description("SECONDS");
669  optgroup_overload.add_entry(opt_watchdog_idle, idle_thread_timeout);
670  optgroup_overload.add_entry(opt_watchdog_convolver, convolver_watchdog);
671  optgroup_overload.add_entry(opt_watchdog_xrun, xrun_watchdog);
672  optgroup_overload.add_entry(opt_sporadic_overload, sporadic_overload);
673 
674  // FILE options
675  Glib::OptionEntry opt_load_file;
676  opt_load_file.set_short_name('f');
677  opt_load_file.set_long_name("load-file");
678  opt_load_file.set_description(_("load state file on startup"));
679  opt_load_file.set_arg_description("FILE");
680  optgroup_file.add_entry_filename(opt_load_file, load_file);
681  Glib::OptionEntry opt_plugin_dir;
682  opt_plugin_dir.set_short_name('P');
683  opt_plugin_dir.set_long_name("plugin-dir");
684  opt_plugin_dir.set_description(_("directory with guitarix plugins (.so files)"));
685  opt_plugin_dir.set_arg_description("DIR");
686  optgroup_file.add_entry_filename(opt_plugin_dir, plugin_dir);
687  Glib::OptionEntry opt_save_on_exit;
688  opt_save_on_exit.set_short_name('K');
689  opt_save_on_exit.set_long_name("disable-save-on-exit");
690  opt_save_on_exit.set_description(_("disable auto save to state file when quit"));
691  optgroup_file.add_entry(opt_save_on_exit, a_save);
692  Glib::OptionEntry opt_auto_save;
693  opt_auto_save.set_short_name('a');
694  opt_auto_save.set_long_name("auto-save");
695  opt_auto_save.set_description(_("enable auto save (only in server mode)"));
696  optgroup_file.add_entry(opt_auto_save, auto_save);
697 
698  // DEBUG options
699  Glib::OptionEntry opt_builder_dir;
700  opt_builder_dir.set_short_name('B');
701  opt_builder_dir.set_long_name("builder-dir");
702  opt_builder_dir.set_description(_("directory from which .glade files are loaded"));
703  opt_builder_dir.set_arg_description("DIR");
704  optgroup_debug.add_entry_filename(opt_builder_dir, builder_dir);
705  Glib::OptionEntry opt_style_dir;
706  opt_style_dir.set_short_name('S');
707  opt_style_dir.set_long_name("style-dir");
708  opt_style_dir.set_description(_("directory with skin style definitions (.rc files)"));
709  opt_style_dir.set_arg_description("DIR");
710  optgroup_debug.add_entry_filename(opt_style_dir, style_dir);
711  Glib::OptionEntry opt_log_terminal;
712  opt_log_terminal.set_short_name('t');
713  opt_log_terminal.set_long_name("log-terminal");
714  opt_log_terminal.set_description(_("print log on terminal"));
715  optgroup_debug.add_entry(opt_log_terminal, lterminal);
716 #ifndef NDEBUG
717  Glib::OptionEntry opt_dump_parameter;
718  opt_dump_parameter.set_short_name('d');
719  opt_dump_parameter.set_long_name("dump-parameter");
720  opt_dump_parameter.set_description(_("dump parameter table in json format"));
721  optgroup_debug.add_entry(opt_dump_parameter, dump_parameter);
722 #endif
723 
724  // collecting all option groups
725  add_group(optgroup_style);
726  add_group(optgroup_jack);
727  add_group(optgroup_overload);
728  add_group(optgroup_file);
729  add_group(optgroup_debug);
730 }
731 
733  write_ui_vars();
734 }
735 
736 void CmdlineOptions::read_ui_vars() {
737  ifstream i(Glib::build_filename(get_user_dir(), "ui_rc").c_str());
738  if (i.fail()) {
739  return;
740  }
741  JsonParser jp(&i);
742  try {
744  while (jp.peek() != JsonParser::end_object) {
746  if (jp.current_value() == "system.mainwin_x") {
749  } else if (jp.current_value() == "system.mainwin_y") {
752  } else if (jp.current_value() == "system.mainwin_height") {
755  } else if (jp.current_value() == "system.mainwin_rack_height") {
758  } else if (jp.current_value() == "system.preset_window_height") {
761  } else if (jp.current_value() == "system.mul_buffer") {
764  } else if (jp.current_value() == "ui.skin_name") {
766  skin_name = jp.current_value();
767  } else if (jp.current_value() == "ui.latency_nowarn") {
770  } else if (jp.current_value() == "system.order_rack_h") {
773  } else if (jp.current_value() == "system.show_value") {
776  } else if (jp.current_value() == "system.show_tooltips") {
779  } else if (jp.current_value() == "system.animations") {
782  } else if (jp.current_value() == "system.show_presets") {
785  } else if (jp.current_value() == "system.show_toolbar") {
788  } else if (jp.current_value() == "system.show_rack") {
791  }
792  }
794  jp.close();
795  } catch (JsonException) {
796  gx_print_warning("main", "can't read/parse ui_rc");
797  }
798  i.close();
799 }
800 
801 void CmdlineOptions::write_ui_vars() {
802  ofstream o(Glib::build_filename(get_user_dir(), "ui_rc").c_str());
803  if (o.fail()) {
804  return;
805  }
806  JsonWriter jw(&o);
807  try {
808  jw.begin_object(true);
809  jw.write_kv("system.mainwin_x", mainwin_x);
810  jw.write_kv("system.mainwin_y", mainwin_y);
811  jw.write_kv("system.mainwin_height", mainwin_height);
812  jw.write_kv("system.mainwin_rack_height", window_height);
813  jw.write_kv("system.preset_window_height", preset_window_height);
814  jw.write_kv("system.mul_buffer", mul_buffer);
815  jw.write_kv("ui.skin_name", skin_name);
816  jw.write_kv("ui.latency_nowarn", no_warn_latency);
817  jw.write_kv("system.order_rack_h", system_order_rack_h);
818  jw.write_kv("system.show_value", system_show_value);
819  jw.write_kv("system.show_tooltips", system_show_tooltips);
820  jw.write_kv("system.animations", system_animations);
821  jw.write_kv("system.show_presets", system_show_presets);
822  jw.write_kv("system.show_toolbar", system_show_toolbar);
823  jw.write_kv("system.show_rack", system_show_rack);
824  jw.end_object(true);
825  jw.close();
826  } catch (JsonException) {
827  gx_print_warning("main", "can't write ui_rc");
828  }
829  o.close();
830 }
831 
832 Glib::ustring CmdlineOptions::get_jack_output(unsigned int n) const {
833  if (n >= jack_outputs.size()) {
834  return "";
835  }
836  return jack_outputs.at(n);
837 }
838 
839 string CmdlineOptions::get_opskin() {
840  // GTK options: rc style (aka skin)
841  string opskin("Style to use");
842 
843  // initialize number of skins. We just count the number of rc files
844  unsigned int n = skin.skin_list.size();
845  if (n < 1) {
846  return opskin;
847  }
848 
849  vector<Glib::ustring>::iterator it;
850 
851  for (it = skin.skin_list.begin(); it != skin.skin_list.end(); ++it) {
852  opskin += ", '" + *it + "'";
853  }
854  return opskin;
855 }
856 
857 static void log_terminal(const string& msg, GxLogger::MsgType tp, bool plugged) {
858  const char *t;
859  switch (tp) {
860  case GxLogger::kInfo: t = "I"; break;
861  case GxLogger::kWarning: t = "W"; break;
862  case GxLogger::kError: t = "E"; break;
863  default: t = "?"; break;
864  }
865  if (!plugged) {
866  cerr << t << " " << msg << endl;
867  }
868 }
869 
870 void CmdlineOptions::process(int argc, char** argv) {
871  path_to_program = Gio::File::create_for_path(argv[0])->get_path();
872  if (version) {
873  std::cout << "Guitarix version \033[1;32m"
874  << GX_VERSION << endl
875  << "\033[0m Copyright " << static_cast<char>(0x40) << " 2010 "
876  << "Hermman Meyer - James Warden - Andreas Degert"
877  << endl;
878  exit(0);
879  }
880 #ifdef NDEBUG
881  if (argc > 1) {
882  throw GxFatalError(
883  string("unknown argument on command line: ")+argv[1]);
884  }
885 #endif
886  if (clear && !rcset.empty()) {
887  throw Glib::OptionError(
888  Glib::OptionError::BAD_VALUE,
889  _("-c and -r cannot be used together"));
890  }
891  if (nogui && liveplaygui) {
892  throw Glib::OptionError(
893  Glib::OptionError::BAD_VALUE,
894  _("-N and -L cannot be used together"));
895  }
896  if (onlygui && !setbank.empty()) {
897  throw Glib::OptionError(
898  Glib::OptionError::BAD_VALUE,
899  _("-G and -b cannot be used together"));
900  }
901  if (lterminal) {
903  sigc::ptr_fun(log_terminal));
904  if (nogui) {
906  }
907  }
908 
910  make_ending_slash(style_dir);
911  make_ending_slash(factory_dir);
912  make_ending_slash(pixmap_dir);
913  make_ending_slash(preset_dir);
914  make_ending_slash(pluginpreset_dir);
915  make_ending_slash(lv2_preset_dir);
916  make_ending_slash(loop_dir);
917  make_ending_slash(temp_dir);
918  make_ending_slash(plugin_dir);
919 
920  skin.set_styledir(style_dir);
921  unsigned int n = skin.skin_list.size();
922  if (n < 1) {
923  gx_print_fatal(_("main"), string(_("number of skins is 0")));
924  }
925  if (!rcset.empty()) {
926  if (skin.is_in_list(rcset)) {
927  skin_name = rcset;
928  } else {
929  throw Glib::OptionError(
930  Glib::OptionError::BAD_VALUE,
931  (boost::format(_("invalid style '%1%' on command line"))
932  % rcset).str());
933  }
934  }
935  if (jack_outputs.size() > 2) {
937  _("main"),
938  _("Warning --> provided more than 2 output ports, ignoring extra ports"));
939  }
940 }
941 
942 
943 /****************************************************************
944  ** misc functions
945  */
946 
947 // ---- gx_head system function
948 int gx_system_call(const string& cmd,
949  const bool devnull,
950  const bool escape) {
951  string str = cmd;
952 
953  if (devnull)
954  str.append(" 1>/dev/null 2>&1");
955 
956  if (escape)
957  str.append("&");
958 
959  // cerr << " ********* \n system command = " << str.c_str() << endl;
960 
961  sigset_t waitset;
962  sigemptyset(&waitset);
963  sigaddset(&waitset, SIGCHLD);
964  sigprocmask(SIG_UNBLOCK, &waitset, NULL);
965  int rc = system(str.c_str());
966  sigprocmask(SIG_BLOCK, &waitset, NULL);
967  return rc;
968 }
969 
970 void strip(Glib::ustring& s) {
971  size_t n = s.find_first_not_of(' ');
972  if (n == Glib::ustring::npos) {
973  s.erase();
974  return;
975  }
976  if (n != 0) {
977  s.erase(0, n);
978  }
979  s.erase(s.find_last_not_of(' ')+1);
980 }
981 
982 /*
983 ** encoding / decoding filenames
984 */
985 
986 static inline bool check_char(unsigned char c) {
987  static const char *badchars = "/%?*<>\\:#&$'\"(){}[]~;`|.";
988  if (c < 32) {
989  return false;
990  }
991  for (const char *p = badchars; *p; p++) {
992  if (c == *p) {
993  return false;
994  }
995  }
996  return true;
997 }
998 
999 std::string encode_filename(const std::string& s) {
1000  std::string res;
1001  res.reserve(s.size());
1002  for (unsigned int i = 0; i < s.size(); i++) {
1003  unsigned char c = s[i];
1004  if (!check_char(c)) {
1005  res.append(1, '%');
1006  static const unsigned char code[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
1007  res.append(1, code[c / 16]);
1008  res.append(1, code[c % 16]);
1009  } else {
1010  res.append(1, c);
1011  }
1012  }
1013  return res;
1014 }
1015 
1016 static inline bool dct(unsigned char c, int &n) {
1017  if (c < '0') {
1018  return false;
1019  }
1020  if (c <= '9') {
1021  n = c - '0';
1022  return true;
1023  }
1024  if (c < 'a') {
1025  return false;
1026  }
1027  if (c <= 'f') {
1028  n = c - 'a';
1029  return true;
1030  }
1031  return false;
1032 }
1033 
1034 std::string decode_filename(const std::string& s) {
1035  std::string res;
1036  res.reserve(s.size());
1037  for (unsigned int i = 0; i < s.size(); i++) {
1038  unsigned char c = s[i];
1039  if (c == '%') {
1040  int n1, n2;
1041  if (s.size() - i < 3 || !dct(s[i+1],n1) || !dct(s[i+2],n2)) {
1042  // error, don't do any decoding
1043  return s;
1044  }
1045  res.push_back(n1*16 + n2);
1046  i += 2;
1047  } else {
1048  res.push_back(c);
1049  }
1050  }
1051  return res;
1052 }
1053 
1054 
1055 } /* end of gx_system namespace */
PathList(const char *env_name=0)
Definition: gx_system.cpp:227
void write_kv(const char *key, float v)
Definition: gx_json.h:81
float ns2ms(int n) const
Definition: gx_system.h:187
static void make_ending_slash(std::string &dirpath)
Definition: gx_system.cpp:410
const std::string & get_user_IR_dir() const
Definition: gx_system.h:375
#define TCLR2(s)
Definition: gx_system.cpp:430
std::list< Glib::RefPtr< Gio::File > >::const_iterator iterator
Definition: gx_system.h:292
#define RPCPORT_DEFAULT
Definition: gx_system.h:350
iterator end()
Definition: gx_system.h:302
bool contains(const std::string &d) const
Definition: gx_system.cpp:252
const Glib::ustring & operator[](unsigned int idx)
Definition: gx_system.cpp:214
bool is_in_list(const std::string &name)
Definition: gx_system.cpp:200
void print_accum(const Accum &accum, const char *prefix, bool verbose, int total=0) const
Definition: gx_system.cpp:50
MeasureThreadsafe measure
Definition: gx_system.cpp:144
virtual void close()
Definition: gx_json.cpp:277
unsigned int MXStatus2
Definition: gx_system.h:186
Glib::ustring skin_name
Definition: gx_system.h:445
void list_subdirs(PathList pl, std::vector< FileName > &dirs)
Definition: gx_system.cpp:365
int gx_system_call(const std::string &, bool devnull=false, bool escape=false)
Definition: gx_system.cpp:948
IRFileListing(const std::string &path)
Definition: gx_system.cpp:324
std::string decode_filename(const std::string &s)
Definition: gx_system.cpp:1034
void gx_print_fatal(const char *, const std::string &)
Definition: gx_logging.cpp:177
void add(const std::string &d)
Definition: gx_system.h:297
void set_styledir(const std::string &styledir)
Definition: gx_system.cpp:171
bool find_dir(std::string *d, const std::string &filename) const
Definition: gx_system.cpp:264
float minimum() const
Definition: gx_system.h:165
int count() const
Definition: gx_system.h:162
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
static GxLogger & get_logger()
Definition: gx_logging.cpp:50
void process(int argc, char **argv)
Definition: gx_system.cpp:870
const std::string & get_pluginpreset_dir() const
Definition: gx_system.h:474
virtual void close()
Definition: gx_json.cpp:68
void begin_object(bool nl=false)
Definition: gx_json.cpp:168
std::string replace_symbol(const std::string &dir) const
Definition: gx_system.cpp:287
msg_signal & signal_message()
Definition: gx_logging.cpp:77
void print(bool verbose=false)
Definition: gx_system.cpp:131
unsigned int FPUStatus1
Definition: gx_system.h:183
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
void add(char s, const std::string &d)
Definition: gx_system.cpp:282
void strip(Glib::ustring &s)
Definition: gx_system.cpp:970
float stddev() const
Definition: gx_system.h:164
void atomic_set(volatile int *p, int v)
Definition: gx_system.h:90
float mean() const
Definition: gx_system.h:163
Glib::ustring get_jack_output(unsigned int n) const
Definition: gx_system.cpp:832
unsigned int index(const Glib::ustring &name)
Definition: gx_system.cpp:204
float maximum() const
Definition: gx_system.h:166
void print(bool verbose) const
Definition: gx_system.cpp:114
const std::string & get_user_dir() const
Definition: gx_system.h:374
unsigned int FPUStatus2
Definition: gx_system.h:185
string current_value() const
Definition: gx_json.h:143
token next(token expect=no_token)
Definition: gx_json.cpp:496
iterator begin()
Definition: gx_system.h:301
const std::string & get_sys_IR_dir() const
Definition: gx_system.h:376
void add_time_measurement()
Definition: gx_system.cpp:146
unsigned int MXStatus1
Definition: gx_system.h:184
void unplug_queue()
Definition: gx_logging.cpp:82
void end_object(bool nl=false)
Definition: gx_json.cpp:176
std::string replace_path(const std::string &dir) const
Definition: gx_system.cpp:301
std::string builder_dir
Definition: gx_system.h:362
std::vector< Glib::ustring > skin_list
Definition: gx_system.h:278
std::string encode_filename(const std::string &s)
Definition: gx_system.cpp:999