Guitarix
gx_paramtable.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  * parameter and midi data
21  *
22  * ----------------------------------------------------------------------------
23  */
24 
25 #ifndef NDEBUG
26 #include <iostream>
27 #endif
28 
29 #include "engine.h" // NOLINT
30 
31 namespace gx_engine {
32 
33 /****************************************************************
34  ** Global Variables
35  */
36 
37 /* Midi */
38 MidiStandardControllers midi_std_ctr; // map ctrl num -> standard name
39 
40 
41 /****************************************************************
42  ** class MidiStandardControllers
43  */
44 
45 static struct midi_std_init {
46  int ctrl;
47  const char *name;
48 } midi_std_itab[] = {
49  { 0, "Bank Select MSB"},
50  { 1, "Modulation MSB"},
51  { 2, "Breath Controller"},
52 
53  { 4, "Foot Controller MSB"},
54  { 5, "Portamento Time MSB"},
55  { 6, "Data Entry MSB"},
56  { 7, "Main Volume"},
57  { 8, "Balance"},
58 
59  {10, "Pan"},
60  {11, "Expression"},
61  {12, "Effect Control 1"},
62  {13, "Effect Control 2"},
63 
64  {22, "Midi Beat Clock"},
65  {23, "Clock start/stop"},
66  {24, "Jack Transport"},
67 
68  {32, "Bank Select LSB"},
69 
70  {64, "Sustain"},
71  {65, "Portamento"},
72  {66, "Sostenuto"},
73  {67, "Soft Pedal"},
74  {68, "Legato Footswitch"},
75  {69, "Hold 2"},
76  {70, "Sound Contr. 1"}, // default: Sound Variation
77  {71, "Sound Contr. 2"}, // default: Timbre/Harmonic Content
78  {72, "Sound Contr. 3"}, // default: Release Time
79  {73, "Sound Contr. 4"}, // default: Attack Time
80  {74, "Sound Contr. 5"}, // default: Brightness
81  {75, "Sound Contr. 6"},
82  {76, "Sound Contr. 7"},
83  {77, "Sound Contr. 8"},
84  {78, "Sound Contr. 9"},
85  {79, "Sound Contr. 10"},
86 
87  {84, "Portamento Control"},
88 
89  {91, "Eff. 1 Depth"},
90  {92, "Eff. 2 Depth"},
91  {93, "Eff. 3 Depth"},
92  {94, "Eff. 4 Depth"},
93  {95, "Eff. 5 Depth"},
94  {96, "Data Inc"},
95  {97, "Data Dec"},
96  {98, "NRPN LSB"},
97  {99, "NRPN MSB"},
98  {100, "RPN LSB"},
99  {101, "RPN MSB"},
100 
101  {120, "All Sounds Off"},
102  {121, "Controller Reset"},
103  {122, "Local Control"},
104  {123, "All Notes Off"},
105  {124, "Omni Off"},
106  {125, "Omni On"},
107  {126, "Mono On (Poly Off)"},
108  {127, "Poly On (Mono Off)"},
109 };
110 
112  for (unsigned int i = 0; i < sizeof(midi_std_itab)/sizeof(midi_std_itab[0]); i++) {
113  m.insert(pair<int, modstring>(midi_std_itab[i].ctrl, modstring(midi_std_itab[i].name)));
114  }
115 }
116 
117 void MidiStandardControllers::replace(int ctr, const string& name) {
118  map<int, modstring>::iterator i = m.find(ctr);
119  if (name.empty()) {
120  if (i != m.end()) {
121  if (i->second.modified) {
122  if (i->second.std) {
123  i->second.name = m[ctr].std;
124  m[ctr].modified = false;
125  } else {
126  m.erase(i);
127  }
128  }
129  }
130  } else {
131  if (i == m.end()) {
132  m[ctr] = modstring(name, true, 0);
133  } else {
134  i->second.modified = true;
135  i->second.name = name;
136  }
137  }
138 }
139 
141  jw.begin_object(true);
142  for (map<int, modstring>::const_iterator i = m.begin(); i != m.end(); ++i) {
143  if (i->second.modified) {
144  ostringstream ostr;
145  ostr << i->first;
146  jw.write_kv(ostr.str().c_str(), i->second.name);
147  }
148  }
149  jw.end_object(true);
150 }
151 
154  while (jp.peek() == gx_system::JsonParser::value_key) {
155  jp.next();
156  istringstream istr(jp.current_value());
157  int ctl;
158  istr >> ctl;
159  if (istr.fail()) {
160  throw gx_system::JsonException(_("midi standard controllers: number expected"));
161  }
162  jp.next();
163  replace(ctl, jp.current_value());
164  }
166 }
167 
168 
169 /****************************************************************
170  ** class MidiController
171  */
172 
174  jw.begin_array();
175  jw.write(param->id());
176  if (param->getControlType() == Parameter::Continuous ||
177  param->getControlType() == Parameter::Enum) {
178  jw.write(_lower);
179  jw.write(_upper);
180  } else {
181  assert(param->getControlType() == Parameter::Switch);
182  jw.write(toggle);
183  }
184  jw.end_array();
185 }
186 
190  string id = jp.current_value();
191  if (!pmap.hasId(id)) {
192  gx_print_warning(_("Midi controller settings"),
193  _("unknown parameter: ") + id);
194  while (jp.next() != gx_system::JsonParser::end_array);
195  return 0;
196  }
197  Parameter& pm = pmap[id];
198  float lower = 0, upper = 0;
199  bool toggle = false;
200  bool bad = false;
201  bool chg = false;
207  // two numbers -> range
208  float pmin, pmax;
209  if (pm.hasRange()) {
210  pmin = pm.getLowerAsFloat();
211  pmax = pm.getUpperAsFloat();
212  } else {
213  bad = true;
214  pmin = pmax = 0;
215  }
216  lower = jp.current_value_float();
218  upper = jp.current_value_float();
219  if (lower > pmax) {
220  lower = pmax;
221  chg = true;
222  } else if (lower < pmin) {
223  lower = pmin;
224  chg = true;
225  }
226  if (upper > pmax) {
227  upper = pmax;
228  chg = true;
229  } else if (upper < pmin) {
230  upper = pmin;
231  chg = true;
232  }
233  } else {
234  // just one number -> switch (new format)
235  bad = true;
236  }
237  } else {
238  // no number -> switch (old format)
239  bad = true;
240  }
241  } else if (pm.getControlType() == Parameter::Switch) {
245  // two numbers -> range
246  bad = true;
247  } else {
248  toggle = jp.current_value_int();
249  }
250  }
251  } else {
252  // bad control type
253  bad = true;
254  }
255  assert(jp.peek() == gx_system::JsonParser::end_array);
256  while (jp.next() != gx_system::JsonParser::end_array); // be tolerant (non-debug mode)
257  if (bad) {
259  _("recall MIDI state"),
260  _("invalid format, Parameter skipped: ") + id);
261  return 0;
262  }
263  if (chg) {
265  _("recall MIDI state"),
266  _("Parameter range outside bounds, changed: ") + id);
267  }
268  return new MidiController(pm, lower, upper, toggle);
269 }
270 
271 bool MidiController::set_midi(int n, int last_value) {
272  bool ret = false;
273  if (param->get_midi_blocked()) return ret;
274  if (toggle) {
275  bool s_o = (2*last_value > 127);
276  bool s_n = (2*n > 127);
277  if (!s_o && s_n) {
278  if (param->on_off_value()) {
279  ret = param->midi_set(0, 127, _lower, _upper);
280  } else {
281  ret = param->midi_set(127, 127, _lower, _upper);
282  }
283  }
284  } else {
285  //fprintf(stderr,"continues %s \n",param->id().c_str());
286  //fprintf(stderr,"%f \n",(127.*log10f(double(n+1.)))/2.1072);
287  //fprintf(stderr,"%f \n",double(n * double(double(n+1.)/128)));
288 
289  ret = param->midi_set(n, 127, _lower, _upper);
290  }
291  param->trigger_changed();
292  return ret;
293 }
294 
295 bool MidiController::set_trans(int n, int last_value) {
296  bool ret = false;
297  if (param->get_blocked()) return ret;
298  if (strcmp(param->id().c_str(), "engine.mute")==0) {
299  if ( n == 0) n = 127;
300  else n = 0;
301  }
302  ret = param->midi_set(n, 127, _lower, _upper);
303  return ret;
304 }
305 
306 bool MidiController::set_bpm(int n, int last_value) {
307  bool ret = false;
308  if (param->get_blocked()) return ret;
309  if (toggle) {
310  bool s_o = (2*last_value > 360);
311  bool s_n = (2*n > 360);
312  if (!s_o && s_n) {
313  if (param->on_off_value()) {
314  ret = param->midi_set_bpm(0, 360, _lower, _upper);
315  } else {
316  ret = param->midi_set_bpm(360, 360, _lower, _upper);
317  }
318  }
319  } else {
320  ret = param->midi_set_bpm(n, 360, _lower, _upper);
321  }
322  return ret;
323 }
324 
325 /****************************************************************
326  ** class ControllerArray
327  */
328 
330  for (unsigned int n = 0; n < array_size; n++) {
331  operator[](n).clear();
332  }
334  while (jp.peek() != gx_system::JsonParser::end_array) {
336  midi_controller_list& l = operator[](jp.current_value_int());
338  while (jp.peek() != gx_system::JsonParser::end_array) {
340  if (p) {
341  l.push_back(*p);
342  delete p;
343  }
344  }
346  }
348 }
349 
351  w.begin_array(true);
352  for (unsigned int n = 0; n < array_size; n++) {
353  const midi_controller_list& cl = operator[](n);
354  if (cl.empty())
355  continue;
356  w.write(n);
357  w.begin_array();
358  for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i)
359  i->writeJSON(w);
360  w.end_array(true);
361  }
362  w.newline();
363  w.end_array(true);
364 }
365 
367  for (ControllerArray::size_type n = 0; n < size(); ++n) {
368  const midi_controller_list& cl = operator[](n);
369  for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i) {
370  if (i->hasParameter(param)) {
371  if (p) {
372  *p = &(*i);
373  }
374  return n;
375  }
376  }
377  }
378  return -1;
379 }
380 
382  for (iterator pctr = begin(); pctr != end(); ++pctr) {
383  for (midi_controller_list::iterator i = pctr->begin(); i != pctr->end(); ++i) {
384  if (i->hasParameter(p)) {
385  pctr->erase(i);
386  return true;
387  }
388  }
389  }
390  return false;
391 }
392 
393 
394 /****************************************************************
395  ** class MidiClockToBpm
396  */
397 
398 
400  : time1(0),
401  time_diff(0),
402  collect(0),
403  collect_(0),
404  bpm(0),
405  bpm_new(0),
406  ret(false) {}
407 
408 unsigned int MidiClockToBpm::rounded(float f) {
409  if (f >= 0x1.0p23) return (unsigned int) f;
410  return (unsigned int) (f + 0.49999997f);
411 }
412 
413 bool MidiClockToBpm::time_to_bpm(double time, unsigned int* bpm_) {
414  ret = false;
415  // if time drift to far, reset bpm detection.
416  if ((time-time1)> (1.05*time_diff) || (time-time1)*1.05 < (time_diff)) {
417  bpm = 0;
418  collect = 0;
419  collect_ = 0;
420  } else {
421  bpm_new = ((1000000000. / (time-time1) / 24) * 60);
422  bpm += bpm_new;
423  collect++;
424 
425  if (collect >= (bpm_new*bpm_new*0.0002)+1) {
426  bpm = (bpm/collect);
427  if (collect_>=2) {
428  (*bpm_) = rounded(min(360.,max(24.,bpm)));
429  collect_ = 0;
430  ret = true;
431  }
432  collect_++;
433  collect = 1;
434  }
435  }
436  time_diff = time-time1;
437  time1 = time;
438  return ret;
439 }
440 
441 /****************************************************************
442  ** class MidiControllerList
443  */
444 
446  : map(),
447  last_midi_control_value(),
448  last_midi_control(-2),
449  program_change(-1),
450  mute_change(-1),
451  bank_change(-1),
452  time0(0),
453  bpm_(9),
454  mp(),
455  pgm_chg(),
456  mute_chg(),
457  bank_chg(),
458  changed(),
459  new_program(),
460  new_mute_state(),
461  new_bank(),
462  midi_value_changed() {
463  for (int i = 0; i < ControllerArray::array_size; ++i) {
464  last_midi_control_value[i] = -1;
465  }
466  pgm_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_pgm_chg));
467  mute_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_mute_chg));
468  bank_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_bank_chg));
469  Glib::signal_timeout().connect(
470  sigc::mem_fun(this, &MidiControllerList::check_midi_values), 60);
471 }
472 
473 bool MidiControllerList::check_midi_values() {
474  static int saved_values[ControllerArray::array_size];
475  for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
476  if (saved_values[n] != last_midi_control_value[n]) {
477  saved_values[n] = last_midi_control_value[n];
478  midi_value_changed(n, saved_values[n]);
479  if (!get_config_mode()) {
480  midi_controller_list& ctr_list = map[n];
481  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
482  i->trigger_changed();
483  }
484  }
485  }
486  }
487  return true;
488 }
489 
492  int v = get_last_midi_control_value(ctr);
493  if (v >= 0) {
494  midi_controller_list& cl = map[ctr];
495  for (midi_controller_list::iterator i = cl.begin(); i != cl.end(); ++i) {
496  i->set_midi(v, v);
497  }
498  }
499 }
500 
502  for (unsigned int n = 0; n < map.size(); n++) {
504  }
505 }
506 
507 void MidiControllerList::on_pgm_chg() {
508  int pgm;
509  do {
510  pgm = gx_system::atomic_get(program_change);
511  } while (!gx_system::atomic_compare_and_exchange(&program_change, pgm, -1));
512  if (pgm>=0) new_program(pgm);
513 }
514 
515 void MidiControllerList::on_mute_chg() {
516  int mute;
517  do {
518  mute = gx_system::atomic_get(mute_change);
519  } while (!gx_system::atomic_compare_and_exchange(&mute_change, mute, -1));
520  new_mute_state(mute);
521 }
522 
523 void MidiControllerList::on_bank_chg() {
524  int bk;
525  do {
526  bk = gx_system::atomic_get(bank_change);
527  } while (!gx_system::atomic_compare_and_exchange(&bank_change, bk, -1));
528  if (bk>=0) new_bank(bk);
529 }
530 
531 void MidiControllerList::set_config_mode(bool mode, int ctl) {
532  assert(mode != get_config_mode());
533  if (mode) {
534  last_midi_control = ctl;
535  } else {
536  last_midi_control = -2;
537  }
538 }
539 
541  bool mode = get_config_mode();
542  if (!mode) {
543  set_config_mode(true); // keep rt thread away from table
544  }
545  if (map.deleteParameter(p)) {
546  changed();
547  }
548  if (!mode) {
549  set_config_mode(false);
550  }
551 }
552 
554  float lower, float upper, bool toggle) {
555  if (!get_config_mode()) {
556  assert(false);
557  return; // keep rt thread away from table
558  }
559  // maximal one controller for a zone allowed
560  deleteParameter(param);
561  if (last_midi_control < 0)
562  return;
563  // add zone to controller
564  map[last_midi_control].push_front(MidiController(param, lower, upper, toggle));
565  update_from_controller(last_midi_control);
566  changed();
567 }
568 
570  for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
571  int v = last_midi_control_value[n];
572  if (v >= 0) {
573  midi_value_changed(n, v);
574  }
575  }
576 }
577 
578 void MidiControllerList::set_ctr_val(int ctr, int val) {
579  if (get_config_mode()) {
580  last_midi_control = ctr;
581  } else {
582  midi_controller_list& ctr_list = map[ctr];
583  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
584  i->set_midi(val, get_last_midi_control_value(ctr));
585  }
586  }
588 }
589 
590 void MidiControllerList::set_bpm_val(unsigned int val) {
591  if (get_config_mode()) {
592  last_midi_control = 22;
593  } else {
594  midi_controller_list& ctr_list = map[22];
595  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
596  i->set_bpm(val, get_last_midi_control_value(22));
597  }
598  }
600 }
601 
603  bool mode = get_config_mode();
604  if (!mode) {
605  set_config_mode(true); // keep rt thread away from table
606  }
607  map = m;
608  if (!mode) {
609  set_config_mode(false);
610  }
611  changed();
612 }
613 
615  const ControllerArray *new_m) {
616  std::set<Parameter*> pset;
617  for (unsigned int i = 0; i < map.size(); i++) {
618  midi_controller_list& ctr = map[i];
619  for (midi_controller_list::iterator j = ctr.begin(); j != ctr.end(); ++j) {
620  if (new_m) {
621  const midi_controller_list& ctr_new = (*new_m)[i];
622  for (midi_controller_list::const_iterator jn = ctr_new.begin();
623  jn != ctr_new.end(); ++jn) {
624  if (j->getParameter() == jn->getParameter()) {
625  pset.insert(&j->getParameter());
626  break;
627  }
628  }
629  } else {
630  pset.insert(&j->getParameter());
631  }
632  }
633  }
634  for (paramlist::iterator n = plist.begin(); n != plist.end(); ) {
635  paramlist::iterator n1 = n++;
636  if (pset.find(*n1) != pset.end()) {
637  plist.erase(n1);
638  }
639  }
640 }
641 
642 void MidiControllerList::process_trans(int transport_state) {
643  unsigned int val = 0;
644  switch (transport_state) {
645  case JackTransportStopped:
646  val = 0;
647  break;
648  case JackTransportRolling:
649  val = 127;
650  break;
651  case JackTransportStarting:
652  val = 127;
653  break;
654  default:
655  return;
656  }
657  if (get_config_mode()) {
658  last_midi_control = 24;
659  } else {
660  midi_controller_list& ctr_list = map[24];
661  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
662  i->set_trans(val, get_last_midi_control_value(24));
663  }
664  }
666 }
667 
668 // ----- jack process callback for the midi input
669 void MidiControllerList::compute_midi_in(void* midi_input_port_buf, void *arg) {
670  jack_midi_event_t in_event;
671  jack_nframes_t event_count = jack_midi_get_event_count(midi_input_port_buf);
672  unsigned int i;
673  for (i = 0; i < event_count; i++) {
674  jack_midi_event_get(&in_event, midi_input_port_buf, i);
675  if ((in_event.buffer[0] & 0xf0) == 0xc0) { // program change on any midi channel
676  gx_system::atomic_set(&program_change, in_event.buffer[1]);
677  pgm_chg();
678  } else if ((in_event.buffer[0] & 0xf0) == 0xb0) { // controller
679  if (in_event.buffer[1]== 120) { // engine mute by All Sound Off on any midi channel
680  gx_system::atomic_set(&mute_change, in_event.buffer[2]);
681  mute_chg();
682  } else if (in_event.buffer[1]== 32) { // bank change on any midi channel
683  gx_system::atomic_set(&bank_change, in_event.buffer[2]);
684  bank_chg();
685  } else {
686  set_ctr_val(in_event.buffer[1], in_event.buffer[2]);
687  }
688  } else if ((in_event.buffer[0] ) > 0xf0) { // midi clock
689  if ((in_event.buffer[0] ) == 0xf8) { // midi beat clock
690  clock_gettime(CLOCK_MONOTONIC, &ts1);
691  gx_jack::GxJack& jack = *static_cast<gx_jack::GxJack*>(arg);
692  static unsigned int sr = jack.get_jack_sr();
693  time0 = (ts1.tv_sec*1000000000.0)+(ts1.tv_nsec)+
694  (1000000000.0/(double)(sr/(double)in_event.time));
695  if (mp.time_to_bpm(time0, &bpm_)) {
696  set_bpm_val(bpm_);
697  }
698  } else if ((in_event.buffer[0] ) == 0xfa) { // midi clock start
699  set_ctr_val(23, 127);
700  } else if ((in_event.buffer[0] ) == 0xfb) { // midi clock continue
701  // set_ctr_val(23, 127);
702  } else if ((in_event.buffer[0] ) == 0xfc) { // midi clock stop
703  set_ctr_val(23, 0);
704  } else if ((in_event.buffer[0] ) == 0xf2) { // midi clock position
705  // not implemented
706  // set_ctr_val(24,(in_event.buffer[2]<<7) | in_event.buffer[1]);
707  }
708  }
709  }
710 }
711 
712 /****************************************************************
713  ** Parameter Groups
714  */
715 
717  insert("system", N_("System"));
718  insert("ui", N_("User Interface"));
719  insert("ui.amp", N_("User Interface")); // FIXME (ui.amp.tonestack)
720  insert("engine", N_("Audio Engine"));
721 }
722 
724 #ifndef NDEBUG
725  for (map<string, bool>::iterator i = used.begin(); i != used.end(); ++i) {
726  if (!i->second) {
727  gx_print_error("Debug Check", "Group not used: " + i->first);
728  }
729  }
730 #endif
731 }
732 
733 #ifndef NDEBUG
734 void ParameterGroups::group_exists(const string& id) {
735  if (groups.find(id) == groups.end()) {
736  gx_print_error("Debug Check", "Group does not exist: " + id);
737  } else {
738  used[id] = true;
739  }
740 }
741 
742 void ParameterGroups::group_is_new(const string& id) {
743  if (groups.find(id) != groups.end()) {
744  gx_print_error("Debug Check", "Group already exists: " + id);
745  }
746 }
747 
749  for (map<string, string>::iterator i = groups.begin(); i != groups.end(); ++i) {
750  printf("PG %s: %s\n", i->first.c_str(), i->second.c_str());
751  }
752 }
753 
754 #endif
755 
757  static ParameterGroups groups;
758  return groups;
759 }
760 
761 string param_group(const string& group_id, bool nowarn) {
762  static ParameterGroups& groups = get_group_table();
763  if (nowarn) {
764  return groups.get(group_id);
765  } else {
766  return groups[group_id];
767  }
768 }
769 
770 /****************************************************************
771  ** Parameter
772  */
773 
777  assert(jp.current_value() == key);
778  return jp;
779 }
780 
782  jw.begin_object();
783  jw.write_kv("id", _id);
784  jw.write_kv("name", _name);
785  jw.write_kv("group", _group);
786  jw.write_kv("desc", _desc);
787  jw.write_kv("v_type", v_type); //FIXME
788  jw.write_kv("c_type", c_type); //FIXME
789  jw.write_kv("d_flags", d_flags); //FIXME
790  if (!controllable) {
791  jw.write_key("non_controllable"); jw.write(false);
792  }
793  if (!save_in_preset) {
794  jw.write_key("non_preset"); jw.write(false);
795  }
796  jw.end_object();
797 }
798 
800  : boost::noncopyable(),
801  _id(),
802  _name(),
803  _group(),
804  _desc(),
805  v_type(tp_float),
806  c_type(Continuous),
807  d_flags(0),
808  save_in_preset(true),
809  controllable(true),
810  do_not_save(false),
811  blocked(false),
812  used(false) {
814  while (jp.peek() != gx_system::JsonParser::end_object) {
816  if (jp.read_kv("id", _id) ||
817  jp.read_kv("name", _name) ||
818  jp.read_kv("group", _group) ||
819  jp.read_kv("desc", _desc)) {
820  } else if (jp.current_value() == "v_type") {
822  v_type = static_cast<value_type>(jp.current_value_int());
823  } else if (jp.current_value() == "c_type") {
825  c_type = static_cast<ctrl_type>(jp.current_value_int());
826  } else if (jp.current_value() == "d_flags") {
828  d_flags = jp.current_value_int();
829  } else if (jp.current_value() == "non_controllable") {
831  controllable = false;
832  } else if (jp.current_value() == "non_preset") {
834  save_in_preset = false;
835  } else {
837  "Parameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
838  jp.skip_object();
839  }
840  }
842 }
843 
845 }
846 
847 bool Parameter::midi_set(float n, float high, float llimit, float ulimit) {
848  assert(false);
849  return false;
850 }
851 
852 bool Parameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
853  assert(false);
854  return false;
855 }
856 
857 void Parameter::trigger_changed() {
858  assert(false);
859 }
860 
861 static int get_upper(const value_pair *vn) {
862  for (int n = 0; ; n++) {
863  if (!vn[n].value_id) {
864  return n - 1;
865  }
866  }
867 }
868 
869 void Parameter::range_warning(float value, float lower, float upper) {
871  _("parameter load"),
872  Glib::ustring::compose(_("parameter %1: value %2 out of range [%3, %4]"),
873  _id, value, lower, upper));
874 }
875 
876 const char *Parameter::get_typename() const {
877  static const char *tpname[] = {
878  "float", "int", "bool", "bool", "filename", "string", "special"};
879  assert(0 <= v_type and v_type < sizeof(tpname)/sizeof(tpname[0]));
880  return tpname[v_type];
881 }
882 
883 bool Parameter::hasRange() const {
884  return false;
885 }
886 
888  return 1;
889 }
890 
892  return 0;
893 }
894 
896  return 0;
897 }
898 
900  return 0;
901 }
902 
903 #ifndef NDEBUG
904 void compare_parameter(const char *title, Parameter* p1, Parameter* p2, bool all) {
905  if (p1->_id != p2->_id) {
907  title, Glib::ustring::compose("Different ID's: %2 / %3",
908  p1->_id, p2->_id));
909  }
910  if (p1->_name != p2->_name) {
912  title, Glib::ustring::compose("[%1]: Different name: %2 / %3",
913  p1->_id, p1->_name, p2->_name));
914  }
915  if (p1->_group != p2->_group) {
917  title, Glib::ustring::compose("[%1]: Different group: %2 / %3",
918  p1->_id, p1->_group, p2->_group));
919  }
920  if (p1->_desc != p2->_desc) {
922  title, Glib::ustring::compose("[%1]: Different desc: %2 / %3",
923  p1->_id, p1->_desc, p2->_desc));
924  }
925  if (p1->save_in_preset != p2->save_in_preset) {
927  title, Glib::ustring::compose("[%1]: save_in_preset different: %2 / %3",
928  p1->_id, p1->save_in_preset, p2->save_in_preset));
929  }
930  if (p1->controllable != p2->controllable) {
932  title, Glib::ustring::compose("[%1]: controllable different: %2 / %3",
933  p1->_id, p1->controllable, p2->controllable));
934  }
935  if (p1->used != p2->used) {
937  title, Glib::ustring::compose("[%1]: used different: %2 / %3",
938  p1->_id, p1->used, p2->used));
939  }
940  if (p1->c_type != p2->c_type) {
942  title, Glib::ustring::compose("[%1]: c_type different: %2 / %3",
943  p1->_id, p1->c_type, p2->c_type));
944  }
945  if (p1->v_type != p2->v_type) {
947  title, Glib::ustring::compose("[%1]: v_type different: %2 / %3",
948  p1->_id, p1->v_type, p2->v_type));
949  return;
950  }
951  if (p1->isFloat()) {
952  FloatParameter& f1 = p1->getFloat();
953  FloatParameter& f2 = p2->getFloat();
954  if (f1.value != f2.value) {
956  title, Glib::ustring::compose("[%1]: value address different: %2 / %3",
957  p1->_id, f1.value, f2.value));
958  }
959  if (f1.lower != f2.lower) {
961 
962  title, Glib::ustring::compose("[%1]: float lower different: %2 / %3",
963  p1->_id, f1.lower, f2.lower));
964  }
965  if (f1.upper != f2.upper) {
967  title, Glib::ustring::compose("[%1]: float upper different: %2 / %3",
968  p1->_id, f1.upper, f2.upper));
969  }
970  if (f1.step != f2.step) {
972  title, Glib::ustring::compose("[%1]: float step different: %2 / %3",
973  p1->_id, f1.step, f2.step));
974  }
975  if (f1.std_value != f2.std_value) {
977  title, Glib::ustring::compose("[%1]: float std value different: %2 / %3",
978  p1->_id, f1.std_value, f2.std_value));
979  }
980  if (all) {
981  if (f1.value != f2.value) {
983  title, Glib::ustring::compose("[%1]: float value different: %2 / %3",
984  p1->_id, *f1.value, *f2.value));
985  }
986  if (f1.json_value != f2.json_value) {
988  title, Glib::ustring::compose("[%1]: float json value different: %2 / %3",
989  p1->_id, f1.json_value, f2.json_value));
990  }
991  }
992  return;
993  }
994  if (p1->isInt()) {
995  assert(false);
996  return;
997  }
998  if (p1->isBool()) {
999  assert(false);
1000  return;
1001  }
1002  if (p1->isFile()) {
1003  assert(false);
1004  return;
1005  }
1006  assert(false);
1007 }
1008 #endif
1009 
1010 /* FloatParameter */
1011 
1013  jw.begin_object();
1014  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1015  jw.write_kv("lower", lower);
1016  jw.write_kv("upper", upper);
1017  jw.write_kv("step", step);
1018  jw.write_kv("value", *value);
1019  jw.write_kv("std_value", std_value);
1020  jw.end_object();
1021 }
1022 
1024  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper(), step() {
1025  while (jp.peek() != gx_system::JsonParser::end_object) {
1027  if (jp.read_kv("lower", lower) ||
1028  jp.read_kv("upper", upper) ||
1029  jp.read_kv("step", step) ||
1030  jp.read_kv("value", *value) ||
1031  jp.read_kv("std_value", std_value)) {
1032  } else {
1034  "FloatParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1035  jp.skip_object();
1036  }
1037  }
1039 }
1040 
1042 }
1043 
1044 bool FloatParameter::set(float val) const {
1045  float v = min(max(val, lower), upper);
1046  if (v != *value) {
1047  *value = v;
1048  changed(v);
1049  return true;
1050  }
1051  return false;
1052 }
1053 
1055  return *value != 0;
1056 }
1057 
1058 float FloatParameter::idx_from_id(string v_id) {
1059  assert(false);
1060  return 0;
1061 }
1062 
1063 bool FloatParameter::midi_set(float n, float high, float llimit, float ulimit) {
1064  float v;
1065  switch (c_type) {
1066  case Continuous:
1067  assert(n >= 0 && n <= high);
1068  v = llimit + (n / high) * (ulimit - llimit);
1069  break;
1070  case Switch:
1071  v = (2*n > high ? 1.0 : 0.0);
1072  break;
1073  case Enum:
1074  v = lower + min(n, upper-lower);
1075  break;
1076  default:
1077  assert(false);
1078  return false;
1079  }
1080  if (v != *value) {
1081  *value = v;
1082  return true;
1083  }
1084  return false;
1085 }
1086 
1087 bool FloatParameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
1088  float v;
1089  switch (c_type) {
1090  case Continuous:
1091  assert(n >= 0 && n <= high);
1092  if (high <= ulimit) {
1093  v = max(llimit,min(ulimit,n));
1094  } else {
1095  v = llimit + (n / high) * (ulimit - llimit);
1096  }
1097  break;
1098  case Switch:
1099  v = (2*n > high ? 1.0 : 0.0);
1100  break;
1101  case Enum:
1102  v = lower + min(n, upper-lower);
1103  break;
1104  default:
1105  assert(false);
1106  return false;
1107  }
1108  if (v != *value) {
1109  *value = v;
1110  return true;
1111  }
1112  return false;
1113 }
1114 
1115 void FloatParameter::trigger_changed() {
1116  changed(*value);
1117 }
1118 
1120  json_value = std_value;
1121 }
1122 
1124  jw.write_kv(_id.c_str(), *value);
1125 }
1126 
1129  json_value = jp.current_value_float();
1130  if (json_value < lower-abs(5*FLT_EPSILON*lower) || json_value > upper+abs(5*FLT_EPSILON*upper)) {
1131  range_warning(json_value, lower, upper);
1132  json_value = std_value;
1133  }
1134 }
1135 
1137  return abs(json_value - *value) < 5*FLT_EPSILON;
1138 }
1139 
1141  set(json_value);
1142 }
1143 
1144 void FloatParameter::convert_from_range(float low, float up) {
1145  json_value = lower + (json_value - low) / (up - low) * (upper - lower);
1146 }
1147 
1149  return true;
1150 }
1151 
1153  return lower;
1154 }
1155 
1157  return upper;
1158 }
1159 
1161  return step;
1162 }
1163 
1164 
1165 /* FloatEnumParameter */
1166 
1167 static void serializeValueNames(gx_system::JsonWriter& jw, const value_pair *p) {
1168  jw.write_key("value_names");
1169  jw.begin_array();
1170  while (p->value_id) {
1171  jw.write(p->value_id);
1172  if (p->value_label) {
1173  jw.write(p->value_label);
1174  } else {
1175  jw.write(p->value_id);
1176  }
1177  p++;
1178  }
1179  jw.end_array();
1180 }
1181 
1183  jw.begin_object();
1184  jw.write_key("FloatParameter"); FloatParameter::serializeJSON(jw);
1185  serializeValueNames(jw, value_names);
1186  jw.end_object();
1187 }
1188 
1189 FloatEnumParameter::FloatEnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1190  float *v, int sv, int low, bool ctrl, bool no_init):
1191  FloatParameter(id, name, Enum, preset, v, sv, low, low+get_upper(vn), 1, ctrl, no_init),
1192  value_names(vn) {}
1193 
1195  return value_names;
1196 }
1197 
1199  jw.write_key(_id.c_str());
1200  jw.write(value_names[static_cast<int>(round(*value-lower))].value_id);
1201 }
1202 
1204  int up = static_cast<int>(round(upper));
1205  int low = static_cast<int>(round(lower));
1206  int n = 0;
1207  for (; n <= up-low; n++) {
1208  if (v_id == value_names[n].value_id) {
1209  return low + n;
1210  }
1211  }
1212  return -1;
1213 }
1214 
1218  // old version compatability
1219  json_value = jp.current_value_int();
1220  return;
1221  }
1223  float n = idx_from_id(jp.current_value());
1224  if (n < 0) {
1226  _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1227  % _id % jp.current_value()).str());
1228  n = lower;
1229  }
1230  json_value = n;
1231 }
1232 
1233 /* IntParameter */
1234 
1236  jw.begin_object();
1237  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1238  jw.write_kv("lower", lower);
1239  jw.write_kv("upper", upper);
1240  jw.write_kv("value", *value);
1241  jw.write_kv("std_value", std_value);
1242  jw.end_object();
1243 }
1244 
1246  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper() {
1247  while (jp.peek() != gx_system::JsonParser::end_object) {
1249  if (jp.read_kv("lower", lower) ||
1250  jp.read_kv("upper", upper) ||
1251  jp.read_kv("value", *value) ||
1252  jp.read_kv("std_value", std_value)) {
1253  } else {
1255  "IntParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1256  jp.skip_object();
1257  }
1258  }
1260 }
1261 
1263 }
1264 
1265 bool IntParameter::set(int val) const {
1266  int v = min(max(val, lower), upper);
1267  if (v != *value) {
1268  *value = v;
1269  changed(v);
1270  return true;
1271  }
1272  return false;
1273 }
1274 
1275 int IntParameter::idx_from_id(string v_id) {
1276  assert(false);
1277  return 0;
1278 }
1279 
1281  return *value != 0;
1282 }
1283 
1284 bool IntParameter::midi_set(float n, float high, float llimit, float ulimit) {
1285  int v;
1286  switch (c_type) {
1287  case Continuous:
1288  assert(false); // not implemented
1289  return false;
1290  case Switch:
1291  assert(false); // not implemented
1292  return false;
1293  case Enum:
1294  v = lower + min(static_cast<int>(n), upper-lower);
1295  break;
1296  default:
1297  assert(false);
1298  return false;
1299  }
1300  if (v != *value) {
1301  *value = v;
1302  return true;
1303  }
1304  return false;
1305 }
1306 
1307 void IntParameter::trigger_changed() {
1308  changed(*value);
1309 }
1310 
1312  json_value = std_value;
1313 }
1314 
1316  jw.write_kv(_id.c_str(), *value);
1317 }
1318 
1321  json_value = jp.current_value_int();
1322  if (json_value < lower || json_value > upper) {
1323  range_warning(json_value, lower, upper);
1324  }
1325 }
1326 
1328  return json_value == *value;
1329 }
1330 
1332  set(json_value);
1333 }
1334 
1336  return true;
1337 }
1338 
1340  return lower;
1341 }
1342 
1344  return upper;
1345 }
1346 
1347 /* EnumParameter */
1348 
1350  jw.begin_object();
1351  jw.write_key("IntParameter"); IntParameter::serializeJSON(jw);
1352  serializeValueNames(jw, value_names);
1353  jw.end_object();
1354 }
1355 
1356 EnumParameter::EnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1357  int *v, int sv, bool ctrl):
1358  IntParameter(id, name, Enum, preset, v, sv, 0, get_upper(vn), ctrl),
1359  value_names(vn) {}
1360 
1362  return value_names;
1363 }
1364 
1365 int EnumParameter::idx_from_id(string v_id) {
1366  int n = 0;
1367  for (; n <= upper; n++) {
1368  if (v_id == value_names[n].value_id) {
1369  return n;
1370  }
1371  }
1372  return -1;
1373 }
1374 
1376  jw.write_key(_id.c_str());
1377  jw.write(value_names[*value].value_id);
1378 }
1379 
1383  // old version compatability
1384  json_value = jp.current_value_int();
1385  return;
1386  }
1388  int n = idx_from_id(jp.current_value());
1389  if (n < 0) {
1391  _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1392  % _id % jp.current_value()).str());
1393  n = 0;
1394  }
1395  json_value = n;
1396 }
1397 
1398 /* derived enum parameters */
1399 
1400 typedef std::pair<std::string,std::string> id_label;
1401 
1402 void enum_parameter_load_values(gx_system::JsonParser& jp, std::vector<id_label>& value_array, const value_pair **value_names) {
1403  while (jp.peek() != gx_system::JsonParser::end_object) {
1405  if (jp.current_value() == "value_names") {
1407  while (jp.peek() != gx_system::JsonParser::end_array) {
1409  std::string value_id = jp.current_value();
1411  std::string value_label = jp.current_value();
1412  value_array.push_back(id_label(value_id, value_label));
1413  }
1415  } else {
1417  "EnumValueNames", Glib::ustring::compose("unknown key: %1", jp.current_value()));
1418  jp.skip_object();
1419  }
1420  }
1422  value_pair* p = new value_pair[value_array.size()+1];
1423  *value_names = p;
1424  for (std::vector<id_label>::iterator i = value_array.begin(); i != value_array.end(); ++i) {
1425  p->value_id = i->first.c_str();
1426  p->value_label = i->second.c_str();
1427  p++;
1428  }
1429  p->value_id = p->value_label = 0;
1430 }
1431 
1433 private:
1434  std::vector<id_label> value_array;
1435 public:
1438 };
1439 
1441  : FloatEnumParameter(jp), value_array() {
1442  enum_parameter_load_values(jp, value_array, &value_names);
1443 }
1444 
1446  delete value_names;
1447 }
1448 
1450 private:
1451  std::vector<id_label> value_array;
1452 public:
1454  ~EnumParameterD();
1455 };
1456 
1458  : EnumParameter(jp), value_array() {
1459  enum_parameter_load_values(jp, value_array, &value_names);
1460 }
1461 
1463  delete value_names;
1464 }
1465 
1466 
1467 /* BoolParameter */
1468 
1470  jw.begin_object();
1471  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1472  jw.write_kv("value", *value);
1473  jw.write_kv("std_value", std_value);
1474  jw.end_object();
1475 }
1476 
1478  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0) {
1479  while (jp.peek() != gx_system::JsonParser::end_object) {
1481  if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1482  } else {
1484  "BoolParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1485  jp.skip_object();
1486  }
1487  }
1489 }
1490 
1492 }
1493 
1494 bool BoolParameter::set(bool val) const {
1495  if (val != *value) {
1496  *value = val;
1497  changed(val);
1498  return true;
1499  }
1500  return false;
1501 }
1502 
1504  return *value;
1505 }
1506 
1507 bool BoolParameter::midi_set(float n, float high, float llimit, float ulimit) {
1508  bool v;
1509  switch (c_type) {
1510  case Switch:
1511  v = (2*n > high);
1512  break;
1513  default:
1514  assert(false);
1515  return false;
1516  }
1517  if (v != *value) {
1518  *value = v;
1519  return true;
1520  }
1521  return false;
1522 }
1523 
1524 void BoolParameter::trigger_changed() {
1525  changed(*value);
1526 }
1527 
1529  json_value = std_value;
1530 }
1531 
1533  jw.write_kv(_id.c_str(), *value);
1534 }
1535 
1538  if (jp.current_value_int() < 0 || jp.current_value_int() > 1) {
1539  range_warning(json_value, 0, 1);
1540  }
1541  json_value = jp.current_value_int();
1542 }
1543 
1545  return json_value == *value;
1546 }
1547 
1549  set(json_value);
1550 }
1551 
1552 
1553 /* FileParameter */
1554 
1556  jw.begin_object();
1557  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1558  jw.write_kv("value", value->get_path());
1559  jw.write_kv("std_value", std_value->get_path());
1560  jw.end_object();
1561 }
1562 
1564  : Parameter(jp_next(jp, "Parameter")), value(0), std_value(0), json_value(0) {
1565  while (jp.peek() != gx_system::JsonParser::end_object) {
1567  if (jp.current_value() == "value") {
1569  value = Gio::File::create_for_path(jp.current_value());
1570  } else if (jp.current_value() == "std_value") {
1572  std_value = Gio::File::create_for_path(jp.current_value());
1573  } else {
1575  "FileParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1576  jp.skip_object();
1577  }
1578  }
1580 }
1581 
1582 void FileParameter::set_path(const string& path) {
1583  Glib::RefPtr<Gio::File> v = Gio::File::create_for_path(path);
1584  if (is_equal(v)) {
1585  return;
1586  }
1587  value = v;
1588  changed();
1589 }
1590 
1591 bool FileParameter::set(const Glib::RefPtr<Gio::File>& val) {
1592  if (is_equal(val)) {
1593  return false;
1594  }
1595  value = val;
1596  changed();
1597  return true;
1598 }
1599 
1600 void FileParameter::set_standard(const string& filename) {
1601  std_value = Gio::File::create_for_path(filename);
1602  if (!value) {
1603  value = std_value->dup();
1604  changed();
1605  }
1606 }
1607 
1609  json_value = std_value->dup();
1610  changed();
1611 }
1612 
1614  return bool(value);
1615 }
1616 
1618  jw.write_kv(_id.c_str(), get_path());
1619 }
1620 
1623  json_value = Gio::File::create_for_path(jp.current_value());
1624 }
1625 
1627  return json_value->get_path() == value->get_path(); //FIXME
1628 }
1629 
1631  set(json_value);
1632 }
1633 
1634 static string get_file_id(const Glib::RefPtr<Gio::File>& f) {
1635  return f->query_info(G_FILE_ATTRIBUTE_ID_FILE)->get_attribute_string(G_FILE_ATTRIBUTE_ID_FILE);
1636 }
1637 
1638 bool FileParameter::is_equal(const Glib::RefPtr<Gio::File>& v) const {
1639  string id, id2;
1640  try {
1641  id = get_file_id(value);
1642  } catch(Gio::Error& ex) {
1643  return false; // FIXME check type of exception
1644  }
1645  try {
1646  id2 = get_file_id(v);
1647  } catch(Gio::Error& ex) {
1648  return false; // FIXME check type of exception
1649  }
1650  return id == id2;
1651 }
1652 
1653 string FileParameter::get_path() const {
1654  return value->get_path();
1655 }
1656 
1658  return value->get_parent()->get_path();
1659 }
1660 
1662  return value->get_parse_name();
1663 }
1664 
1666  return value->query_info(G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)->get_display_name();
1667 }
1668 
1669 void FileParameter::copy(const string& destination) const {
1670  value->copy(Gio::File::create_for_path(destination));
1671 }
1672 
1673 
1674 /* StringParameter */
1675 
1677  jw.begin_object();
1678  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1679  jw.write_kv("value", *value);
1680  jw.write_kv("std_value", std_value);
1681  jw.end_object();
1682 }
1683 
1685  : Parameter(jp_next(jp, "Parameter")), json_value(""), value(&value_storage), std_value("") {
1686  while (jp.peek() != gx_system::JsonParser::end_object) {
1688  if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1689  } else {
1691  "StringParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1692  jp.skip_object();
1693  }
1694  }
1696 }
1697 
1699 }
1700 
1701 bool StringParameter::set(const Glib::ustring& val) const {
1702  if (val != *value) {
1703  *value = val;
1704  changed(*value);
1705  return true;
1706  }
1707  return false;
1708 }
1709 
1711  return !value->empty();
1712 }
1713 
1715  json_value = std_value;
1716 }
1717 
1719  jw.write_kv(_id.c_str(), *value);
1720 }
1721 
1724  json_value = jp.current_value();
1725 }
1726 
1728  return json_value == *value;
1729 }
1730 
1732  set(json_value);
1733 }
1734 
1735 
1736 /****************************************************************
1737  ** Parameter Map
1738  */
1739 
1741  : id_map(),
1742  replace_mode(false) {
1743 }
1744 
1746  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1747  delete i->second;
1748  }
1749 }
1750 
1752  if (p->isFloat()) {
1753  if (p->getControlType() == Parameter::Enum) {
1754  jw.write("FloatEnum");
1755  } else {
1756  jw.write("Float");
1757  }
1758  } else if (p->isInt()) {
1759  if (p->getControlType() == Parameter::Enum) {
1760  jw.write("Enum");
1761  } else {
1762  jw.write("Int");
1763  }
1764  } else if (p->isBool()) {
1765  jw.write("Bool");
1766  } else if (p->isFile()) {
1767  jw.write("File");
1768  } else if (p->isString()) {
1769  jw.write("String");
1770  } else if (dynamic_cast<JConvParameter*>(p) != 0) {
1771  jw.write("JConv");
1772  } else {
1773 #ifndef NDEBUG
1774  cerr << "skipping " << p->id() << endl;
1775 #endif
1776  return;
1777  }
1778  p->serializeJSON(jw);
1779 }
1780 
1782  jw.begin_array();
1783  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1784  writeJSON_one(jw, i->second);
1785  }
1786  jw.end_array();
1787 }
1788 
1791  if (jp.current_value() == "FloatEnum") {
1792  return insert(new FloatEnumParameterD(jp));
1793  } else if (jp.current_value() == "Float") {
1794  return insert(new FloatParameter(jp));
1795  } else if (jp.current_value() == "Enum") {
1796  return insert(new EnumParameterD(jp));
1797  } else if (jp.current_value() == "Int") {
1798  return insert(new IntParameter(jp));
1799  } else if (jp.current_value() == "Bool") {
1800  return insert(new BoolParameter(jp));
1801  } else if (jp.current_value() == "File") {
1802  return insert(new FileParameter(jp));
1803  } else if (jp.current_value() == "String") {
1804  return insert(new StringParameter(jp));
1805  } else if (jp.current_value() == "JConv") {
1806  return insert(new JConvParameter(jp));
1807  } else {
1809  "ParamMap", Glib::ustring::compose("unknown parameter type: %1", jp.current_value()));
1810  jp.skip_object();
1811  return 0;
1812  }
1813 }
1814 
1817  while (jp.peek() != gx_system::JsonParser::end_array) {
1818  readJSON_one(jp);
1819  }
1821 }
1822 
1823 #ifndef NDEBUG
1824 void ParamMap::unique_id(Parameter* param) {
1825  if (id_map.find(param->id()) != id_map.end()) {
1826  gx_print_error("Debug Check", "id registered twice: " + param->id());
1827  }
1828 }
1829 
1830 void ParamMap::check_id(const string& id) {
1831  if (!hasId(id)) {
1832  cerr << "string-id not found: " << id << endl;
1833  }
1834 }
1835 
1836 void ParamMap::check_p(const char *p) {
1837  if (!hasId(p)) {
1838  cerr << "char-id not found: " << p << endl;
1839  }
1840 }
1841 
1842 void ParamMap::dump(const string& fmt) {
1843  gx_system::JsonWriter *p = 0;
1845  if (fmt == "json") {
1846  jw.set_stream(&cout);
1847  p = &jw;
1848  jw.begin_array();
1849  jw.newline();
1850  } else {
1851  printf("parameter map dump\n");
1852  }
1853  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1854  i->second->dump(p);
1855  }
1856  if (p) {
1857  jw.end_array();
1858  jw.close();
1859  } else {
1860  printf("---------------------\n");
1861  }
1862 }
1863 
1865  if (jw) {
1866  jw->begin_array();
1867  jw->write(id());
1868  switch (c_type) {
1869  case None: jw->write("None"); break;
1870  case Continuous: jw->write("Cont"); break;
1871  case Switch: jw->write("Swth"); break;
1872  case Enum: jw->write("Enum"); break;
1873  default: assert(false);
1874  }
1875  if (save_in_preset) {
1876  jw->write("preset");
1877  }
1878  if (controllable) {
1879  jw->write("control");
1880  }
1881  jw->write(l_group());
1882  jw->write(l_name());
1883  /*
1884  switch (v_type) {
1885  case tp_float: jw->write("f"); jw->write(getFloat().get_value()); break;
1886  case tp_int: jw->write("i"); jw->write(getInt().get_value()); break;
1887  case tp_bool: jw->write("b"); jw->write(getBool().get_value()); break;
1888  case tp_switch: jw->write("s"); jw->write(getSwitch().get()); break;
1889  case tp_file: jw->write("F"); jw->write(getFile().get_parse_name()); break;
1890  case tp_string: jw->write("S"); jw->write(getString().get_value()); break;
1891  case tp_special: jw->write("G"); break;
1892  default: assert(false);
1893  }
1894  */
1895  jw->write(getLowerAsFloat());
1896  jw->write(getUpperAsFloat());
1897  jw->write(getStepAsFloat());
1898  const value_pair *vn = getValueNames();
1899  if (vn) {
1900  jw->begin_array();
1901  for (int n = 0; ; ++n) {
1902  if (!vn[n].value_id) {
1903  break;
1904  }
1905  jw->begin_array();
1906  jw->write(vn[n].value_id);
1907  jw->write(vn[n].value_label ? vn[n].value_label : vn[n].value_id);
1908  jw->end_array();
1909  }
1910  jw->end_array();
1911  }
1912  jw->end_array();
1913  jw->newline();
1914  } else {
1915  printf("P: %s vt=%d ct=%d c=%d\n", _id.c_str(), v_type, c_type, controllable);
1916  }
1917 }
1918 #endif
1919 
1920 Parameter *ParamMap::insert(Parameter* param) {
1921  if (replace_mode) {
1922  map<string, Parameter*>::iterator ii = id_map.find(param->id());
1923  if (ii != id_map.end()) {
1924  Parameter *p = ii->second;
1925  insert_remove(p,false);
1926  id_map.erase(ii);
1927  delete p;
1928  }
1929  }
1930  debug_check(unique_id, param);
1931  id_map.insert(pair<string, Parameter*>(param->id(), param));
1932  insert_remove(param,true);
1933  return param;
1934 }
1935 
1937  if (!p) {
1938  return;
1939  }
1940  insert_remove(p, false);
1941  id_map.erase(p->id());
1942  delete p;
1943 }
1944 
1945 void ParamMap::unregister(const string& id) {
1946  if (!hasId(id)) {
1947  return;
1948  }
1949  unregister(&(*this)[id]);
1950 }
1951 
1953  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1954  i->second->stdJSON_value();
1955  i->second->setJSON_value();
1956  }
1957 }
1958 
1959 static inline bool compare_groups(const std::string& id, const char **groups) {
1960  if (!groups) {
1961  return false;
1962  }
1963  for (const char **g = groups; *g; g += 2) {
1964  const char *p = *g;
1965  if ((*p) != '.') {
1966  continue;
1967  }
1968  p++;
1969  int n = strlen(p);
1970  if (strncmp(id.c_str(), p, n) == 0 && id[n] == '.') {
1971  return true;
1972  }
1973  }
1974  return false;
1975 }
1976 
1977 bool ParamMap::unit_has_std_values(const PluginDef *pdef) const {
1978  std::string group_id(pdef->id);
1979  group_id += ".";
1980  std::string on_off = group_id + "on_off";
1981  std::string pp = group_id + "pp";
1982  std::string position = group_id + "position";
1983  for (iterator i = begin(); i != end(); ++i) {
1984  if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
1985  if (i->second->isInPreset()) {
1986  if (i->first != on_off && i->first != pp && i->first != position) {
1987  i->second->stdJSON_value();
1988  if (!i->second->compareJSON_value()) {
1989  return false;
1990  break;
1991  }
1992  }
1993  }
1994  }
1995  }
1996  return true;
1997 }
1998 
1999 // reset all parameters to default settings
2000 void ParamMap::reset_unit(const PluginDef *pdef) const {
2001  std::string group_id(pdef->id);
2002  group_id += ".";
2003  std::string on_off = group_id + "on_off";
2004  std::string pp = group_id + "pp";
2005  std::string position = group_id + "position";
2006  for (iterator i = begin(); i != end(); ++i) {
2007  if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
2008  if (i->second->isInPreset()) {
2009  if (i->first != on_off && i->first != pp && i->first != position) {
2010  i->second->stdJSON_value();
2011  i->second->setJSON_value();
2012  }
2013  }
2014  }
2015  }
2016 }
2017 
2018 } // namespace gx_gui
ParameterV< float > FloatParameter
Definition: gx_parameter.h:92
CmdConnection::msg_type end
Definition: jsonrpc.cpp:256
int get_last_midi_control_value(unsigned int n)
Definition: gx_parameter.h:770
void write_kv(const char *key, float v)
Definition: gx_json.h:81
FloatEnumParameter(gx_system::JsonParser &jp)
Definition: gx_parameter.h:277
virtual void readJSON_value(gx_system::JsonParser &jp)
bool set_bpm(int n, int last_value)
void copy(const string &destination) const
void begin_array(bool nl=false)
Definition: gx_json.cpp:184
int param2controller(Parameter &param, const MidiController **p)
ParameterV(const string &id, const string &name, ctrl_type ctp, bool preset, int *v, int sv, int lv, int uv, bool ctrl)
Definition: gx_parameter.h:315
virtual int idx_from_id(string v_id)
void set_stream(ostream *o)
Definition: gx_json.h:70
virtual void writeJSON(gx_system::JsonWriter &jw) const
enum ctrl_type c_type
Definition: gx_parameter.h:119
jack_nframes_t get_jack_sr()
Definition: gx_jack.h:177
MidiStandardControllers midi_std_ctr
map< string, Parameter * >::const_iterator iterator
Definition: gx_parameter.h:531
virtual void writeJSON(gx_system::JsonWriter &jw) const
Parameter(const string &id, const string &name, value_type vtp, ctrl_type ctp, bool preset, bool ctrl)
Definition: gx_parameter.h:132
virtual void serializeJSON(gx_system::JsonWriter &jw)
virtual void readJSON_value(gx_system::JsonParser &jp)
Parameter * readJSON_one(gx_system::JsonParser &jp)
friend void compare_parameter(const char *title, Parameter *p1, Parameter *p2, bool all)
list< Parameter * > paramlist
Definition: gx_parameter.h:219
ParameterV< GxJConvSettings > JConvParameter
virtual void serializeJSON(gx_system::JsonWriter &jw)
void unregister(Parameter *p)
bool deleteParameter(Parameter &p)
void end_array(bool nl=false)
Definition: gx_json.cpp:192
virtual void writeJSON(gx_system::JsonWriter &jw) const
void set_config_mode(bool mode, int ctl=-1)
void dump(const string &fmt)
virtual void readJSON_value(gx_system::JsonParser &jp)
virtual bool hasRange() const
void readJSON(gx_system::JsonParser &jp, ParamMap &param)
const char * value_id
Definition: gx_plugin.h:118
virtual bool compareJSON_value()
#define N_(String)
void range_warning(float value, float lower, float upper)
bool unit_has_std_values(const PluginDef *pdef) const
virtual void readJSON_value(gx_system::JsonParser &jp)
unsigned int rounded(float f)
virtual float idx_from_id(string v_id)
void writeJSON(gx_system::JsonWriter &jw)
string param_group(const string &group_id, bool nowarn=false)
string get(const string &id)
Definition: gx_parameter.h:62
bool is_equal(const Glib::RefPtr< Gio::File > &v) const
virtual const value_pair * getValueNames() const
bool hasId(const string &id) const
Definition: gx_parameter.h:534
bool isFile() const
Definition: gx_parameter.h:164
virtual void writeJSON(gx_system::JsonWriter &jw) const
void write_key(const char *p, bool nl=false)
Definition: gx_json.cpp:200
bool isFloat() const
Definition: gx_parameter.h:161
const string & id() const
Definition: gx_parameter.h:171
void writeJSON(gx_system::JsonWriter &jw) const
const char ** groups
Definition: gx_plugin.h:187
int atomic_get(volatile int &p)
Definition: gx_system.h:98
Glib::RefPtr< Gio::File > std_value
Definition: gx_parameter.h:385
FloatEnumParameterD(gx_system::JsonParser &jp)
EnumParameter(gx_system::JsonParser &jp)
Definition: gx_parameter.h:332
ParameterV< int > IntParameter
Definition: gx_parameter.h:95
void compute_midi_in(void *midi_input_port_buf, void *arg)
iterator begin() const
Definition: gx_parameter.h:532
sigc::signal< void > changed
Definition: gx_parameter.h:387
virtual void serializeJSON(gx_system::JsonWriter &jw)
void reset_unit(const PluginDef *pdef) const
ParameterV< bool > BoolParameter
Definition: gx_parameter.h:96
#define debug_check(func,...)
Definition: gx_parameter.h:36
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
bool read_kv(const char *key, float &v)
Definition: gx_json.cpp:511
virtual void readJSON_value(gx_system::JsonParser &jp)
void enum_parameter_load_values(gx_system::JsonParser &jp, std::vector< id_label > &value_array, const value_pair **value_names)
ParameterGroups & get_group_table()
bool time_to_bpm(double time, unsigned int *bpm_)
bool set(float val) const
virtual void writeJSON(gx_system::JsonWriter &jw) const
void check_expect(token expect)
Definition: gx_json.h:142
#define min(x, y)
const value_pair * value_names
Definition: gx_parameter.h:276
void set_ctr_val(int ctr, int val)
const char * id
Definition: gx_plugin.h:185
virtual void serializeJSON(gx_system::JsonWriter &jw)
std::pair< std::string, std::string > id_label
string get_parse_name() const
virtual void serializeJSON(gx_system::JsonWriter &jw)
bool set_trans(int n, int last_value)
ctrl_type getControlType() const
Definition: gx_parameter.h:166
#define max(x, y)
virtual void close()
Definition: gx_json.cpp:68
const char * value_label
Definition: gx_plugin.h:119
void begin_object(bool nl=false)
Definition: gx_json.cpp:168
const value_pair * value_names
Definition: gx_parameter.h:331
void writeJSON_one(gx_system::JsonWriter &jw, Parameter *p)
virtual const value_pair * getValueNames() const
virtual float getUpperAsFloat() const
virtual float getStepAsFloat() const
string get_display_name() const
virtual void writeJSON(gx_system::JsonWriter &jw) const
bool isBool() const
Definition: gx_parameter.h:163
const char * get_typename() const
virtual float getUpperAsFloat() const
enum value_type v_type
Definition: gx_parameter.h:118
virtual bool hasRange() const
void update_from_controller(int ctr)
update all controlled parameters with last received value from MIDI controller ctr.
virtual float getLowerAsFloat() const
void set_controller_array(const ControllerArray &m)
bool set(const Glib::ustring &val) const
virtual float getStepAsFloat() const
string get_directory_path() const
FloatParameter & getFloat()
Definition: gx_parameter.h:451
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
list< MidiController > midi_controller_list
Definition: gx_parameter.h:692
void writeJSON(gx_system::JsonWriter &jw) const
bool isInt() const
Definition: gx_parameter.h:162
virtual float getUpperAsFloat() const
void set_bpm_val(unsigned int val)
void atomic_set(volatile int *p, int v)
Definition: gx_system.h:90
virtual void serializeJSON(gx_system::JsonWriter &jw)
static MidiController * readJSON(gx_system::JsonParser &jp, ParamMap &param)
const string & name() const
Definition: gx_parameter.h:174
Glib::RefPtr< Gio::File > value
Definition: gx_parameter.h:384
virtual float idx_from_id(string v_id)
virtual void readJSON_value(gx_system::JsonParser &jp)
bool atomic_compare_and_exchange(volatile int *p, int oldv, int newv)
Definition: gx_system.h:114
bool isString() const
Definition: gx_parameter.h:165
void readJSON(gx_system::JsonParser &jp)
EnumParameterD(gx_system::JsonParser &jp)
bool set_midi(int n, int last_value)
void process_trans(int transport_state)
static gx_system::JsonParser & jp_next(gx_system::JsonParser &jp, const char *key)
virtual int idx_from_id(string v_id)
void replace(int ctr, const string &name)
void set_standard(const string &filename)
FileParameter(const string &id, const string &filename, bool preset=false)
Definition: gx_parameter.h:399
ParameterV(const string &id, const string &name, ctrl_type ctp, bool preset, float *v, float sv, float lv, float uv, float tv, bool ctrl, bool no_init)
Definition: gx_parameter.h:256
string current_value() const
Definition: gx_json.h:143
void writeJSON(gx_system::JsonWriter &jw) const
ParameterV(const string &id, const string &name, Glib::ustring *v, const Glib::ustring &sv, bool preset=false)
Definition: gx_parameter.h:438
void set_path(const string &path)
float current_value_float()
Definition: gx_json.h:146
static const char * value_label(const value_pair &vp)
Definition: gx_parameter.h:197
ParameterV(const string &id, const string &name, ctrl_type ctp, bool preset, bool *v, bool sv, bool ctrl)
Definition: gx_parameter.h:366
void deleteParameter(Parameter &param)
virtual void serializeJSON(gx_system::JsonWriter &jw)
virtual const value_pair * getValueNames() const
token next(token expect=no_token)
Definition: gx_json.cpp:496
unsigned int d_flags
Definition: gx_parameter.h:120
ParameterV< Glib::ustring > StringParameter
Definition: gx_parameter.h:97
void write(float v, bool nl=false)
Definition: gx_json.cpp:116
virtual float getLowerAsFloat() const
Glib::RefPtr< Gio::File > json_value
Definition: gx_parameter.h:386
void modifyCurrent(Parameter &param, float lower, float upper, bool toggle)
virtual bool hasRange() const
void set_last_midi_control_value(unsigned int n, int v)
Definition: gx_parameter.h:772
bool set(const Glib::RefPtr< Gio::File > &val)
virtual void serializeJSON(gx_system::JsonWriter &jw)
iterator end() const
Definition: gx_parameter.h:533
void readJSON(gx_system::JsonParser &jp)
void convert_from_range(float low, float up)
void remove_controlled_parameters(paramlist &plist, const ControllerArray *m)
void end_object(bool nl=false)
Definition: gx_json.cpp:176
virtual void readJSON_value(gx_system::JsonParser &jp)
void dump(gx_system::JsonWriter *jw)
virtual float getLowerAsFloat() const
virtual void writeJSON(gx_system::JsonWriter &jw) const