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 (toggle) {
274  bool s_o = (2*last_value > 127);
275  bool s_n = (2*n > 127);
276  if (!s_o && s_n) {
277  if (param->on_off_value()) {
278  ret = param->midi_set(0, 127, _lower, _upper);
279  } else {
280  ret = param->midi_set(127, 127, _lower, _upper);
281  }
282  }
283  } else {
284  //fprintf(stderr,"%s \n",param->id().c_str());
285  //fprintf(stderr,"%f \n",(127.*log10f(double(n+1.)))/2.1072);
286  // fprintf(stderr,"%f \n",double(n * double(double(n+1.)/128)));
287 
288  ret = param->midi_set(n, 127, _lower, _upper);
289  }
290  return ret;
291 }
292 
293 bool MidiController::set_trans(int n, int last_value) {
294  bool ret = false;
295  if (strcmp(param->id().c_str(), "engine.mute")==0) {
296  if ( n == 0) n = 127;
297  else n = 0;
298  }
299  ret = param->midi_set(n, 127, _lower, _upper);
300  return ret;
301 }
302 
303 bool MidiController::set_bpm(int n, int last_value) {
304  bool ret = false;
305  if (toggle) {
306  bool s_o = (2*last_value > 360);
307  bool s_n = (2*n > 360);
308  if (!s_o && s_n) {
309  if (param->on_off_value()) {
310  ret = param->midi_set_bpm(0, 360, _lower, _upper);
311  } else {
312  ret = param->midi_set_bpm(360, 360, _lower, _upper);
313  }
314  }
315  } else {
316  ret = param->midi_set_bpm(n, 360, _lower, _upper);
317  }
318  return ret;
319 }
320 
321 /****************************************************************
322  ** class ControllerArray
323  */
324 
326  for (unsigned int n = 0; n < array_size; n++) {
327  operator[](n).clear();
328  }
330  while (jp.peek() != gx_system::JsonParser::end_array) {
332  midi_controller_list& l = operator[](jp.current_value_int());
334  while (jp.peek() != gx_system::JsonParser::end_array) {
336  if (p) {
337  l.push_back(*p);
338  delete p;
339  }
340  }
342  }
344 }
345 
347  w.begin_array(true);
348  for (unsigned int n = 0; n < array_size; n++) {
349  const midi_controller_list& cl = operator[](n);
350  if (cl.empty())
351  continue;
352  w.write(n);
353  w.begin_array();
354  for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i)
355  i->writeJSON(w);
356  w.end_array(true);
357  }
358  w.newline();
359  w.end_array(true);
360 }
361 
363  for (ControllerArray::size_type n = 0; n < size(); ++n) {
364  const midi_controller_list& cl = operator[](n);
365  for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i) {
366  if (i->hasParameter(param)) {
367  if (p) {
368  *p = &(*i);
369  }
370  return n;
371  }
372  }
373  }
374  return -1;
375 }
376 
378  for (iterator pctr = begin(); pctr != end(); ++pctr) {
379  for (midi_controller_list::iterator i = pctr->begin(); i != pctr->end(); ++i) {
380  if (i->hasParameter(p)) {
381  pctr->erase(i);
382  return true;
383  }
384  }
385  }
386  return false;
387 }
388 
389 
390 /****************************************************************
391  ** class MidiClockToBpm
392  */
393 
394 
396  : time1(0),
397  time_diff(0),
398  collect(0),
399  collect_(0),
400  bpm(0),
401  bpm_new(0),
402  ret(false) {}
403 
404 unsigned int MidiClockToBpm::rounded(float f) {
405  if (f >= 0x1.0p23) return (unsigned int) f;
406  return (unsigned int) (f + 0.49999997f);
407 }
408 
409 bool MidiClockToBpm::time_to_bpm(double time, unsigned int* bpm_) {
410  ret = false;
411  // if time drift to far, reset bpm detection.
412  if ((time-time1)> (1.05*time_diff) || (time-time1)*1.05 < (time_diff)) {
413  bpm = 0;
414  collect = 0;
415  collect_ = 0;
416  } else {
417  bpm_new = ((1000000000. / (time-time1) / 24) * 60);
418  bpm += bpm_new;
419  collect++;
420 
421  if (collect >= (bpm_new*bpm_new*0.0002)+1) {
422  bpm = (bpm/collect);
423  if (collect_>=2) {
424  (*bpm_) = rounded(min(360.,max(24.,bpm)));
425  collect_ = 0;
426  ret = true;
427  }
428  collect_++;
429  collect = 1;
430  }
431  }
432  time_diff = time-time1;
433  time1 = time;
434  return ret;
435 }
436 
437 /****************************************************************
438  ** class MidiControllerList
439  */
440 
442  : map(),
443  last_midi_control_value(),
444  last_midi_control(-2),
445  program_change(-1),
446  mute_change(-1),
447  bank_change(-1),
448  time0(0),
449  bpm_(9),
450  mp(),
451  pgm_chg(),
452  mute_chg(),
453  bank_chg(),
454  changed(),
455  new_program(),
456  new_mute_state(),
457  new_bank(),
458  midi_value_changed() {
459  for (int i = 0; i < ControllerArray::array_size; ++i) {
460  last_midi_control_value[i] = -1;
461  }
462  pgm_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_pgm_chg));
463  mute_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_mute_chg));
464  bank_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_bank_chg));
465  Glib::signal_timeout().connect(
466  sigc::mem_fun(this, &MidiControllerList::check_midi_values), 60);
467 }
468 
469 bool MidiControllerList::check_midi_values() {
470  static int saved_values[ControllerArray::array_size];
471  for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
472  if (saved_values[n] != last_midi_control_value[n]) {
473  saved_values[n] = last_midi_control_value[n];
474  midi_value_changed(n, saved_values[n]);
475  if (!get_config_mode()) {
476  midi_controller_list& ctr_list = map[n];
477  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
478  i->trigger_changed();
479  }
480  }
481  }
482  }
483  return true;
484 }
485 
488  int v = get_last_midi_control_value(ctr);
489  if (v >= 0) {
490  midi_controller_list& cl = map[ctr];
491  for (midi_controller_list::iterator i = cl.begin(); i != cl.end(); ++i) {
492  i->set_midi(v, v);
493  }
494  }
495 }
496 
498  for (unsigned int n = 0; n < map.size(); n++) {
500  }
501 }
502 
503 void MidiControllerList::on_pgm_chg() {
504  int pgm;
505  do {
506  pgm = gx_system::atomic_get(program_change);
507  } while (!gx_system::atomic_compare_and_exchange(&program_change, pgm, -1));
508  if (pgm>=0) new_program(pgm);
509 }
510 
511 void MidiControllerList::on_mute_chg() {
512  int mute;
513  do {
514  mute = gx_system::atomic_get(mute_change);
515  } while (!gx_system::atomic_compare_and_exchange(&mute_change, mute, -1));
516  new_mute_state(mute);
517 }
518 
519 void MidiControllerList::on_bank_chg() {
520  int bk;
521  do {
522  bk = gx_system::atomic_get(bank_change);
523  } while (!gx_system::atomic_compare_and_exchange(&bank_change, bk, -1));
524  if (bk>=0) new_bank(bk);
525 }
526 
527 void MidiControllerList::set_config_mode(bool mode, int ctl) {
528  assert(mode != get_config_mode());
529  if (mode) {
530  last_midi_control = ctl;
531  } else {
532  last_midi_control = -2;
533  }
534 }
535 
537  bool mode = get_config_mode();
538  if (!mode) {
539  set_config_mode(true); // keep rt thread away from table
540  }
541  if (map.deleteParameter(p)) {
542  changed();
543  }
544  if (!mode) {
545  set_config_mode(false);
546  }
547 }
548 
550  float lower, float upper, bool toggle) {
551  if (!get_config_mode()) {
552  assert(false);
553  return; // keep rt thread away from table
554  }
555  // maximal one controller for a zone allowed
556  deleteParameter(param);
557  if (last_midi_control < 0)
558  return;
559  // add zone to controller
560  map[last_midi_control].push_front(MidiController(param, lower, upper, toggle));
561  update_from_controller(last_midi_control);
562  changed();
563 }
564 
566  for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
567  int v = last_midi_control_value[n];
568  if (v >= 0) {
569  midi_value_changed(n, v);
570  }
571  }
572 }
573 
574 void MidiControllerList::set_ctr_val(int ctr, int val) {
575  if (get_config_mode()) {
576  last_midi_control = ctr;
577  } else {
578  midi_controller_list& ctr_list = map[ctr];
579  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
580  i->set_midi(val, get_last_midi_control_value(ctr));
581  }
582  }
584 }
585 
586 void MidiControllerList::set_bpm_val(unsigned int val) {
587  if (get_config_mode()) {
588  last_midi_control = 22;
589  } else {
590  midi_controller_list& ctr_list = map[22];
591  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
592  i->set_bpm(val, get_last_midi_control_value(22));
593  }
594  }
596 }
597 
599  bool mode = get_config_mode();
600  if (!mode) {
601  set_config_mode(true); // keep rt thread away from table
602  }
603  map = m;
604  if (!mode) {
605  set_config_mode(false);
606  }
607  changed();
608 }
609 
611  const ControllerArray *new_m) {
612  std::set<Parameter*> pset;
613  for (unsigned int i = 0; i < map.size(); i++) {
614  midi_controller_list& ctr = map[i];
615  for (midi_controller_list::iterator j = ctr.begin(); j != ctr.end(); ++j) {
616  if (new_m) {
617  const midi_controller_list& ctr_new = (*new_m)[i];
618  for (midi_controller_list::const_iterator jn = ctr_new.begin();
619  jn != ctr_new.end(); ++jn) {
620  if (j->getParameter() == jn->getParameter()) {
621  pset.insert(&j->getParameter());
622  break;
623  }
624  }
625  } else {
626  pset.insert(&j->getParameter());
627  }
628  }
629  }
630  for (paramlist::iterator n = plist.begin(); n != plist.end(); ) {
631  paramlist::iterator n1 = n++;
632  if (pset.find(*n1) != pset.end()) {
633  plist.erase(n1);
634  }
635  }
636 }
637 
638 void MidiControllerList::process_trans(int transport_state) {
639  unsigned int val = 0;
640  switch (transport_state) {
641  case JackTransportStopped:
642  val = 0;
643  break;
644  case JackTransportRolling:
645  val = 127;
646  break;
647  case JackTransportStarting:
648  val = 127;
649  break;
650  default:
651  return;
652  }
653  if (get_config_mode()) {
654  last_midi_control = 24;
655  } else {
656  midi_controller_list& ctr_list = map[24];
657  for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
658  i->set_trans(val, get_last_midi_control_value(24));
659  }
660  }
662 }
663 
664 // ----- jack process callback for the midi input
665 void MidiControllerList::compute_midi_in(void* midi_input_port_buf, void *arg) {
666  jack_midi_event_t in_event;
667  jack_nframes_t event_count = jack_midi_get_event_count(midi_input_port_buf);
668  unsigned int i;
669  for (i = 0; i < event_count; i++) {
670  jack_midi_event_get(&in_event, midi_input_port_buf, i);
671  if ((in_event.buffer[0] & 0xf0) == 0xc0) { // program change on any midi channel
672  gx_system::atomic_set(&program_change, in_event.buffer[1]);
673  pgm_chg();
674  } else if ((in_event.buffer[0] & 0xf0) == 0xb0) { // controller
675  if (in_event.buffer[1]== 120) { // engine mute by All Sound Off on any midi channel
676  gx_system::atomic_set(&mute_change, in_event.buffer[2]);
677  mute_chg();
678  } else if (in_event.buffer[1]== 32) { // bank change on any midi channel
679  gx_system::atomic_set(&bank_change, in_event.buffer[2]);
680  bank_chg();
681  } else {
682  set_ctr_val(in_event.buffer[1], in_event.buffer[2]);
683  }
684  } else if ((in_event.buffer[0] ) > 0xf0) { // midi clock
685  if ((in_event.buffer[0] ) == 0xf8) { // midi beat clock
686  clock_gettime(CLOCK_MONOTONIC, &ts1);
687  gx_jack::GxJack& jack = *static_cast<gx_jack::GxJack*>(arg);
688  static unsigned int sr = jack.get_jack_sr();
689  time0 = (ts1.tv_sec*1000000000.0)+(ts1.tv_nsec)+
690  (1000000000.0/(double)(sr/(double)in_event.time));
691  if (mp.time_to_bpm(time0, &bpm_)) {
692  set_bpm_val(bpm_);
693  }
694  } else if ((in_event.buffer[0] ) == 0xfa) { // midi clock start
695  set_ctr_val(23, 127);
696  } else if ((in_event.buffer[0] ) == 0xfb) { // midi clock continue
697  // set_ctr_val(23, 127);
698  } else if ((in_event.buffer[0] ) == 0xfc) { // midi clock stop
699  set_ctr_val(23, 0);
700  } else if ((in_event.buffer[0] ) == 0xf2) { // midi clock position
701  // not implemented
702  // set_ctr_val(24,(in_event.buffer[2]<<7) | in_event.buffer[1]);
703  }
704  }
705  }
706 }
707 
708 /****************************************************************
709  ** Parameter Groups
710  */
711 
713  insert("system", N_("System"));
714  insert("ui", N_("User Interface"));
715  insert("ui.amp", N_("User Interface")); // FIXME (ui.amp.tonestack)
716  insert("engine", N_("Audio Engine"));
717 }
718 
720 #ifndef NDEBUG
721  for (map<string, bool>::iterator i = used.begin(); i != used.end(); ++i) {
722  if (!i->second) {
723  gx_print_error("Debug Check", "Group not used: " + i->first);
724  }
725  }
726 #endif
727 }
728 
729 #ifndef NDEBUG
730 void ParameterGroups::group_exists(const string& id) {
731  if (groups.find(id) == groups.end()) {
732  gx_print_error("Debug Check", "Group does not exist: " + id);
733  } else {
734  used[id] = true;
735  }
736 }
737 
738 void ParameterGroups::group_is_new(const string& id) {
739  if (groups.find(id) != groups.end()) {
740  gx_print_error("Debug Check", "Group already exists: " + id);
741  }
742 }
743 
745  for (map<string, string>::iterator i = groups.begin(); i != groups.end(); ++i) {
746  printf("PG %s: %s\n", i->first.c_str(), i->second.c_str());
747  }
748 }
749 
750 #endif
751 
753  static ParameterGroups groups;
754  return groups;
755 }
756 
757 string param_group(const string& group_id, bool nowarn) {
758  static ParameterGroups& groups = get_group_table();
759  if (nowarn) {
760  return groups.get(group_id);
761  } else {
762  return groups[group_id];
763  }
764 }
765 
766 /****************************************************************
767  ** Parameter
768  */
769 
773  assert(jp.current_value() == key);
774  return jp;
775 }
776 
778  jw.begin_object();
779  jw.write_kv("id", _id);
780  jw.write_kv("name", _name);
781  jw.write_kv("group", _group);
782  jw.write_kv("desc", _desc);
783  jw.write_kv("v_type", v_type); //FIXME
784  jw.write_kv("c_type", c_type); //FIXME
785  jw.write_kv("d_flags", d_flags); //FIXME
786  if (!controllable) {
787  jw.write_key("non_controllable"); jw.write(false);
788  }
789  if (!save_in_preset) {
790  jw.write_key("non_preset"); jw.write(false);
791  }
792  jw.end_object();
793 }
794 
796  : boost::noncopyable(),
797  _id(),
798  _name(),
799  _group(),
800  _desc(),
801  v_type(tp_float),
802  c_type(Continuous),
803  d_flags(0),
804  save_in_preset(true),
805  controllable(true),
806  do_not_save(false),
807  blocked(false),
808  used(false) {
810  while (jp.peek() != gx_system::JsonParser::end_object) {
812  if (jp.read_kv("id", _id) ||
813  jp.read_kv("name", _name) ||
814  jp.read_kv("group", _group) ||
815  jp.read_kv("desc", _desc)) {
816  } else if (jp.current_value() == "v_type") {
818  v_type = static_cast<value_type>(jp.current_value_int());
819  } else if (jp.current_value() == "c_type") {
821  c_type = static_cast<ctrl_type>(jp.current_value_int());
822  } else if (jp.current_value() == "d_flags") {
824  d_flags = jp.current_value_int();
825  } else if (jp.current_value() == "non_controllable") {
827  controllable = false;
828  } else if (jp.current_value() == "non_preset") {
830  save_in_preset = false;
831  } else {
833  "Parameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
834  jp.skip_object();
835  }
836  }
838 }
839 
841 }
842 
843 bool Parameter::midi_set(float n, float high, float llimit, float ulimit) {
844  assert(false);
845  return false;
846 }
847 
848 bool Parameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
849  assert(false);
850  return false;
851 }
852 
853 void Parameter::trigger_changed() {
854  assert(false);
855 }
856 
857 static int get_upper(const value_pair *vn) {
858  for (int n = 0; ; n++) {
859  if (!vn[n].value_id) {
860  return n - 1;
861  }
862  }
863 }
864 
865 void Parameter::range_warning(float value, float lower, float upper) {
867  _("parameter load"),
868  Glib::ustring::compose(_("parameter %1: value %2 out of range [%3, %4]"),
869  _id, value, lower, upper));
870 }
871 
872 const char *Parameter::get_typename() const {
873  static const char *tpname[] = {
874  "float", "int", "bool", "bool", "filename", "string", "special"};
875  assert(0 <= v_type and v_type < sizeof(tpname)/sizeof(tpname[0]));
876  return tpname[v_type];
877 }
878 
879 bool Parameter::hasRange() const {
880  return false;
881 }
882 
884  return 1;
885 }
886 
888  return 0;
889 }
890 
892  return 0;
893 }
894 
896  return 0;
897 }
898 
899 #ifndef NDEBUG
900 void compare_parameter(const char *title, Parameter* p1, Parameter* p2, bool all) {
901  if (p1->_id != p2->_id) {
903  title, Glib::ustring::compose("Different ID's: %2 / %3",
904  p1->_id, p2->_id));
905  }
906  if (p1->_name != p2->_name) {
908  title, Glib::ustring::compose("[%1]: Different name: %2 / %3",
909  p1->_id, p1->_name, p2->_name));
910  }
911  if (p1->_group != p2->_group) {
913  title, Glib::ustring::compose("[%1]: Different group: %2 / %3",
914  p1->_id, p1->_group, p2->_group));
915  }
916  if (p1->_desc != p2->_desc) {
918  title, Glib::ustring::compose("[%1]: Different desc: %2 / %3",
919  p1->_id, p1->_desc, p2->_desc));
920  }
921  if (p1->save_in_preset != p2->save_in_preset) {
923  title, Glib::ustring::compose("[%1]: save_in_preset different: %2 / %3",
924  p1->_id, p1->save_in_preset, p2->save_in_preset));
925  }
926  if (p1->controllable != p2->controllable) {
928  title, Glib::ustring::compose("[%1]: controllable different: %2 / %3",
929  p1->_id, p1->controllable, p2->controllable));
930  }
931  if (p1->used != p2->used) {
933  title, Glib::ustring::compose("[%1]: used different: %2 / %3",
934  p1->_id, p1->used, p2->used));
935  }
936  if (p1->c_type != p2->c_type) {
938  title, Glib::ustring::compose("[%1]: c_type different: %2 / %3",
939  p1->_id, p1->c_type, p2->c_type));
940  }
941  if (p1->v_type != p2->v_type) {
943  title, Glib::ustring::compose("[%1]: v_type different: %2 / %3",
944  p1->_id, p1->v_type, p2->v_type));
945  return;
946  }
947  if (p1->isFloat()) {
948  FloatParameter& f1 = p1->getFloat();
949  FloatParameter& f2 = p2->getFloat();
950  if (f1.value != f2.value) {
952  title, Glib::ustring::compose("[%1]: value address different: %2 / %3",
953  p1->_id, f1.value, f2.value));
954  }
955  if (f1.lower != f2.lower) {
957 
958  title, Glib::ustring::compose("[%1]: float lower different: %2 / %3",
959  p1->_id, f1.lower, f2.lower));
960  }
961  if (f1.upper != f2.upper) {
963  title, Glib::ustring::compose("[%1]: float upper different: %2 / %3",
964  p1->_id, f1.upper, f2.upper));
965  }
966  if (f1.step != f2.step) {
968  title, Glib::ustring::compose("[%1]: float step different: %2 / %3",
969  p1->_id, f1.step, f2.step));
970  }
971  if (f1.std_value != f2.std_value) {
973  title, Glib::ustring::compose("[%1]: float std value different: %2 / %3",
974  p1->_id, f1.std_value, f2.std_value));
975  }
976  if (all) {
977  if (f1.value != f2.value) {
979  title, Glib::ustring::compose("[%1]: float value different: %2 / %3",
980  p1->_id, *f1.value, *f2.value));
981  }
982  if (f1.json_value != f2.json_value) {
984  title, Glib::ustring::compose("[%1]: float json value different: %2 / %3",
985  p1->_id, f1.json_value, f2.json_value));
986  }
987  }
988  return;
989  }
990  if (p1->isInt()) {
991  assert(false);
992  return;
993  }
994  if (p1->isBool()) {
995  assert(false);
996  return;
997  }
998  if (p1->isFile()) {
999  assert(false);
1000  return;
1001  }
1002  assert(false);
1003 }
1004 #endif
1005 
1006 /* FloatParameter */
1007 
1009  jw.begin_object();
1010  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1011  jw.write_kv("lower", lower);
1012  jw.write_kv("upper", upper);
1013  jw.write_kv("step", step);
1014  jw.write_kv("value", *value);
1015  jw.write_kv("std_value", std_value);
1016  jw.end_object();
1017 }
1018 
1020  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper(), step() {
1021  while (jp.peek() != gx_system::JsonParser::end_object) {
1023  if (jp.read_kv("lower", lower) ||
1024  jp.read_kv("upper", upper) ||
1025  jp.read_kv("step", step) ||
1026  jp.read_kv("value", *value) ||
1027  jp.read_kv("std_value", std_value)) {
1028  } else {
1030  "FloatParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1031  jp.skip_object();
1032  }
1033  }
1035 }
1036 
1038 }
1039 
1040 bool FloatParameter::set(float val) const {
1041  float v = min(max(val, lower), upper);
1042  if (v != *value) {
1043  *value = v;
1044  changed(v);
1045  return true;
1046  }
1047  return false;
1048 }
1049 
1051  return *value != 0;
1052 }
1053 
1054 float FloatParameter::idx_from_id(string v_id) {
1055  assert(false);
1056  return 0;
1057 }
1058 
1059 bool FloatParameter::midi_set(float n, float high, float llimit, float ulimit) {
1060  float v;
1061  switch (c_type) {
1062  case Continuous:
1063  assert(n >= 0 && n <= high);
1064  v = llimit + (n / high) * (ulimit - llimit);
1065  break;
1066  case Switch:
1067  v = (2*n > high ? 1.0 : 0.0);
1068  break;
1069  case Enum:
1070  v = lower + min(n, upper-lower);
1071  break;
1072  default:
1073  assert(false);
1074  return false;
1075  }
1076  if (v != *value) {
1077  *value = v;
1078  return true;
1079  }
1080  return false;
1081 }
1082 
1083 bool FloatParameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
1084  float v;
1085  switch (c_type) {
1086  case Continuous:
1087  assert(n >= 0 && n <= high);
1088  if (high <= ulimit) {
1089  v = max(llimit,min(ulimit,n));
1090  } else {
1091  v = llimit + (n / high) * (ulimit - llimit);
1092  }
1093  break;
1094  case Switch:
1095  v = (2*n > high ? 1.0 : 0.0);
1096  break;
1097  case Enum:
1098  v = lower + min(n, upper-lower);
1099  break;
1100  default:
1101  assert(false);
1102  return false;
1103  }
1104  if (v != *value) {
1105  *value = v;
1106  return true;
1107  }
1108  return false;
1109 }
1110 
1111 void FloatParameter::trigger_changed() {
1112  changed(*value);
1113 }
1114 
1116  json_value = std_value;
1117 }
1118 
1120  jw.write_kv(_id.c_str(), *value);
1121 }
1122 
1125  json_value = jp.current_value_float();
1126  if (json_value < lower-abs(5*FLT_EPSILON*lower) || json_value > upper+abs(5*FLT_EPSILON*upper)) {
1127  range_warning(json_value, lower, upper);
1128  json_value = std_value;
1129  }
1130 }
1131 
1133  return abs(json_value - *value) < 5*FLT_EPSILON;
1134 }
1135 
1137  set(json_value);
1138 }
1139 
1140 void FloatParameter::convert_from_range(float low, float up) {
1141  json_value = lower + (json_value - low) / (up - low) * (upper - lower);
1142 }
1143 
1145  return true;
1146 }
1147 
1149  return lower;
1150 }
1151 
1153  return upper;
1154 }
1155 
1157  return step;
1158 }
1159 
1160 
1161 /* FloatEnumParameter */
1162 
1163 static void serializeValueNames(gx_system::JsonWriter& jw, const value_pair *p) {
1164  jw.write_key("value_names");
1165  jw.begin_array();
1166  while (p->value_id) {
1167  jw.write(p->value_id);
1168  if (p->value_label) {
1169  jw.write(p->value_label);
1170  } else {
1171  jw.write(p->value_id);
1172  }
1173  p++;
1174  }
1175  jw.end_array();
1176 }
1177 
1179  jw.begin_object();
1180  jw.write_key("FloatParameter"); FloatParameter::serializeJSON(jw);
1181  serializeValueNames(jw, value_names);
1182  jw.end_object();
1183 }
1184 
1185 FloatEnumParameter::FloatEnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1186  float *v, int sv, int low, bool ctrl, bool no_init):
1187  FloatParameter(id, name, Enum, preset, v, sv, low, low+get_upper(vn), 1, ctrl, no_init),
1188  value_names(vn) {}
1189 
1191  return value_names;
1192 }
1193 
1195  jw.write_key(_id.c_str());
1196  jw.write(value_names[static_cast<int>(round(*value-lower))].value_id);
1197 }
1198 
1200  int up = static_cast<int>(round(upper));
1201  int low = static_cast<int>(round(lower));
1202  int n = 0;
1203  for (; n <= up-low; n++) {
1204  if (v_id == value_names[n].value_id) {
1205  return low + n;
1206  }
1207  }
1208  return -1;
1209 }
1210 
1214  // old version compatability
1215  json_value = jp.current_value_int();
1216  return;
1217  }
1219  float n = idx_from_id(jp.current_value());
1220  if (n < 0) {
1222  _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1223  % _id % jp.current_value()).str());
1224  n = lower;
1225  }
1226  json_value = n;
1227 }
1228 
1229 /* IntParameter */
1230 
1232  jw.begin_object();
1233  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1234  jw.write_kv("lower", lower);
1235  jw.write_kv("upper", upper);
1236  jw.write_kv("value", *value);
1237  jw.write_kv("std_value", std_value);
1238  jw.end_object();
1239 }
1240 
1242  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper() {
1243  while (jp.peek() != gx_system::JsonParser::end_object) {
1245  if (jp.read_kv("lower", lower) ||
1246  jp.read_kv("upper", upper) ||
1247  jp.read_kv("value", *value) ||
1248  jp.read_kv("std_value", std_value)) {
1249  } else {
1251  "IntParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1252  jp.skip_object();
1253  }
1254  }
1256 }
1257 
1259 }
1260 
1261 bool IntParameter::set(int val) const {
1262  int v = min(max(val, lower), upper);
1263  if (v != *value) {
1264  *value = v;
1265  changed(v);
1266  return true;
1267  }
1268  return false;
1269 }
1270 
1271 int IntParameter::idx_from_id(string v_id) {
1272  assert(false);
1273  return 0;
1274 }
1275 
1277  return *value != 0;
1278 }
1279 
1280 bool IntParameter::midi_set(float n, float high, float llimit, float ulimit) {
1281  int v;
1282  switch (c_type) {
1283  case Continuous:
1284  assert(false); // not implemented
1285  return false;
1286  case Switch:
1287  assert(false); // not implemented
1288  return false;
1289  case Enum:
1290  v = lower + min(static_cast<int>(n), upper-lower);
1291  break;
1292  default:
1293  assert(false);
1294  return false;
1295  }
1296  if (v != *value) {
1297  *value = v;
1298  return true;
1299  }
1300  return false;
1301 }
1302 
1303 void IntParameter::trigger_changed() {
1304  changed(*value);
1305 }
1306 
1308  json_value = std_value;
1309 }
1310 
1312  jw.write_kv(_id.c_str(), *value);
1313 }
1314 
1317  json_value = jp.current_value_int();
1318  if (json_value < lower || json_value > upper) {
1319  range_warning(json_value, lower, upper);
1320  }
1321 }
1322 
1324  return json_value == *value;
1325 }
1326 
1328  set(json_value);
1329 }
1330 
1332  return true;
1333 }
1334 
1336  return lower;
1337 }
1338 
1340  return upper;
1341 }
1342 
1343 /* EnumParameter */
1344 
1346  jw.begin_object();
1347  jw.write_key("IntParameter"); IntParameter::serializeJSON(jw);
1348  serializeValueNames(jw, value_names);
1349  jw.end_object();
1350 }
1351 
1352 EnumParameter::EnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1353  int *v, int sv, bool ctrl):
1354  IntParameter(id, name, Enum, preset, v, sv, 0, get_upper(vn), ctrl),
1355  value_names(vn) {}
1356 
1358  return value_names;
1359 }
1360 
1361 int EnumParameter::idx_from_id(string v_id) {
1362  int n = 0;
1363  for (; n <= upper; n++) {
1364  if (v_id == value_names[n].value_id) {
1365  return n;
1366  }
1367  }
1368  return -1;
1369 }
1370 
1372  jw.write_key(_id.c_str());
1373  jw.write(value_names[*value].value_id);
1374 }
1375 
1379  // old version compatability
1380  json_value = jp.current_value_int();
1381  return;
1382  }
1384  int n = idx_from_id(jp.current_value());
1385  if (n < 0) {
1387  _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1388  % _id % jp.current_value()).str());
1389  n = 0;
1390  }
1391  json_value = n;
1392 }
1393 
1394 /* derived enum parameters */
1395 
1396 typedef std::pair<std::string,std::string> id_label;
1397 
1398 void enum_parameter_load_values(gx_system::JsonParser& jp, std::vector<id_label>& value_array, const value_pair **value_names) {
1399  while (jp.peek() != gx_system::JsonParser::end_object) {
1401  if (jp.current_value() == "value_names") {
1403  while (jp.peek() != gx_system::JsonParser::end_array) {
1405  std::string value_id = jp.current_value();
1407  std::string value_label = jp.current_value();
1408  value_array.push_back(id_label(value_id, value_label));
1409  }
1411  } else {
1413  "EnumValueNames", Glib::ustring::compose("unknown key: %1", jp.current_value()));
1414  jp.skip_object();
1415  }
1416  }
1418  value_pair* p = new value_pair[value_array.size()+1];
1419  *value_names = p;
1420  for (std::vector<id_label>::iterator i = value_array.begin(); i != value_array.end(); ++i) {
1421  p->value_id = i->first.c_str();
1422  p->value_label = i->second.c_str();
1423  p++;
1424  }
1425  p->value_id = p->value_label = 0;
1426 }
1427 
1429 private:
1430  std::vector<id_label> value_array;
1431 public:
1434 };
1435 
1437  : FloatEnumParameter(jp), value_array() {
1438  enum_parameter_load_values(jp, value_array, &value_names);
1439 }
1440 
1442  delete value_names;
1443 }
1444 
1446 private:
1447  std::vector<id_label> value_array;
1448 public:
1450  ~EnumParameterD();
1451 };
1452 
1454  : EnumParameter(jp), value_array() {
1455  enum_parameter_load_values(jp, value_array, &value_names);
1456 }
1457 
1459  delete value_names;
1460 }
1461 
1462 
1463 /* BoolParameter */
1464 
1466  jw.begin_object();
1467  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1468  jw.write_kv("value", *value);
1469  jw.write_kv("std_value", std_value);
1470  jw.end_object();
1471 }
1472 
1474  : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0) {
1475  while (jp.peek() != gx_system::JsonParser::end_object) {
1477  if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1478  } else {
1480  "BoolParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1481  jp.skip_object();
1482  }
1483  }
1485 }
1486 
1488 }
1489 
1490 bool BoolParameter::set(bool val) const {
1491  if (val != *value) {
1492  *value = val;
1493  changed(val);
1494  return true;
1495  }
1496  return false;
1497 }
1498 
1500  return *value;
1501 }
1502 
1503 bool BoolParameter::midi_set(float n, float high, float llimit, float ulimit) {
1504  bool v;
1505  switch (c_type) {
1506  case Switch:
1507  v = (2*n > high);
1508  break;
1509  default:
1510  assert(false);
1511  return false;
1512  }
1513  if (v != *value) {
1514  *value = v;
1515  return true;
1516  }
1517  return false;
1518 }
1519 
1520 void BoolParameter::trigger_changed() {
1521  changed(*value);
1522 }
1523 
1525  json_value = std_value;
1526 }
1527 
1529  jw.write_kv(_id.c_str(), *value);
1530 }
1531 
1534  if (jp.current_value_int() < 0 || jp.current_value_int() > 1) {
1535  range_warning(json_value, 0, 1);
1536  }
1537  json_value = jp.current_value_int();
1538 }
1539 
1541  return json_value == *value;
1542 }
1543 
1545  set(json_value);
1546 }
1547 
1548 
1549 /* FileParameter */
1550 
1552  jw.begin_object();
1553  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1554  jw.write_kv("value", value->get_path());
1555  jw.write_kv("std_value", std_value->get_path());
1556  jw.end_object();
1557 }
1558 
1560  : Parameter(jp_next(jp, "Parameter")), value(0), std_value(0), json_value(0) {
1561  while (jp.peek() != gx_system::JsonParser::end_object) {
1563  if (jp.current_value() == "value") {
1565  value = Gio::File::create_for_path(jp.current_value());
1566  } else if (jp.current_value() == "std_value") {
1568  std_value = Gio::File::create_for_path(jp.current_value());
1569  } else {
1571  "FileParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1572  jp.skip_object();
1573  }
1574  }
1576 }
1577 
1578 void FileParameter::set_path(const string& path) {
1579  Glib::RefPtr<Gio::File> v = Gio::File::create_for_path(path);
1580  if (is_equal(v)) {
1581  return;
1582  }
1583  value = v;
1584  changed();
1585 }
1586 
1587 bool FileParameter::set(const Glib::RefPtr<Gio::File>& val) {
1588  if (is_equal(val)) {
1589  return false;
1590  }
1591  value = val;
1592  changed();
1593  return true;
1594 }
1595 
1596 void FileParameter::set_standard(const string& filename) {
1597  std_value = Gio::File::create_for_path(filename);
1598  if (!value) {
1599  value = std_value->dup();
1600  changed();
1601  }
1602 }
1603 
1605  json_value = std_value->dup();
1606  changed();
1607 }
1608 
1610  return bool(value);
1611 }
1612 
1614  jw.write_kv(_id.c_str(), get_path());
1615 }
1616 
1619  json_value = Gio::File::create_for_path(jp.current_value());
1620 }
1621 
1623  return json_value->get_path() == value->get_path(); //FIXME
1624 }
1625 
1627  set(json_value);
1628 }
1629 
1630 static string get_file_id(const Glib::RefPtr<Gio::File>& f) {
1631  return f->query_info(G_FILE_ATTRIBUTE_ID_FILE)->get_attribute_string(G_FILE_ATTRIBUTE_ID_FILE);
1632 }
1633 
1634 bool FileParameter::is_equal(const Glib::RefPtr<Gio::File>& v) const {
1635  string id, id2;
1636  try {
1637  id = get_file_id(value);
1638  } catch(Gio::Error& ex) {
1639  return false; // FIXME check type of exception
1640  }
1641  try {
1642  id2 = get_file_id(v);
1643  } catch(Gio::Error& ex) {
1644  return false; // FIXME check type of exception
1645  }
1646  return id == id2;
1647 }
1648 
1649 string FileParameter::get_path() const {
1650  return value->get_path();
1651 }
1652 
1654  return value->get_parent()->get_path();
1655 }
1656 
1658  return value->get_parse_name();
1659 }
1660 
1662  return value->query_info(G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)->get_display_name();
1663 }
1664 
1665 void FileParameter::copy(const string& destination) const {
1666  value->copy(Gio::File::create_for_path(destination));
1667 }
1668 
1669 
1670 /* StringParameter */
1671 
1673  jw.begin_object();
1674  jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1675  jw.write_kv("value", *value);
1676  jw.write_kv("std_value", std_value);
1677  jw.end_object();
1678 }
1679 
1681  : Parameter(jp_next(jp, "Parameter")), json_value(""), value(&value_storage), std_value("") {
1682  while (jp.peek() != gx_system::JsonParser::end_object) {
1684  if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1685  } else {
1687  "StringParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1688  jp.skip_object();
1689  }
1690  }
1692 }
1693 
1695 }
1696 
1697 bool StringParameter::set(const Glib::ustring& val) const {
1698  if (val != *value) {
1699  *value = val;
1700  changed(*value);
1701  return true;
1702  }
1703  return false;
1704 }
1705 
1707  return !value->empty();
1708 }
1709 
1711  json_value = std_value;
1712 }
1713 
1715  jw.write_kv(_id.c_str(), *value);
1716 }
1717 
1720  json_value = jp.current_value();
1721 }
1722 
1724  return json_value == *value;
1725 }
1726 
1728  set(json_value);
1729 }
1730 
1731 
1732 /****************************************************************
1733  ** Parameter Map
1734  */
1735 
1737  : id_map(),
1738  replace_mode(false) {
1739 }
1740 
1742  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1743  delete i->second;
1744  }
1745 }
1746 
1748  if (p->isFloat()) {
1749  if (p->getControlType() == Parameter::Enum) {
1750  jw.write("FloatEnum");
1751  } else {
1752  jw.write("Float");
1753  }
1754  } else if (p->isInt()) {
1755  if (p->getControlType() == Parameter::Enum) {
1756  jw.write("Enum");
1757  } else {
1758  jw.write("Int");
1759  }
1760  } else if (p->isBool()) {
1761  jw.write("Bool");
1762  } else if (p->isFile()) {
1763  jw.write("File");
1764  } else if (p->isString()) {
1765  jw.write("String");
1766  } else if (dynamic_cast<JConvParameter*>(p) != 0) {
1767  jw.write("JConv");
1768  } else {
1769 #ifndef NDEBUG
1770  cerr << "skipping " << p->id() << endl;
1771 #endif
1772  return;
1773  }
1774  p->serializeJSON(jw);
1775 }
1776 
1778  jw.begin_array();
1779  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1780  writeJSON_one(jw, i->second);
1781  }
1782  jw.end_array();
1783 }
1784 
1787  if (jp.current_value() == "FloatEnum") {
1788  return insert(new FloatEnumParameterD(jp));
1789  } else if (jp.current_value() == "Float") {
1790  return insert(new FloatParameter(jp));
1791  } else if (jp.current_value() == "Enum") {
1792  return insert(new EnumParameterD(jp));
1793  } else if (jp.current_value() == "Int") {
1794  return insert(new IntParameter(jp));
1795  } else if (jp.current_value() == "Bool") {
1796  return insert(new BoolParameter(jp));
1797  } else if (jp.current_value() == "File") {
1798  return insert(new FileParameter(jp));
1799  } else if (jp.current_value() == "String") {
1800  return insert(new StringParameter(jp));
1801  } else if (jp.current_value() == "JConv") {
1802  return insert(new JConvParameter(jp));
1803  } else {
1805  "ParamMap", Glib::ustring::compose("unknown parameter type: %1", jp.current_value()));
1806  jp.skip_object();
1807  return 0;
1808  }
1809 }
1810 
1813  while (jp.peek() != gx_system::JsonParser::end_array) {
1814  readJSON_one(jp);
1815  }
1817 }
1818 
1819 #ifndef NDEBUG
1820 void ParamMap::unique_id(Parameter* param) {
1821  if (id_map.find(param->id()) != id_map.end()) {
1822  gx_print_error("Debug Check", "id registered twice: " + param->id());
1823  }
1824 }
1825 
1826 void ParamMap::check_id(const string& id) {
1827  if (!hasId(id)) {
1828  cerr << "string-id not found: " << id << endl;
1829  }
1830 }
1831 
1832 void ParamMap::check_p(const char *p) {
1833  if (!hasId(p)) {
1834  cerr << "char-id not found: " << p << endl;
1835  }
1836 }
1837 
1838 void ParamMap::dump(const string& fmt) {
1839  gx_system::JsonWriter *p = 0;
1841  if (fmt == "json") {
1842  jw.set_stream(&cout);
1843  p = &jw;
1844  jw.begin_array();
1845  jw.newline();
1846  } else {
1847  printf("parameter map dump\n");
1848  }
1849  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1850  i->second->dump(p);
1851  }
1852  if (p) {
1853  jw.end_array();
1854  jw.close();
1855  } else {
1856  printf("---------------------\n");
1857  }
1858 }
1859 
1861  if (jw) {
1862  jw->begin_array();
1863  jw->write(id());
1864  switch (c_type) {
1865  case None: jw->write("None"); break;
1866  case Continuous: jw->write("Cont"); break;
1867  case Switch: jw->write("Swth"); break;
1868  case Enum: jw->write("Enum"); break;
1869  default: assert(false);
1870  }
1871  if (save_in_preset) {
1872  jw->write("preset");
1873  }
1874  if (controllable) {
1875  jw->write("control");
1876  }
1877  jw->write(l_group());
1878  jw->write(l_name());
1879  /*
1880  switch (v_type) {
1881  case tp_float: jw->write("f"); jw->write(getFloat().get_value()); break;
1882  case tp_int: jw->write("i"); jw->write(getInt().get_value()); break;
1883  case tp_bool: jw->write("b"); jw->write(getBool().get_value()); break;
1884  case tp_switch: jw->write("s"); jw->write(getSwitch().get()); break;
1885  case tp_file: jw->write("F"); jw->write(getFile().get_parse_name()); break;
1886  case tp_string: jw->write("S"); jw->write(getString().get_value()); break;
1887  case tp_special: jw->write("G"); break;
1888  default: assert(false);
1889  }
1890  */
1891  jw->write(getLowerAsFloat());
1892  jw->write(getUpperAsFloat());
1893  jw->write(getStepAsFloat());
1894  const value_pair *vn = getValueNames();
1895  if (vn) {
1896  jw->begin_array();
1897  for (int n = 0; ; ++n) {
1898  if (!vn[n].value_id) {
1899  break;
1900  }
1901  jw->begin_array();
1902  jw->write(vn[n].value_id);
1903  jw->write(vn[n].value_label ? vn[n].value_label : vn[n].value_id);
1904  jw->end_array();
1905  }
1906  jw->end_array();
1907  }
1908  jw->end_array();
1909  jw->newline();
1910  } else {
1911  printf("P: %s vt=%d ct=%d c=%d\n", _id.c_str(), v_type, c_type, controllable);
1912  }
1913 }
1914 #endif
1915 
1916 Parameter *ParamMap::insert(Parameter* param) {
1917  if (replace_mode) {
1918  map<string, Parameter*>::iterator ii = id_map.find(param->id());
1919  if (ii != id_map.end()) {
1920  Parameter *p = ii->second;
1921  insert_remove(p,false);
1922  id_map.erase(ii);
1923  delete p;
1924  }
1925  }
1926  debug_check(unique_id, param);
1927  id_map.insert(pair<string, Parameter*>(param->id(), param));
1928  insert_remove(param,true);
1929  return param;
1930 }
1931 
1933  if (!p) {
1934  return;
1935  }
1936  insert_remove(p, false);
1937  id_map.erase(p->id());
1938  delete p;
1939 }
1940 
1941 void ParamMap::unregister(const string& id) {
1942  if (!hasId(id)) {
1943  return;
1944  }
1945  unregister(&(*this)[id]);
1946 }
1947 
1949  for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1950  i->second->stdJSON_value();
1951  i->second->setJSON_value();
1952  }
1953 }
1954 
1955 static inline bool compare_groups(const std::string& id, const char **groups) {
1956  if (!groups) {
1957  return false;
1958  }
1959  for (const char **g = groups; *g; g += 2) {
1960  const char *p = *g;
1961  if ((*p) != '.') {
1962  continue;
1963  }
1964  p++;
1965  int n = strlen(p);
1966  if (strncmp(id.c_str(), p, n) == 0 && id[n] == '.') {
1967  return true;
1968  }
1969  }
1970  return false;
1971 }
1972 
1973 bool ParamMap::unit_has_std_values(const PluginDef *pdef) const {
1974  std::string group_id(pdef->id);
1975  group_id += ".";
1976  std::string on_off = group_id + "on_off";
1977  std::string pp = group_id + "pp";
1978  std::string position = group_id + "position";
1979  for (iterator i = begin(); i != end(); ++i) {
1980  if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
1981  if (i->second->isInPreset()) {
1982  if (i->first != on_off && i->first != pp && i->first != position) {
1983  i->second->stdJSON_value();
1984  if (!i->second->compareJSON_value()) {
1985  return false;
1986  break;
1987  }
1988  }
1989  }
1990  }
1991  }
1992  return true;
1993 }
1994 
1995 // reset all parameters to default settings
1996 void ParamMap::reset_unit(const PluginDef *pdef) const {
1997  std::string group_id(pdef->id);
1998  group_id += ".";
1999  std::string on_off = group_id + "on_off";
2000  std::string pp = group_id + "pp";
2001  std::string position = group_id + "position";
2002  for (iterator i = begin(); i != end(); ++i) {
2003  if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
2004  if (i->second->isInPreset()) {
2005  if (i->first != on_off && i->first != pp && i->first != position) {
2006  i->second->stdJSON_value();
2007  i->second->setJSON_value();
2008  }
2009  }
2010  }
2011  }
2012 }
2013 
2014 } // 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:766
void write_kv(const char *key, float v)
Definition: gx_json.h:81
FloatEnumParameter(gx_system::JsonParser &jp)
Definition: gx_parameter.h:273
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:311
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:527
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:131
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:215
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:530
bool isFile() const
Definition: gx_parameter.h:162
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:159
const string & id() const
Definition: gx_parameter.h:169
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:381
FloatEnumParameterD(gx_system::JsonParser &jp)
EnumParameter(gx_system::JsonParser &jp)
Definition: gx_parameter.h:328
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:528
sigc::signal< void > changed
Definition: gx_parameter.h:383
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:272
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:164
#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:327
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:161
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:447
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
list< MidiController > midi_controller_list
Definition: gx_parameter.h:688
void writeJSON(gx_system::JsonWriter &jw) const
bool isInt() const
Definition: gx_parameter.h:160
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:172
Glib::RefPtr< Gio::File > value
Definition: gx_parameter.h:380
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:163
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:395
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:252
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:434
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:193
ParameterV(const string &id, const string &name, ctrl_type ctp, bool preset, bool *v, bool sv, bool ctrl)
Definition: gx_parameter.h:362
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:382
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:768
bool set(const Glib::RefPtr< Gio::File > &val)
virtual void serializeJSON(gx_system::JsonWriter &jw)
iterator end() const
Definition: gx_parameter.h:529
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