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 
midi_to_note(int ctr)111 string MidiStandardControllers::midi_to_note(int ctr) {
112 	static const char* notes[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
113     int octave = (ctr / 12) - 1;
114     ostringstream b;
115     b << octave;
116     string p = b.str().substr(0, 1);
117     int index = (ctr % 12);
118     string note = notes[index];
119     return note + p;
120 }
121 
ctr_desc(int ctr)122 string MidiStandardControllers::ctr_desc(int ctr) {
123     string p = midi_to_note(ctr-200);
124     return  "Note On ( " + p + " )";
125  }
126 
MidiStandardControllers()127 MidiStandardControllers::MidiStandardControllers() {
128     for (unsigned int i = 0; i < sizeof(midi_std_itab)/sizeof(midi_std_itab[0]); i++) {
129         m.insert(pair<int, modstring>(midi_std_itab[i].ctrl, modstring(midi_std_itab[i].name)));
130     }
131     for (unsigned int i = 0; i < 127; i++) {
132         const int mm = i + 200;
133         m.insert(pair<int, modstring>(mm, modstring(ctr_desc(mm).c_str())));
134     }
135 }
136 
replace(int ctr,const string & name)137 void MidiStandardControllers::replace(int ctr, const string& name) {
138     map<int, modstring>::iterator i = m.find(ctr);
139     if (name.empty()) {
140         if (i != m.end()) {
141             if (i->second.modified) {
142                 if (i->second.std) {
143                     i->second.name = m[ctr].std;
144                     m[ctr].modified = false;
145                 } else {
146                     m.erase(i);
147                 }
148             }
149         }
150     } else {
151         if (i == m.end()) {
152             m[ctr] = modstring(name, true, 0);
153         } else {
154             i->second.modified = true;
155             i->second.name = name;
156         }
157     }
158 }
159 
writeJSON(gx_system::JsonWriter & jw) const160 void MidiStandardControllers::writeJSON(gx_system::JsonWriter& jw) const {
161     jw.begin_object(true);
162     for (map<int, modstring>::const_iterator i = m.begin(); i != m.end(); ++i) {
163         if (i->second.modified) {
164             ostringstream ostr;
165             ostr << i->first;
166             jw.write_kv(ostr.str().c_str(), i->second.name);
167         }
168     }
169     jw.end_object(true);
170 }
171 
readJSON(gx_system::JsonParser & jp)172 void MidiStandardControllers::readJSON(gx_system::JsonParser& jp) {
173     jp.next(gx_system::JsonParser::begin_object);
174     while (jp.peek() == gx_system::JsonParser::value_key) {
175         jp.next();
176         istringstream istr(jp.current_value());
177         int ctl;
178         istr >> ctl;
179         if (istr.fail()) {
180             throw gx_system::JsonException(_("midi standard controllers: number expected"));
181         }
182         jp.next();
183         replace(ctl, jp.current_value());
184     }
185     jp.next(gx_system::JsonParser::end_object);
186 }
187 
188 
189 /****************************************************************
190  ** class MidiController
191  */
192 
writeJSON(gx_system::JsonWriter & jw) const193 void MidiController::writeJSON(gx_system::JsonWriter& jw) const {
194     jw.begin_array();
195     jw.write(param->id());
196     if (param->getControlType() == Parameter::Continuous ||
197         param->getControlType() == Parameter::Enum) {
198         jw.write(_lower);
199         jw.write(_upper);
200     } else {
201         assert(param->getControlType() == Parameter::Switch);
202         jw.write(toggle);
203         jw.write(_toggle_behaviour);
204     }
205     jw.end_array();
206 }
207 
readJSON(gx_system::JsonParser & jp,ParamMap & pmap)208 MidiController *MidiController::readJSON(gx_system::JsonParser& jp, ParamMap& pmap) {
209     jp.next(gx_system::JsonParser::begin_array);
210     jp.next(gx_system::JsonParser::value_string);
211     string id = jp.current_value();
212     if (!pmap.hasId(id)) {
213         gx_print_warning(_("Midi controller settings"),
214                                     _("unknown parameter: ") + id);
215         while (jp.next() != gx_system::JsonParser::end_array);
216         return 0;
217     }
218     Parameter& pm = pmap[id];
219     float lower = 0, upper = 0;
220     bool toggle = false;
221     int toggle_behaviour = 0;
222     bool bad = false;
223     bool chg = false;
224     if (pm.getControlType() == Parameter::Continuous ||
225         pm.getControlType() == Parameter::Enum) {
226         if (jp.peek() == gx_system::JsonParser::value_number) {
227             jp.next(gx_system::JsonParser::value_number);
228             if (jp.peek() == gx_system::JsonParser::value_number) {
229                 // two numbers -> range
230                 float pmin, pmax;
231                 if (pm.hasRange()) {
232                     pmin = pm.getLowerAsFloat();
233                     pmax = pm.getUpperAsFloat();
234                 } else {
235                     bad = true;
236                     pmin = pmax = 0;
237                 }
238                 lower = jp.current_value_float();
239                 jp.next(gx_system::JsonParser::value_number);
240                 upper = jp.current_value_float();
241                 if (lower > pmax) {
242                     lower = pmax;
243                     chg = true;
244                 } else if (lower < pmin) {
245                     lower = pmin;
246                     chg = true;
247                 }
248                 if (upper > pmax) {
249                     upper = pmax;
250                     chg = true;
251                 } else if (upper < pmin) {
252                     upper = pmin;
253                     chg = true;
254                 }
255             } else {
256                 // just one number -> switch (new format)
257                 bad = true;
258             }
259         } else {
260             // no number -> switch (old format)
261             bad = true;
262         }
263     } else if (pm.getControlType() == Parameter::Switch) {
264         if (jp.peek() == gx_system::JsonParser::value_number) {
265             jp.next(gx_system::JsonParser::value_number);
266             int _toggle = jp.current_value_int();
267             if (jp.peek() == gx_system::JsonParser::value_number) {
268                 jp.next(gx_system::JsonParser::value_number);
269                 if (jp.current_value_int() < Parameter::toggle_type::_Count) {
270                    toggle = _toggle;
271                    toggle_behaviour = jp.current_value_int();
272                 } else {
273                    // two numbers -> range
274                    bad = true;
275                 }
276             } else {
277                 toggle = _toggle;
278             }
279         }
280     } else {
281         // bad control type
282         bad = true;
283     }
284     assert(jp.peek() == gx_system::JsonParser::end_array);
285     while (jp.next() != gx_system::JsonParser::end_array); // be tolerant (non-debug mode)
286     if (bad) {
287         gx_print_warning(
288             _("recall MIDI state"),
289             _("invalid format, Parameter skipped: ") + id);
290         return 0;
291     }
292     if (chg) {
293         gx_print_warning(
294             _("recall MIDI state"),
295             _("Parameter range outside bounds, changed: ") + id);
296     }
297     return new MidiController(pm, lower, upper, toggle, toggle_behaviour);
298 }
299 
set_midi(int n,int last_value,int * value_set,bool update)300 bool MidiController::set_midi(int n, int last_value, int *value_set, bool update) {
301     bool ret = false;
302     if (param->get_midi_blocked()) return ret;
303     if (toggle) {
304         switch (_toggle_behaviour) {
305             case Parameter::toggle_type::OnOff: {
306                 bool s_o = (2*last_value > 127);
307                 bool s_n = (2*n > 127);
308                 if (!s_o && s_n) {
309                     if (param->on_off_value()) {
310                         ret = param->midi_set(0, 127, _lower, _upper);
311                         *value_set = 0;
312                     } else {
313                         ret = param->midi_set(127, 127, _lower, _upper);
314                         *value_set = 127;
315                     }
316                 }
317                 break;
318             }
319             case Parameter::toggle_type::Constant: {
320                 if (n == last_value || last_value == -1) {
321                     if (param->on_off_value()) {
322                         if (!update) {
323                             ret = param->midi_set(0, n, _lower, _upper);
324                             *value_set = 0;
325                         } else {
326                             ret = param->midi_set(127, n, _lower, _upper);
327                             *value_set = 127;
328                         }
329                     } else {
330                         if (!update) {
331                             ret = param->midi_set(127, n, _lower, _upper);
332                             *value_set = 127;
333                        } else {
334                             ret = param->midi_set(0, n, _lower, _upper);
335                             *value_set = 0;
336                         }
337                     }
338                 }
339                 break;
340             }
341             case Parameter::toggle_type::Toggle: {
342                 if (n !=last_value) {
343                     if (param->on_off_value() && !n) {
344                         ret = param->midi_set(0, 127, _lower, _upper);
345                         *value_set = 0;
346                    } else if (last_value != -1) {
347                         ret = param->midi_set(127, 127, _lower, _upper);
348                         *value_set = 127;
349                    }
350                 }
351                 break;
352             }
353             case Parameter::toggle_type::Commander: {
354                 if (!update) {
355                     if (param->on_off_value()) {
356                         ret = param->midi_set(0, 127, _lower, _upper);
357                         *value_set = 0;
358                     } else {
359                         ret = param->midi_set(127, 127, _lower, _upper);
360                         *value_set = 127;
361                     }
362                 }
363                 break;
364             }
365         }
366     } else {
367         //fprintf(stderr,"continues %s \n",param->id().c_str());
368         //fprintf(stderr,"%f \n",(127.*log10f(double(n+1.)))/2.1072);
369         //fprintf(stderr,"%f \n",double(n * double(double(n+1.)/128)));
370         ret = param->midi_set(n, 127, _lower, _upper);
371         *value_set = n;
372     }
373     return ret;
374 }
375 
set_trans(int n,int last_value)376 bool MidiController::set_trans(int n, int last_value) {
377     bool ret = false;
378     if (param->get_blocked()) return ret;
379     if (strcmp(param->id().c_str(), "engine.mute")==0) {
380         if ( n == 0) n = 127;
381         else n = 0;
382     }
383     ret = param->midi_set(n, 127, _lower, _upper);
384     if (ret) param->trigger_changed();
385     return ret;
386 }
387 
set_bpm(int n,int last_value)388 bool MidiController::set_bpm(int n, int last_value) {
389     bool ret = false;
390     if (param->get_blocked()) return ret;
391     if (toggle) {
392         bool s_o = (2*last_value > 360);
393         bool s_n = (2*n > 360);
394         if (!s_o && s_n) {
395             if (param->on_off_value()) {
396                 ret = param->midi_set_bpm(0, 360, _lower, _upper);
397             } else {
398                 ret = param->midi_set_bpm(360, 360, _lower, _upper);
399             }
400         }
401     } else {
402         ret = param->midi_set_bpm(n, 360, _lower, _upper);
403     }
404     if (ret) param->trigger_changed();
405     return ret;
406 }
407 
408 /****************************************************************
409  ** class ControllerArray
410  */
411 
readJSON(gx_system::JsonParser & jp,ParamMap & param)412 void ControllerArray::readJSON(gx_system::JsonParser& jp, ParamMap& param) {
413     for (unsigned int n = 0; n < array_size; n++) {
414         operator[](n).clear();
415     }
416     jp.next(gx_system::JsonParser::begin_array);
417     while (jp.peek() != gx_system::JsonParser::end_array) {
418             jp.next(gx_system::JsonParser::value_number);
419         midi_controller_list& l = operator[](jp.current_value_int());
420         jp.next(gx_system::JsonParser::begin_array);
421         while (jp.peek() != gx_system::JsonParser::end_array) {
422             MidiController *p = MidiController::readJSON(jp, param);
423             if (p) {
424                 l.push_back(*p);
425                 delete p;
426             }
427         }
428         jp.next(gx_system::JsonParser::end_array);
429     }
430     jp.next(gx_system::JsonParser::end_array);
431 }
432 
writeJSON(gx_system::JsonWriter & w) const433 void ControllerArray::writeJSON(gx_system::JsonWriter& w) const {
434     w.begin_array(true);
435     for (unsigned int n = 0; n < array_size; n++) {
436         const midi_controller_list& cl = operator[](n);
437         if (cl.empty())
438             continue;
439         w.write(n);
440         w.begin_array();
441         for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i)
442             i->writeJSON(w);
443         w.end_array(true);
444     }
445     w.newline();
446     w.end_array(true);
447 }
448 
param2controller(Parameter & param,const MidiController ** p)449 int ControllerArray::param2controller(Parameter& param, const MidiController** p) {
450     for (ControllerArray::size_type n = 0; n < size(); ++n) {
451         const midi_controller_list& cl = operator[](n);
452         for (midi_controller_list::const_iterator i = cl.begin(); i != cl.end(); ++i) {
453             if (i->hasParameter(param)) {
454                 if (p) {
455                     *p = &(*i);
456                 }
457                 return n;
458             }
459         }
460     }
461     return -1;
462 }
463 
deleteParameter(Parameter & p)464 bool ControllerArray::deleteParameter(Parameter& p) {
465     for (iterator pctr = begin(); pctr != end(); ++pctr) {
466         for (midi_controller_list::iterator i = pctr->begin(); i != pctr->end(); ++i) {
467             if (i->hasParameter(p)) {
468                 pctr->erase(i);
469                 return true;
470             }
471         }
472     }
473     return false;
474 }
475 
476 
477 /****************************************************************
478  ** class MidiClockToBpm
479  */
480 
481 
MidiClockToBpm()482 MidiClockToBpm::MidiClockToBpm()
483     : time1(0),
484       time_diff(0),
485       collect(0),
486       collect_(0),
487       bpm(0),
488       bpm_new(0),
489       ret(false) {}
490 
rounded(float f)491 unsigned int MidiClockToBpm::rounded(float f) {
492     if (f >= 0x1.0p23) return (unsigned int) f;
493     return (unsigned int) (f + 0.49999997f);
494 }
495 
time_to_bpm(double time,unsigned int * bpm_)496 bool MidiClockToBpm::time_to_bpm(double time, unsigned int* bpm_) {
497     ret = false;
498     // if time drift to far, reset bpm detection.
499     if ((time-time1)> (1.05*time_diff) || (time-time1)*1.05 < (time_diff)) {
500         bpm = 0;
501         collect = 0;
502         collect_ = 0;
503     } else {
504         bpm_new = ((1000000000. / (time-time1) / 24) * 60);
505         bpm += bpm_new;
506         collect++;
507 
508         if (collect >= (bpm_new*bpm_new*0.0002)+1) {
509             bpm = (bpm/collect);
510             if (collect_>=2) {
511                 (*bpm_) = rounded(min(360.,max(24.,bpm)));
512                 collect_ = 0;
513                 ret = true;
514             }
515             collect_++;
516             collect = 1;
517         }
518     }
519     time_diff = time-time1;
520     time1 = time;
521     return ret;
522 }
523 
524 /****************************************************************
525  ** class MidiControllerList
526  */
527 
MidiControllerList()528 MidiControllerList::MidiControllerList()
529     : map(),
530       last_midi_control_value(),
531       last_midi_control(-2),
532       changed_midi_control_value(),
533       program_change(-1),
534       mute_change(-1),
535       bank_change(-1),
536       bank_changed(0),
537       time0(0),
538       bpm_(9),
539       mp(),
540       pgm_chg(),
541       mute_chg(),
542       bank_chg(),
543       val_chg(),
544       changed(),
545       new_program(),
546       new_mute_state(),
547       new_bank(),
548       midi_value_changed(),
549       trigger_midi_feedback() {
550     for (int i = 0; i < ControllerArray::array_size; ++i) {
551         last_midi_control_value[i] = -1;
552         changed_midi_control_value[i] = 0;
553     }
554     pgm_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_pgm_chg));
555     mute_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_mute_chg));
556     bank_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_bank_chg));
557    // val_chg.connect(sigc::mem_fun(*this, &MidiControllerList::on_val_chg));
558     Glib::signal_timeout().connect(
559          sigc::mem_fun(this, &MidiControllerList::check_midi_values), 60);
560 }
561 
check_midi_values()562 bool MidiControllerList::check_midi_values() {
563     static int saved_values[ControllerArray::array_size];
564     for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
565         if (changed_midi_control_value[n]) {
566             changed_midi_control_value[n] = 0;
567             saved_values[n] = last_midi_control_value[n];
568             midi_value_changed(n, saved_values[n]);
569             if (!get_config_mode()) {
570                 midi_controller_list& ctr_list = map[n];
571                 for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
572                     if (i->is_toggle()
573                         && i->toggle_behaviour() == Parameter::toggle_type::Constant) {
574                         midi_value_changed(n, i->getParameter().on_off_value() * 127);
575                     }
576                     if (!i->getParameter().get_blocked()) i->trigger_changed();
577                 }
578             }
579         }
580     }
581     return true;
582 }
583 
on_val_chg()584 void MidiControllerList::on_val_chg() {
585     static int saved_values[ControllerArray::array_size];
586     for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
587         if (changed_midi_control_value[n]) {
588             changed_midi_control_value[n] = 0;
589             saved_values[n] = last_midi_control_value[n];
590             midi_value_changed(n, saved_values[n]);
591             if (!get_config_mode()) {
592                 midi_controller_list& ctr_list = map[n];
593                 for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
594                     if (i->is_toggle()
595                         && i->toggle_behaviour() == Parameter::toggle_type::Constant) {
596                         midi_value_changed(n, i->getParameter().on_off_value() * 127);
597                     }
598                 }
599             }
600         }
601     }
602 }
603 
604 /** update all controlled parameters with last received value from MIDI controller ctr. */
update_from_controller(int ctr)605 void MidiControllerList::update_from_controller(int ctr) {
606     int v = get_last_midi_control_value(ctr);
607     if (v >= 0) {
608         midi_controller_list& cl = map[ctr];
609         for (midi_controller_list::iterator i = cl.begin(); i != cl.end(); ++i) {
610             int value_set = -1;
611             i->set_midi(v, v, &value_set, true);
612         }
613     }
614 }
615 
update_from_controllers()616 void MidiControllerList::update_from_controllers() {
617     for (unsigned int n = 0; n < map.size(); n++) {
618         update_from_controller(n);
619     }
620 }
621 
on_pgm_chg()622 void MidiControllerList::on_pgm_chg() {
623     int pgm;
624     do {
625         pgm = gx_system::atomic_get(program_change);
626     } while (!gx_system::atomic_compare_and_exchange(&program_change, pgm, -1));
627     if (pgm>=0 || bank_changed) {
628         new_program(pgm);
629         bank_changed = 0;
630     }
631 }
632 
on_mute_chg()633 void MidiControllerList::on_mute_chg() {
634     int mute;
635     do {
636         mute = gx_system::atomic_get(mute_change);
637     } while (!gx_system::atomic_compare_and_exchange(&mute_change, mute, -1));
638     new_mute_state(mute);
639 }
640 
on_bank_chg()641 void MidiControllerList::on_bank_chg() {
642     int bk;
643     do {
644         bk = gx_system::atomic_get(bank_change);
645     } while (!gx_system::atomic_compare_and_exchange(&bank_change, bk, -1));
646     if (bk>=0) {
647         new_bank(bk);
648         bank_changed = 1;
649     }
650 }
651 
set_config_mode(bool mode,int ctl)652 void MidiControllerList::set_config_mode(bool mode, int ctl) {
653     assert(mode != get_config_mode());
654     if (mode) {
655         last_midi_control = ctl;
656     } else {
657         last_midi_control = -2;
658     }
659 }
660 
deleteParameter(Parameter & p)661 void MidiControllerList::deleteParameter(Parameter& p) {
662     bool mode = get_config_mode();
663     if (!mode) {
664         set_config_mode(true); // keep rt thread away from table
665     }
666     if (map.deleteParameter(p)) {
667         changed();
668     }
669     if (!mode) {
670         set_config_mode(false);
671     }
672 }
673 
modifyCurrent(Parameter & param,float lower,float upper,bool toggle,int toggle_behaviour)674 void MidiControllerList::modifyCurrent(Parameter &param,
675                                        float lower, float upper, bool toggle, int toggle_behaviour) {
676     if (!get_config_mode()) {
677         assert(false);
678         return;	// keep rt thread away from table
679     }
680     // maximal one controller for a zone allowed
681     deleteParameter(param);
682     if (last_midi_control < 0)
683         return;
684     // add zone to controller
685     map[last_midi_control].push_front(MidiController(param, lower, upper, toggle, toggle_behaviour));
686     update_from_controller(last_midi_control);
687     changed();
688 }
689 
request_midi_value_update()690 void MidiControllerList::request_midi_value_update() {
691     for (unsigned int n = 0; n < ControllerArray::array_size; ++n) {
692         int v = last_midi_control_value[n];
693         midi_controller_list& ctr_list = map[n];
694         for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
695             if (i->is_toggle()) {
696                 v = i->getParameter().on_off_value() * 127;
697             }
698             midi_value_changed(n, v);
699         }
700     }
701 }
702 
set_ctr_val(int ctr,int val)703 void MidiControllerList::set_ctr_val(int ctr, int val) {
704     if (get_config_mode()) {
705         last_midi_control = ctr;
706     } else {
707         midi_controller_list& ctr_list = map[ctr];
708         for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
709             int value_set = -1;
710             if( i->set_midi(val, get_last_midi_control_value(ctr), &value_set, false)) {
711                 trigger_midi_feedback(ctr,value_set);
712 
713             }
714         }
715     }
716     MidiControllerList::set_last_midi_control_value(ctr, val);
717 }
718 
set_bpm_val(unsigned int val)719 void MidiControllerList::set_bpm_val(unsigned int val) {
720     if (get_config_mode()) {
721         last_midi_control = 22;
722     } else {
723         midi_controller_list& ctr_list = map[22];
724         for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
725             i->set_bpm(val, get_last_midi_control_value(22));
726         }
727     }
728     MidiControllerList::set_last_midi_control_value(22, val);
729 }
730 
set_controller_array(const ControllerArray & m)731 void MidiControllerList::set_controller_array(const ControllerArray& m) {
732     bool mode = get_config_mode();
733     if (!mode) {
734         set_config_mode(true); // keep rt thread away from table
735     }
736     map = m;
737     if (!mode) {
738         set_config_mode(false);
739     }
740     changed();
741 }
742 
remove_controlled_parameters(paramlist & plist,const ControllerArray * new_m)743 void MidiControllerList::remove_controlled_parameters(paramlist& plist,
744                                                       const ControllerArray *new_m) {
745     std::set<Parameter*> pset;
746     for (unsigned int i = 0; i < map.size(); i++) {
747         midi_controller_list& ctr = map[i];
748         for (midi_controller_list::iterator j = ctr.begin(); j != ctr.end(); ++j) {
749             if (new_m) {
750                 const midi_controller_list& ctr_new = (*new_m)[i];
751                 for (midi_controller_list::const_iterator jn = ctr_new.begin();
752                                                           jn != ctr_new.end(); ++jn) {
753                     if (j->getParameter() == jn->getParameter()) {
754                         pset.insert(&j->getParameter());
755                         break;
756                     }
757                 }
758             } else {
759                 pset.insert(&j->getParameter());
760             }
761         }
762     }
763     for (paramlist::iterator n = plist.begin(); n != plist.end(); ) {
764         paramlist::iterator n1 = n++;
765         if (pset.find(*n1) != pset.end()) {
766             plist.erase(n1);
767         }
768     }
769 }
770 
set_midi_channel(int s)771 void MidiControllerList::set_midi_channel(int s) {
772     channel_select = s;
773 }
774 
process_trans(int transport_state)775 void MidiControllerList::process_trans(int transport_state) {
776     unsigned int val = 0;
777     switch (transport_state) {
778         case JackTransportStopped:
779             val = 0;
780             break;
781         case JackTransportRolling:
782             val = 127;
783             break;
784         case JackTransportStarting:
785             val = 127;
786             break;
787         default:
788             return;
789     }
790     if (get_config_mode()) {
791         last_midi_control = 24;
792     } else {
793         midi_controller_list& ctr_list = map[24];
794         for (midi_controller_list::iterator i = ctr_list.begin(); i != ctr_list.end(); ++i) {
795             i->set_trans(val, get_last_midi_control_value(24));
796         }
797     }
798     MidiControllerList::set_last_midi_control_value(24, val);
799     val_chg();
800 }
801 
802 // ----- jack process callback for the midi input
compute_midi_in(void * midi_input_port_buf,void * arg)803 void MidiControllerList::compute_midi_in(void* midi_input_port_buf, void *arg) {
804     jack_midi_event_t in_event;
805     jack_nframes_t event_count = jack_midi_get_event_count(midi_input_port_buf);
806     unsigned int i;
807     for (i = 0; i < event_count; i++) {
808         jack_midi_event_get(&in_event, midi_input_port_buf, i);
809         bool ch = true;
810         if (channel_select>0) {
811             if ((channel_select) != (int(in_event.buffer[0]&0x0f)+1)) {
812                 ch = false;
813             }
814         }
815         if ((in_event.buffer[0] & 0xf0) == 0xc0 && ch) {  // program change on any midi channel
816             gx_system::atomic_set(&program_change, in_event.buffer[1]);
817             pgm_chg();
818         } else if ((in_event.buffer[0] & 0xf0) == 0xb0 && ch) {   // controller
819             if (in_event.buffer[1]== 120) { // engine mute by All Sound Off on any midi channel
820                 gx_system::atomic_set(&mute_change, in_event.buffer[2]);
821                 mute_chg();
822             } else if ((in_event.buffer[1]== 32 ||
823                         in_event.buffer[1]== 0) && ch) { // bank change (LSB/MSB) on any midi channel
824                 gx_system::atomic_set(&bank_change, in_event.buffer[2]);
825                 bank_chg();
826             } else {
827                 set_ctr_val(in_event.buffer[1], in_event.buffer[2]);
828                 val_chg();
829             }
830         } else if ((in_event.buffer[0] & 0xf0) == 0x90 && ch) {   // Note On
831             set_ctr_val(in_event.buffer[1]+200, 1);
832             val_chg();
833             //fprintf(stderr,"Note On %i", (int)in_event.buffer[1]);
834         } else if ((in_event.buffer[0] ) > 0xf0) {   // midi clock
835             if ((in_event.buffer[0] ) == 0xf8) {   // midi beat clock
836                 clock_gettime(CLOCK_MONOTONIC, &ts1);
837                 gx_jack::GxJack& jack = *static_cast<gx_jack::GxJack*>(arg);
838                 static unsigned int sr = jack.get_jack_sr();
839                 time0 = (ts1.tv_sec*1000000000.0)+(ts1.tv_nsec)+
840                         (1000000000.0/(double)(sr/(double)in_event.time));
841                 if (mp.time_to_bpm(time0, &bpm_)) {
842                     set_bpm_val(bpm_);
843                     val_chg();
844                 }
845             } else if ((in_event.buffer[0] ) == 0xfa) {   // midi clock start
846                 set_ctr_val(23, 127);
847                 val_chg();
848             } else if ((in_event.buffer[0] ) == 0xfb) {   // midi clock continue
849                //  set_ctr_val(23, 127);
850             } else if ((in_event.buffer[0] ) == 0xfc) {   // midi clock stop
851                 set_ctr_val(23, 0);
852                 val_chg();
853             } else if ((in_event.buffer[0] ) == 0xf2) {   // midi clock position
854               // not implemented
855               //  set_ctr_val(24,(in_event.buffer[2]<<7) | in_event.buffer[1]);
856             }
857         }
858     }
859 }
860 
861 /****************************************************************
862  ** Parameter Groups
863  */
864 
ParameterGroups()865 ParameterGroups::ParameterGroups() {
866     insert("system", N_("System"));
867     insert("ui", N_("User Interface"));
868     insert("ui.amp", N_("User Interface")); // FIXME (ui.amp.tonestack)
869     insert("engine", N_("Audio Engine"));
870 }
871 
~ParameterGroups()872 ParameterGroups::~ParameterGroups() {
873 #ifndef NDEBUG
874     for (map<string, bool>::iterator i = used.begin(); i != used.end(); ++i) {
875         if (!i->second) {
876             gx_print_error("Debug Check", "Group not used: " + i->first);
877         }
878     }
879 #endif
880 }
881 
882 #ifndef NDEBUG
group_exists(const string & id)883 void ParameterGroups::group_exists(const string& id) {
884     if (groups.find(id) == groups.end()) {
885         gx_print_error("Debug Check", "Group does not exist: " + id);
886     } else {
887         used[id] = true;
888     }
889 }
890 
group_is_new(const string & id)891 void ParameterGroups::group_is_new(const string& id) {
892     if (groups.find(id) != groups.end()) {
893         gx_print_error("Debug Check", "Group already exists: " + id);
894     }
895 }
896 
dump()897 void ParameterGroups::dump() {
898     for (map<string, string>::iterator i = groups.begin(); i != groups.end(); ++i) {
899         printf("PG %s: %s\n", i->first.c_str(), i->second.c_str());
900     }
901 }
902 
903 #endif
904 
get_group_table()905 ParameterGroups& get_group_table() {
906     static ParameterGroups groups;
907     return groups;
908 }
909 
param_group(const string & group_id,bool nowarn)910 string param_group(const string& group_id, bool nowarn) {
911     static ParameterGroups& groups = get_group_table();
912     if (nowarn) {
913         return groups.get(group_id);
914     } else {
915         return groups[group_id];
916     }
917 }
918 
group_exist(const string & id)919 bool ParameterGroups::group_exist(const string& id) {
920     if (groups.find(id) == groups.end()) {
921         return false;
922     } else {
923         return true;
924     }
925 }
926 
927 /****************************************************************
928  ** Parameter
929  */
930 
jp_next(gx_system::JsonParser & jp,const char * key)931 gx_system::JsonParser& Parameter::jp_next(gx_system::JsonParser& jp, const char *key) {
932     jp.next(gx_system::JsonParser::begin_object);
933     jp.next(gx_system::JsonParser::value_key);
934     assert(jp.current_value() == key);
935     return jp;
936 }
937 
serializeJSON(gx_system::JsonWriter & jw)938 void Parameter::serializeJSON(gx_system::JsonWriter& jw) {
939     jw.begin_object();
940     jw.write_kv("id", _id);
941     jw.write_kv("name", _name);
942     jw.write_kv("group", _group);
943     jw.write_kv("desc", _desc);
944     jw.write_kv("v_type", v_type); //FIXME
945     jw.write_kv("c_type", c_type); //FIXME
946     jw.write_kv("d_flags", d_flags); //FIXME
947     if (!controllable) {
948         jw.write_key("non_controllable"); jw.write(false);
949     }
950     if (!save_in_preset) {
951         jw.write_key("non_preset"); jw.write(false);
952     }
953     if (do_not_save) {
954         jw.write_key("do_not_save"); jw.write(true);
955     }
956     if (output) {
957         jw.write_key("output"); jw.write(true);
958     }
959     if (maxlevel) {
960         jw.write_key("maxlevel"); jw.write(true);
961     }
962     jw.end_object();
963 }
964 
Parameter(gx_system::JsonParser & jp)965 Parameter::Parameter(gx_system::JsonParser& jp)
966     : boost::noncopyable(),
967       _id(),
968       _name(),
969       _group(),
970       _desc(),
971       v_type(tp_float),
972       c_type(Continuous),
973       d_flags(0),
974       save_in_preset(true),
975       controllable(true),
976       do_not_save(false),
977       blocked(false),
978       midi_blocked(false),
979       output(false),
980       maxlevel(false),
981       used(false) {
982     jp.next(gx_system::JsonParser::begin_object);
983     while (jp.peek() != gx_system::JsonParser::end_object) {
984         jp.next(gx_system::JsonParser::value_key);
985         if (jp.read_kv("id", _id) ||
986             jp.read_kv("name", _name) ||
987             jp.read_kv("group", _group) ||
988             jp.read_kv("desc", _desc)) {
989         } else if (jp.current_value() == "v_type") {
990             jp.next(gx_system::JsonParser::value_number);
991             v_type = static_cast<value_type>(jp.current_value_int());
992         } else if (jp.current_value() == "c_type") {
993             jp.next(gx_system::JsonParser::value_number);
994             c_type = static_cast<ctrl_type>(jp.current_value_int());
995         } else if (jp.current_value() == "d_flags") {
996             jp.next(gx_system::JsonParser::value_number);
997             d_flags = jp.current_value_int();
998         } else if (jp.current_value() == "non_controllable") {
999             jp.next(gx_system::JsonParser::value_number);
1000             controllable = false;
1001         } else if (jp.current_value() == "non_preset") {
1002             jp.next(gx_system::JsonParser::value_number);
1003             save_in_preset = false;
1004         } else if (jp.current_value() == "do_not_save") {
1005             jp.next(gx_system::JsonParser::value_number);
1006             do_not_save = true;
1007         } else if (jp.current_value() == "output") {
1008             jp.next(gx_system::JsonParser::value_number);
1009             output = true;
1010         } else if (jp.current_value() == "maxlevel") {
1011             jp.next(gx_system::JsonParser::value_number);
1012             maxlevel = true;
1013         } else {
1014             gx_print_warning(
1015             "Parameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1016             jp.skip_object();
1017         }
1018     }
1019     jp.next(gx_system::JsonParser::end_object);
1020 }
1021 
~Parameter()1022 Parameter::~Parameter() {
1023 }
1024 
midi_set(float n,float high,float llimit,float ulimit)1025 bool Parameter::midi_set(float n, float high, float llimit, float ulimit) {
1026     assert(false);
1027     return false;
1028 }
1029 
midi_set_bpm(float n,float high,float llimit,float ulimit)1030 bool Parameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
1031     assert(false);
1032     return false;
1033 }
1034 
trigger_changed()1035 void Parameter::trigger_changed() {
1036     assert(false);
1037 }
1038 
get_upper(const value_pair * vn)1039 static int get_upper(const value_pair *vn) {
1040     for (int n = 0; ; n++) {
1041         if (!vn[n].value_id) {
1042             return n - 1;
1043         }
1044     }
1045 }
1046 
range_warning(float value,float lower,float upper)1047 void Parameter::range_warning(float value, float lower, float upper) {
1048     gx_print_warning(_("parameter load"),
1049         Glib::ustring::compose(_("parameter %1: value %2 out of range [%3, %4]"),
1050                     _id, value, lower, upper));
1051 }
1052 
get_typename() const1053 const char *Parameter::get_typename() const {
1054     static const char *tpname[] = {
1055         "float", "int", "bool", "bool", "filename", "string", "special"};
1056     assert(0 <= v_type and v_type < sizeof(tpname)/sizeof(tpname[0]));
1057     return tpname[v_type];
1058 }
1059 
hasRange() const1060 bool Parameter::hasRange() const {
1061     return false;
1062 }
1063 
getStepAsFloat() const1064 float Parameter::getStepAsFloat() const {
1065     return 1;
1066 }
1067 
getLowerAsFloat() const1068 float Parameter::getLowerAsFloat() const {
1069     return 0;
1070 }
1071 
getUpperAsFloat() const1072 float Parameter::getUpperAsFloat() const {
1073     return 0;
1074 }
1075 
getValueNames() const1076 const value_pair *Parameter::getValueNames() const {
1077     return 0;
1078 }
1079 
1080 #ifndef NDEBUG
compare_parameter(const char * title,Parameter * p1,Parameter * p2,bool all)1081 void compare_parameter(const char *title, Parameter* p1, Parameter* p2, bool all) {
1082     if (p1->_id != p2->_id) {
1083         gx_print_warning(
1084             title, Glib::ustring::compose("Different ID's: %2 / %3",
1085                           p1->_id, p2->_id));
1086     }
1087     if (p1->_name != p2->_name) {
1088         gx_print_warning(
1089             title, Glib::ustring::compose("[%1]: Different name: %2 / %3",
1090                           p1->_id, p1->_name, p2->_name));
1091     }
1092     if (p1->_group != p2->_group) {
1093         gx_print_warning(
1094             title, Glib::ustring::compose("[%1]: Different group: %2 / %3",
1095                           p1->_id, p1->_group, p2->_group));
1096     }
1097     if (p1->_desc != p2->_desc) {
1098         gx_print_warning(
1099             title, Glib::ustring::compose("[%1]: Different desc: %2 / %3",
1100                           p1->_id, p1->_desc, p2->_desc));
1101     }
1102     if (p1->save_in_preset != p2->save_in_preset) {
1103         gx_print_warning(
1104             title, Glib::ustring::compose("[%1]: save_in_preset different: %2 / %3",
1105                           p1->_id, p1->save_in_preset, p2->save_in_preset));
1106     }
1107     if (p1->controllable != p2->controllable) {
1108         gx_print_warning(
1109             title, Glib::ustring::compose("[%1]: controllable different: %2 / %3",
1110                           p1->_id, p1->controllable, p2->controllable));
1111     }
1112     if (p1->used != p2->used) {
1113         gx_print_warning(
1114             title, Glib::ustring::compose("[%1]: used different: %2 / %3",
1115                           p1->_id, p1->used, p2->used));
1116     }
1117         if (p1->c_type != p2->c_type) {
1118         gx_print_warning(
1119             title, Glib::ustring::compose("[%1]: c_type different: %2 / %3",
1120                           p1->_id, p1->c_type, p2->c_type));
1121     }
1122     if (p1->v_type != p2->v_type) {
1123         gx_print_warning(
1124             title, Glib::ustring::compose("[%1]: v_type different: %2 / %3",
1125                           p1->_id, p1->v_type, p2->v_type));
1126         return;
1127     }
1128     if (p1->isFloat()) {
1129         FloatParameter& f1 = p1->getFloat();
1130         FloatParameter& f2 = p2->getFloat();
1131         if (f1.value != f2.value) {
1132             gx_print_warning(
1133             title, Glib::ustring::compose("[%1]: value address different: %2 / %3",
1134                               p1->_id, f1.value, f2.value));
1135         }
1136         if (f1.lower != f2.lower) {
1137             gx_print_warning(
1138 
1139             title, Glib::ustring::compose("[%1]: float lower different: %2 / %3",
1140                               p1->_id, f1.lower, f2.lower));
1141         }
1142         if (f1.upper != f2.upper) {
1143             gx_print_warning(
1144             title, Glib::ustring::compose("[%1]: float upper different: %2 / %3",
1145                               p1->_id, f1.upper, f2.upper));
1146         }
1147         if (f1.step != f2.step) {
1148             gx_print_warning(
1149             title, Glib::ustring::compose("[%1]: float step different: %2 / %3",
1150                               p1->_id, f1.step, f2.step));
1151         }
1152         if (f1.std_value != f2.std_value) {
1153             gx_print_warning(
1154             title, Glib::ustring::compose("[%1]: float std value different: %2 / %3",
1155                               p1->_id, f1.std_value, f2.std_value));
1156         }
1157         if (all) {
1158             if (f1.value != f2.value) {
1159                 gx_print_warning(
1160                     title, Glib::ustring::compose("[%1]: float value different: %2 / %3",
1161                                   p1->_id, *f1.value, *f2.value));
1162             }
1163             if (f1.json_value != f2.json_value) {
1164                 gx_print_warning(
1165                     title, Glib::ustring::compose("[%1]: float json value different: %2 / %3",
1166                                   p1->_id, f1.json_value, f2.json_value));
1167             }
1168         }
1169         return;
1170     }
1171     if (p1->isInt()) {
1172         assert(false);
1173         return;
1174     }
1175     if (p1->isBool()) {
1176         assert(false);
1177         return;
1178     }
1179     if (p1->isFile()) {
1180         assert(false);
1181         return;
1182     }
1183     assert(false);
1184 }
1185 #endif
1186 
1187 /* FloatParameter */
1188 
serializeJSON(gx_system::JsonWriter & jw)1189 void FloatParameter::serializeJSON(gx_system::JsonWriter& jw) {
1190     jw.begin_object();
1191     jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1192     jw.write_kv("lower", lower);
1193     jw.write_kv("upper", upper);
1194     jw.write_kv("step", step);
1195     jw.write_kv("value", *value);
1196     jw.write_kv("std_value", std_value);
1197     jw.end_object();
1198 }
1199 
ParameterV(gx_system::JsonParser & jp)1200 FloatParameter::ParameterV(gx_system::JsonParser& jp)
1201     : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper(), step() {
1202     while (jp.peek() != gx_system::JsonParser::end_object) {
1203         jp.next(gx_system::JsonParser::value_key);
1204         if (jp.read_kv("lower", lower) ||
1205             jp.read_kv("upper", upper) ||
1206             jp.read_kv("step", step) ||
1207             jp.read_kv("value", *value) ||
1208             jp.read_kv("std_value", std_value)) {
1209         } else {
1210             gx_print_warning(
1211             "FloatParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1212             jp.skip_object();
1213         }
1214     }
1215     jp.next(gx_system::JsonParser::end_object);
1216 }
1217 
~ParameterV()1218 FloatParameter::~ParameterV() {
1219 }
1220 
set(float val) const1221 bool FloatParameter::set(float val) const {
1222     float v = min(max(val, lower), upper);
1223     if (std::fabs(v - *value) >= step) {
1224         *value = v;
1225         changed(v);
1226         return true;
1227     }
1228     return false;
1229 }
1230 
on_off_value()1231 bool FloatParameter::on_off_value() {
1232     return *value != 0;
1233 }
1234 
idx_from_id(string v_id)1235 float FloatParameter::idx_from_id(string v_id) {
1236     assert(false);
1237     return 0;
1238 }
1239 
midi_set(float n,float high,float llimit,float ulimit)1240 bool FloatParameter::midi_set(float n, float high, float llimit, float ulimit) {
1241     float v;
1242     switch (c_type) {
1243     case Continuous:
1244         assert(n >= 0 && n <= high);
1245         v = llimit + (n / high) * (ulimit - llimit);
1246         break;
1247     case Switch:
1248         v = (2*n > high ? 1.0 : 0.0);
1249         break;
1250     case Enum:
1251         v = lower + min(n, upper-lower);
1252         break;
1253     default:
1254         assert(false);
1255         return false;
1256     }
1257     if (std::fabs(v - *value) >= step) {
1258         *value = v;
1259         return true;
1260     }
1261     return false;
1262 }
1263 
midi_set_bpm(float n,float high,float llimit,float ulimit)1264 bool FloatParameter::midi_set_bpm(float n, float high, float llimit, float ulimit) {
1265     float v;
1266     switch (c_type) {
1267     case Continuous:
1268         assert(n >= 0 && n <= high);
1269         if (high <= ulimit) {
1270             v = max(llimit,min(ulimit,n));
1271         } else {
1272             v = llimit + (n / high) * (ulimit - llimit);
1273         }
1274         break;
1275     case Switch:
1276         v = (2*n > high ? 1.0 : 0.0);
1277         break;
1278     case Enum:
1279         v = lower + min(n, upper-lower);
1280         break;
1281     default:
1282         assert(false);
1283         return false;
1284     }
1285     if (std::fabs(v - *value) >= step) {
1286         *value = v;
1287         return true;
1288     }
1289     return false;
1290 }
1291 
trigger_changed()1292 void FloatParameter::trigger_changed() {
1293     changed(*value);
1294 }
1295 
stdJSON_value()1296 void FloatParameter::stdJSON_value() {
1297     json_value = std_value;
1298 }
1299 
writeJSON(gx_system::JsonWriter & jw) const1300 void FloatParameter::writeJSON(gx_system::JsonWriter& jw) const {
1301     jw.write_kv(_id.c_str(), *value);
1302 }
1303 
ramp_value(float val)1304 bool FloatParameter::ramp_value(float val) {
1305     if (std::abs(json_value - val) < 10*FLT_EPSILON || std::abs(json_value )> std::abs(val)) {
1306         json_value = val;
1307         setJSON_value();
1308         return false;
1309     } else if (val<=std_value) {
1310         json_value = val;
1311         setJSON_value();
1312         return false;
1313     }
1314     float v = val * 0.1;
1315     json_value += v;
1316     setJSON_value();
1317     //fprintf(stderr, "set value %f of %f\n",json_value, val);
1318     return true;
1319 }
1320 
rampJSON_value(gx_system::JsonParser & jp)1321 void FloatParameter::rampJSON_value(gx_system::JsonParser& jp) {
1322     jp.next(gx_system::JsonParser::value_number);
1323     json_value = std_value;
1324      Glib::signal_timeout().connect(sigc::bind<float>(
1325          sigc::mem_fun (*this, &FloatParameter::ramp_value),jp.current_value_float()), 10);
1326 }
1327 
readJSON_value(gx_system::JsonParser & jp)1328 void FloatParameter::readJSON_value(gx_system::JsonParser& jp) {
1329     jp.next(gx_system::JsonParser::value_number);
1330     json_value = jp.current_value_float();
1331     if (json_value < lower-std::abs(5*FLT_EPSILON*lower) || json_value > upper+std::abs(5*FLT_EPSILON*upper)) {
1332         range_warning(json_value, lower, upper);
1333         json_value = std_value;
1334     }
1335 }
1336 
compareJSON_value()1337 bool FloatParameter::compareJSON_value() {
1338     return std::abs(json_value - *value) < 5*FLT_EPSILON;
1339 }
1340 
setJSON_value()1341 void FloatParameter::setJSON_value() {
1342     set(json_value);
1343 }
1344 
convert_from_range(float low,float up)1345 void FloatParameter::convert_from_range(float low, float up) {
1346     json_value = lower + (json_value - low) / (up - low) * (upper - lower);
1347 }
1348 
hasRange() const1349 bool FloatParameter::hasRange() const {
1350     return true;
1351 }
1352 
getLowerAsFloat() const1353 float FloatParameter::getLowerAsFloat() const {
1354     return lower;
1355 }
1356 
getUpperAsFloat() const1357 float FloatParameter::getUpperAsFloat() const {
1358     return upper;
1359 }
1360 
getStepAsFloat() const1361 float FloatParameter::getStepAsFloat() const {
1362     return step;
1363 }
1364 
1365 
1366 /* FloatEnumParameter */
1367 
serializeValueNames(gx_system::JsonWriter & jw,const value_pair * p)1368 static void serializeValueNames(gx_system::JsonWriter& jw, const value_pair *p) {
1369     jw.write_key("value_names");
1370     jw.begin_array();
1371     while (p->value_id) {
1372         jw.write(p->value_id);
1373         if (p->value_label) {
1374             jw.write(p->value_label);
1375         } else {
1376             jw.write(p->value_id);
1377         }
1378         p++;
1379     }
1380     jw.end_array();
1381 }
1382 
serializeJSON(gx_system::JsonWriter & jw)1383 void FloatEnumParameter::serializeJSON(gx_system::JsonWriter& jw) {
1384     jw.begin_object();
1385     jw.write_key("FloatParameter"); FloatParameter::serializeJSON(jw);
1386     serializeValueNames(jw, value_names);
1387     jw.end_object();
1388 }
1389 
FloatEnumParameter(const string & id,const string & name,const value_pair * vn,bool preset,float * v,int sv,int low,bool ctrl,bool no_init)1390 FloatEnumParameter::FloatEnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1391                                        float *v, int sv, int low, bool ctrl, bool no_init):
1392     FloatParameter(id, name, Enum, preset, v, sv, low, low+get_upper(vn), 1, ctrl, no_init),
1393     value_names(vn) {}
1394 
getValueNames() const1395 const value_pair *FloatEnumParameter::getValueNames() const {
1396     return value_names;
1397 }
1398 
writeJSON(gx_system::JsonWriter & jw) const1399 void FloatEnumParameter::writeJSON(gx_system::JsonWriter& jw) const {
1400     jw.write_key(_id.c_str());
1401     jw.write(value_names[static_cast<int>(round(*value-lower))].value_id);
1402 }
1403 
idx_from_id(string v_id)1404 float FloatEnumParameter::idx_from_id(string v_id) {
1405     int up = static_cast<int>(round(upper));
1406     int low = static_cast<int>(round(lower));
1407     int n = 0;
1408     for (; n <= up-low; n++) {
1409         if (v_id == value_names[n].value_id) {
1410             return low + n;
1411         }
1412     }
1413     return -1;
1414 }
1415 
readJSON_value(gx_system::JsonParser & jp)1416 void FloatEnumParameter::readJSON_value(gx_system::JsonParser& jp) {
1417     gx_system::JsonParser::token tok = jp.next();
1418     if (tok == gx_system::JsonParser::value_number) {
1419         // old version compatibility
1420         json_value = jp.current_value_int();
1421         return;
1422     }
1423     jp.check_expect(gx_system::JsonParser::value_string);
1424     float n = idx_from_id(jp.current_value());
1425     if (n < 0) {
1426 #ifndef NEW_LADSPA
1427         bool found;
1428         string v_id = gx_preset::PresetIO::try_replace_param_value(id(), jp.current_value(), found);
1429         if (found) {
1430             n = idx_from_id(v_id);
1431         }
1432 #endif
1433         if (n < 0) {
1434             gx_print_warning(
1435                 _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1436                                       % _id % jp.current_value()).str());
1437             n = lower;
1438         }
1439     }
1440     json_value = n;
1441 }
1442 
1443 /* IntParameter */
1444 
serializeJSON(gx_system::JsonWriter & jw)1445 void IntParameter::serializeJSON(gx_system::JsonWriter& jw) {
1446     jw.begin_object();
1447     jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1448     jw.write_kv("lower", lower);
1449     jw.write_kv("upper", upper);
1450     jw.write_kv("value", *value);
1451     jw.write_kv("std_value", std_value);
1452     jw.end_object();
1453 }
1454 
ParameterV(gx_system::JsonParser & jp)1455 IntParameter::ParameterV(gx_system::JsonParser& jp)
1456     : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0), lower(), upper() {
1457     while (jp.peek() != gx_system::JsonParser::end_object) {
1458         jp.next(gx_system::JsonParser::value_key);
1459         if (jp.read_kv("lower", lower) ||
1460             jp.read_kv("upper", upper) ||
1461             jp.read_kv("value", *value) ||
1462             jp.read_kv("std_value", std_value)) {
1463         } else {
1464             gx_print_warning(
1465             "IntParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1466             jp.skip_object();
1467         }
1468     }
1469     jp.next(gx_system::JsonParser::end_object);
1470 }
1471 
~ParameterV()1472 IntParameter::~ParameterV() {
1473 }
1474 
set(int val) const1475 bool IntParameter::set(int val) const {
1476     int v = min(max(val, lower), upper);
1477     if (v != *value) {
1478         *value = v;
1479         changed(v);
1480         return true;
1481     }
1482     return false;
1483 }
1484 
idx_from_id(string v_id)1485 int IntParameter::idx_from_id(string v_id) {
1486     assert(false);
1487     return 0;
1488 }
1489 
on_off_value()1490 bool IntParameter::on_off_value() {
1491     return *value != 0;
1492 }
1493 
midi_set(float n,float high,float llimit,float ulimit)1494 bool IntParameter::midi_set(float n, float high, float llimit, float ulimit) {
1495     int v;
1496     switch (c_type) {
1497     case Continuous:
1498         assert(false); // not implemented
1499         return false;
1500     case Switch:
1501         assert(false); // not implemented
1502         return false;
1503     case Enum:
1504         v = lower + min(static_cast<int>(n), upper-lower);
1505         break;
1506     default:
1507         assert(false);
1508         return false;
1509     }
1510     if (v != *value) {
1511         *value = v;
1512         return true;
1513     }
1514     return false;
1515 }
1516 
trigger_changed()1517 void IntParameter::trigger_changed() {
1518     changed(*value);
1519 }
1520 
stdJSON_value()1521 void IntParameter::stdJSON_value() {
1522     json_value = std_value;
1523 }
1524 
writeJSON(gx_system::JsonWriter & jw) const1525 void IntParameter::writeJSON(gx_system::JsonWriter& jw) const {
1526     jw.write_kv(_id.c_str(), *value);
1527 }
1528 
readJSON_value(gx_system::JsonParser & jp)1529 void IntParameter::readJSON_value(gx_system::JsonParser& jp) {
1530     jp.next(gx_system::JsonParser::value_number);
1531     json_value = jp.current_value_int();
1532     if (json_value < lower || json_value > upper) {
1533         range_warning(json_value, lower, upper);
1534     }
1535 }
1536 
compareJSON_value()1537 bool IntParameter::compareJSON_value() {
1538     return json_value == *value;
1539 }
1540 
setJSON_value()1541 void IntParameter::setJSON_value() {
1542     set(json_value);
1543 }
1544 
hasRange() const1545 bool IntParameter::hasRange() const {
1546     return true;
1547 }
1548 
getLowerAsFloat() const1549 float IntParameter::getLowerAsFloat() const {
1550     return lower;
1551 }
1552 
getUpperAsFloat() const1553 float IntParameter::getUpperAsFloat() const {
1554     return upper;
1555 }
1556 
1557 /* EnumParameter */
1558 
serializeJSON(gx_system::JsonWriter & jw)1559 void EnumParameter::serializeJSON(gx_system::JsonWriter& jw) {
1560     jw.begin_object();
1561     jw.write_key("IntParameter"); IntParameter::serializeJSON(jw);
1562     serializeValueNames(jw, value_names);
1563     jw.end_object();
1564 }
1565 
EnumParameter(const string & id,const string & name,const value_pair * vn,bool preset,int * v,int sv,bool ctrl)1566 EnumParameter::EnumParameter(const string& id, const string& name, const value_pair* vn, bool preset,
1567                              int *v, int sv, bool ctrl):
1568     IntParameter(id, name, Enum, preset, v, sv, 0, get_upper(vn), ctrl),
1569     value_names(vn) {}
1570 
getValueNames() const1571 const value_pair *EnumParameter::getValueNames() const {
1572     return value_names;
1573 }
1574 
idx_from_id(string v_id)1575 int EnumParameter::idx_from_id(string v_id) {
1576     int n = 0;
1577     for (; n <= upper; n++) {
1578         if (v_id == value_names[n].value_id) {
1579             return n;
1580         }
1581     }
1582     return -1;
1583 }
1584 
writeJSON(gx_system::JsonWriter & jw) const1585 void EnumParameter::writeJSON(gx_system::JsonWriter& jw) const {
1586     jw.write_key(_id.c_str());
1587     jw.write(value_names[*value].value_id);
1588 }
1589 
readJSON_value(gx_system::JsonParser & jp)1590 void EnumParameter::readJSON_value(gx_system::JsonParser& jp) {
1591     gx_system::JsonParser::token tok = jp.next();
1592     if (tok == gx_system::JsonParser::value_number) {
1593         // old version compatibility
1594         json_value = jp.current_value_int();
1595         return;
1596     }
1597     jp.check_expect(gx_system::JsonParser::value_string);
1598     int n = idx_from_id(jp.current_value());
1599     if (n < 0) {
1600         gx_print_warning(
1601             _("read parameter"), (boost::format(_("parameter %1%: unknown enum value: %2%"))
1602                                % _id % jp.current_value()).str());
1603         n = 0;
1604     }
1605     json_value = n;
1606 }
1607 
1608 /* derived enum parameters */
1609 
1610 typedef std::pair<std::string,std::string> id_label;
1611 
enum_parameter_load_values(gx_system::JsonParser & jp,std::vector<id_label> & value_array,const value_pair ** value_names)1612 void enum_parameter_load_values(gx_system::JsonParser& jp, std::vector<id_label>& value_array, const value_pair **value_names) {
1613     while (jp.peek() != gx_system::JsonParser::end_object) {
1614         jp.next(gx_system::JsonParser::value_key);
1615         if (jp.current_value() == "value_names") {
1616             jp.next(gx_system::JsonParser::begin_array);
1617             while (jp.peek() != gx_system::JsonParser::end_array) {
1618             jp.next(gx_system::JsonParser::value_string);
1619             std::string value_id = jp.current_value();
1620             jp.next(gx_system::JsonParser::value_string);
1621             std::string value_label = jp.current_value();
1622             value_array.push_back(id_label(value_id, value_label));
1623             }
1624             jp.next(gx_system::JsonParser::end_array);
1625         } else {
1626             gx_print_warning(
1627             "EnumValueNames", Glib::ustring::compose("unknown key: %1", jp.current_value()));
1628             jp.skip_object();
1629         }
1630     }
1631     jp.next(gx_system::JsonParser::end_object);
1632     value_pair* p = new value_pair[value_array.size()+1];
1633     *value_names = p;
1634     for (std::vector<id_label>::iterator i = value_array.begin(); i != value_array.end(); ++i) {
1635         p->value_id = i->first.c_str();
1636         p->value_label = i->second.c_str();
1637         p++;
1638     }
1639     p->value_id = p->value_label = 0;
1640 }
1641 
1642 class FloatEnumParameterD: public FloatEnumParameter {
1643 private:
1644     std::vector<id_label> value_array;
1645 public:
1646     FloatEnumParameterD(gx_system::JsonParser& jp);
1647     ~FloatEnumParameterD();
1648 };
1649 
FloatEnumParameterD(gx_system::JsonParser & jp)1650 FloatEnumParameterD::FloatEnumParameterD(gx_system::JsonParser& jp)
1651     : FloatEnumParameter(jp), value_array() {
1652     enum_parameter_load_values(jp, value_array, &value_names);
1653 }
1654 
~FloatEnumParameterD()1655 FloatEnumParameterD::~FloatEnumParameterD() {
1656     delete value_names;
1657 }
1658 
1659 class EnumParameterD: public EnumParameter {
1660 private:
1661     std::vector<id_label> value_array;
1662 public:
1663     EnumParameterD(gx_system::JsonParser& jp);
1664     ~EnumParameterD();
1665 };
1666 
EnumParameterD(gx_system::JsonParser & jp)1667 EnumParameterD::EnumParameterD(gx_system::JsonParser& jp)
1668     : EnumParameter(jp), value_array() {
1669     enum_parameter_load_values(jp, value_array, &value_names);
1670 }
1671 
~EnumParameterD()1672 EnumParameterD::~EnumParameterD() {
1673     delete value_names;
1674 }
1675 
1676 
1677 /* BoolParameter */
1678 
serializeJSON(gx_system::JsonWriter & jw)1679 void BoolParameter::serializeJSON(gx_system::JsonWriter& jw) {
1680     jw.begin_object();
1681     jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1682     jw.write_kv("value", *value);
1683     jw.write_kv("std_value", std_value);
1684     jw.end_object();
1685 }
1686 
ParameterV(gx_system::JsonParser & jp)1687 BoolParameter::ParameterV(gx_system::JsonParser& jp)
1688     : Parameter(jp_next(jp, "Parameter")), json_value(0), value(&value_storage), std_value(0) {
1689     while (jp.peek() != gx_system::JsonParser::end_object) {
1690         jp.next(gx_system::JsonParser::value_key);
1691         if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1692         } else {
1693             gx_print_warning(
1694             "BoolParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1695             jp.skip_object();
1696         }
1697     }
1698     jp.next(gx_system::JsonParser::end_object);
1699 }
1700 
~ParameterV()1701 BoolParameter::~ParameterV() {
1702 }
1703 
set(bool val) const1704 bool BoolParameter::set(bool val) const {
1705     if (val != *value) {
1706         *value = val;
1707         changed(val);
1708         return true;
1709     }
1710     return false;
1711 }
1712 
on_off_value()1713 bool BoolParameter::on_off_value() {
1714     return *value;
1715 }
1716 
midi_set(float n,float high,float llimit,float ulimit)1717 bool BoolParameter::midi_set(float n, float high, float llimit, float ulimit) {
1718     bool v;
1719     switch (c_type) {
1720     case Switch:
1721         v = (2*n > high);
1722         break;
1723     default:
1724         assert(false);
1725         return false;
1726     }
1727     if (v != *value) {
1728         *value = v;
1729         return true;
1730     }
1731     return false;
1732 }
1733 
trigger_changed()1734 void BoolParameter::trigger_changed() {
1735     changed(*value);
1736 }
1737 
stdJSON_value()1738 void BoolParameter::stdJSON_value() {
1739     json_value = std_value;
1740 }
1741 
writeJSON(gx_system::JsonWriter & jw) const1742 void BoolParameter::writeJSON(gx_system::JsonWriter& jw) const {
1743     jw.write_kv(_id.c_str(), *value);
1744 }
1745 
readJSON_value(gx_system::JsonParser & jp)1746 void BoolParameter::readJSON_value(gx_system::JsonParser& jp) {
1747     jp.next(gx_system::JsonParser::value_number);
1748     if (jp.current_value_int() < 0 || jp.current_value_int() > 1) {
1749         range_warning(json_value, 0, 1);
1750     }
1751     json_value = jp.current_value_int();
1752 }
1753 
compareJSON_value()1754 bool BoolParameter::compareJSON_value() {
1755     return json_value == *value;
1756 }
1757 
setJSON_value()1758 void BoolParameter::setJSON_value() {
1759     set(json_value);
1760 }
1761 
1762 
1763 /* FileParameter */
1764 
serializeJSON(gx_system::JsonWriter & jw)1765 void FileParameter::serializeJSON(gx_system::JsonWriter& jw) {
1766     jw.begin_object();
1767     jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1768     jw.write_kv("value", value->get_path());
1769     jw.write_kv("std_value", std_value->get_path());
1770     jw.end_object();
1771 }
1772 
FileParameter(gx_system::JsonParser & jp)1773 FileParameter::FileParameter(gx_system::JsonParser& jp)
1774     : Parameter(jp_next(jp, "Parameter")), value(0), std_value(0), json_value(0) {
1775     while (jp.peek() != gx_system::JsonParser::end_object) {
1776         jp.next(gx_system::JsonParser::value_key);
1777         if (jp.current_value() == "value") {
1778             jp.next(gx_system::JsonParser::value_string);
1779             value = Gio::File::create_for_path(jp.current_value());
1780         } else if (jp.current_value() == "std_value") {
1781             jp.next(gx_system::JsonParser::value_string);
1782             std_value = Gio::File::create_for_path(jp.current_value());
1783         } else {
1784             gx_print_warning(
1785             "FileParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1786             jp.skip_object();
1787         }
1788     }
1789     jp.next(gx_system::JsonParser::end_object);
1790 }
1791 
set_path(const string & path)1792 void FileParameter::set_path(const string& path) {
1793     Glib::RefPtr<Gio::File> v = Gio::File::create_for_path(path);
1794     if (is_equal(v)) {
1795         return;
1796     }
1797     value = v;
1798     changed();
1799 }
1800 
set(const Glib::RefPtr<Gio::File> & val)1801 bool FileParameter::set(const Glib::RefPtr<Gio::File>& val) {
1802     if (is_equal(val)) {
1803         return false;
1804     }
1805     value = val;
1806     changed();
1807     return true;
1808 }
1809 
set_standard(const string & filename)1810 void FileParameter::set_standard(const string& filename) {
1811     std_value = Gio::File::create_for_path(filename);
1812     if (!value) {
1813         value = std_value->dup();
1814         changed();
1815     }
1816 }
1817 
stdJSON_value()1818 void FileParameter::stdJSON_value() {
1819     json_value = std_value->dup();
1820     changed();
1821 }
1822 
on_off_value()1823 bool FileParameter::on_off_value() {
1824     return bool(value);
1825 }
1826 
writeJSON(gx_system::JsonWriter & jw) const1827 void FileParameter::writeJSON(gx_system::JsonWriter& jw) const {
1828     jw.write_kv(_id.c_str(), get_path());
1829 }
1830 
readJSON_value(gx_system::JsonParser & jp)1831 void FileParameter::readJSON_value(gx_system::JsonParser& jp) {
1832     jp.next(gx_system::JsonParser::value_string);
1833     json_value = Gio::File::create_for_path(jp.current_value());
1834 }
1835 
compareJSON_value()1836 bool FileParameter::compareJSON_value() {
1837     return json_value->get_path() == value->get_path(); //FIXME
1838 }
1839 
setJSON_value()1840 void FileParameter::setJSON_value() {
1841     set(json_value);
1842 }
1843 
get_file_id(const Glib::RefPtr<Gio::File> & f)1844 static string get_file_id(const Glib::RefPtr<Gio::File>& f) {
1845     return f->query_info(G_FILE_ATTRIBUTE_ID_FILE)->get_attribute_string(G_FILE_ATTRIBUTE_ID_FILE);
1846 }
1847 
is_equal(const Glib::RefPtr<Gio::File> & v) const1848 bool FileParameter::is_equal(const Glib::RefPtr<Gio::File>& v) const {
1849     string id, id2;
1850     try {
1851         id = get_file_id(value);
1852     } catch(Gio::Error& ex) {
1853         return false; // FIXME check type of exception
1854     }
1855     try {
1856         id2 = get_file_id(v);
1857     } catch(Gio::Error& ex) {
1858         return false; // FIXME check type of exception
1859     }
1860     return id == id2;
1861 }
1862 
get_path() const1863 string FileParameter::get_path() const {
1864     return value->get_path();
1865 }
1866 
get_directory_path() const1867 string FileParameter::get_directory_path() const {
1868     return value->get_parent()->get_path();
1869 }
1870 
get_parse_name() const1871 string FileParameter::get_parse_name() const {
1872     return value->get_parse_name();
1873 }
1874 
get_display_name() const1875 string FileParameter::get_display_name() const {
1876     return value->query_info(G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)->get_display_name();
1877 }
1878 
copy(const string & destination) const1879 void FileParameter::copy(const string& destination) const {
1880     value->copy(Gio::File::create_for_path(destination));
1881 }
1882 
1883 
1884 /* StringParameter */
1885 
serializeJSON(gx_system::JsonWriter & jw)1886 void StringParameter::serializeJSON(gx_system::JsonWriter& jw) {
1887     jw.begin_object();
1888     jw.write_key("Parameter"); Parameter::serializeJSON(jw);
1889     jw.write_kv("value", *value);
1890     jw.write_kv("std_value", std_value);
1891     jw.end_object();
1892 }
1893 
ParameterV(gx_system::JsonParser & jp)1894 StringParameter::ParameterV(gx_system::JsonParser& jp)
1895     : Parameter(jp_next(jp, "Parameter")), json_value(""), value(&value_storage), std_value("") {
1896     while (jp.peek() != gx_system::JsonParser::end_object) {
1897         jp.next(gx_system::JsonParser::value_key);
1898         if (jp.read_kv("value", *value) || jp.read_kv("std_value", std_value)) {
1899         } else {
1900             gx_print_warning(
1901             "StringParameter", Glib::ustring::compose("%1: unknown key: %2", _id, jp.current_value()));
1902             jp.skip_object();
1903         }
1904     }
1905     jp.next(gx_system::JsonParser::end_object);
1906 }
1907 
~ParameterV()1908 StringParameter::~ParameterV() {
1909 }
1910 
set(const Glib::ustring & val) const1911 bool StringParameter::set(const Glib::ustring& val) const {
1912     if (val != *value) {
1913         *value = val;
1914         changed(*value);
1915         return true;
1916     }
1917     return false;
1918 }
1919 
on_off_value()1920 bool StringParameter::on_off_value() {
1921     return !value->empty();
1922 }
1923 
stdJSON_value()1924 void StringParameter::stdJSON_value() {
1925     json_value = std_value;
1926 }
1927 
writeJSON(gx_system::JsonWriter & jw) const1928 void StringParameter::writeJSON(gx_system::JsonWriter& jw) const {
1929     jw.write_kv(_id.c_str(), *value);
1930 }
1931 
readJSON_value(gx_system::JsonParser & jp)1932 void StringParameter::readJSON_value(gx_system::JsonParser& jp) {
1933     jp.next(gx_system::JsonParser::value_string);
1934     json_value = jp.current_value();
1935 }
1936 
compareJSON_value()1937 bool StringParameter::compareJSON_value() {
1938     return json_value == *value;
1939 }
1940 
setJSON_value()1941 void StringParameter::setJSON_value() {
1942     set(json_value);
1943 }
1944 
1945 /****************************************************************
1946  ** Parameter Map
1947  */
1948 
ParamMap()1949 ParamMap::ParamMap()
1950     : id_map(),
1951       replace_mode(false) {
1952 }
1953 
~ParamMap()1954 ParamMap::~ParamMap() {
1955     for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1956         delete i->second;
1957     }
1958 }
1959 
writeJSON_one(gx_system::JsonWriter & jw,Parameter * p)1960 void ParamMap::writeJSON_one(gx_system::JsonWriter& jw, Parameter *p) {
1961     if (p->isFloat()) {
1962         if (p->getControlType() == Parameter::Enum) {
1963             jw.write("FloatEnum");
1964         } else {
1965             jw.write("Float");
1966         }
1967     } else if (p->isInt()) {
1968         if (p->getControlType() == Parameter::Enum) {
1969             jw.write("Enum");
1970         } else {
1971             jw.write("Int");
1972         }
1973     } else if (p->isBool()) {
1974         jw.write("Bool");
1975     } else if (p->isFile()) {
1976         jw.write("File");
1977     } else if (p->isString()) {
1978         jw.write("String");
1979     } else if (dynamic_cast<JConvParameter*>(p) != 0) {
1980         jw.write("JConv");
1981     } else if (dynamic_cast<SeqParameter*>(p) != 0) {
1982         jw.write("Seq");
1983 #ifndef NEW_LADSPA
1984     } else if (dynamic_cast<OscParameter*>(p) != 0) {
1985         jw.write("Osc");
1986 #endif
1987     } else {
1988 #ifndef NDEBUG
1989         cerr << "skipping " << p->id() << endl;
1990 #endif
1991         return;
1992     }
1993     p->serializeJSON(jw);
1994 }
1995 
writeJSON(gx_system::JsonWriter & jw)1996 void ParamMap::writeJSON(gx_system::JsonWriter& jw) {
1997     jw.begin_array();
1998     for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
1999         writeJSON_one(jw, i->second);
2000     }
2001     jw.end_array();
2002 }
2003 
readJSON_one(gx_system::JsonParser & jp)2004 Parameter *ParamMap::readJSON_one(gx_system::JsonParser& jp) {
2005     jp.next(gx_system::JsonParser::value_string);
2006     if (jp.current_value() == "FloatEnum") {
2007         return insert(new FloatEnumParameterD(jp));
2008     } else if (jp.current_value() == "Float") {
2009         return insert(new FloatParameter(jp));
2010     } else if (jp.current_value() == "Enum") {
2011         return insert(new EnumParameterD(jp));
2012     } else if (jp.current_value() == "Int") {
2013         return insert(new IntParameter(jp));
2014     } else if (jp.current_value() == "Bool") {
2015         return insert(new BoolParameter(jp));
2016     } else if (jp.current_value() == "File") {
2017         return insert(new FileParameter(jp));
2018     } else if (jp.current_value() == "String") {
2019         return insert(new StringParameter(jp));
2020     } else if (jp.current_value() == "JConv") {
2021         return insert(new JConvParameter(jp));
2022     } else if (jp.current_value() == "Seq") {
2023         return insert(new SeqParameter(jp));
2024 #ifndef NEW_LADSPA
2025     } else if (jp.current_value() == "Osc") {
2026         return insert(new OscParameter(jp));
2027 #endif
2028     } else {
2029         gx_print_warning(
2030             "ParamMap", Glib::ustring::compose("unknown parameter type: %1", jp.current_value()));
2031         jp.skip_object();
2032         return 0;
2033     }
2034 }
2035 
readJSON(gx_system::JsonParser & jp)2036 void ParamMap::readJSON(gx_system::JsonParser& jp) {
2037     jp.next(gx_system::JsonParser::begin_array);
2038     while (jp.peek() != gx_system::JsonParser::end_array) {
2039         readJSON_one(jp);
2040     }
2041     jp.next(gx_system::JsonParser::end_array);
2042 }
2043 
2044 #ifndef NDEBUG
unique_id(Parameter * param)2045 void ParamMap::unique_id(Parameter* param) {
2046     if (id_map.find(param->id()) != id_map.end()) {
2047         gx_print_error("Debug Check", "id registered twice: " + param->id());
2048     }
2049 }
2050 
check_id(const string & id)2051 void ParamMap::check_id(const string& id) {
2052     if (!hasId(id)) {
2053         cerr << "string-id not found: " << id << endl;
2054     }
2055 }
2056 
check_p(const char * p)2057 void ParamMap::check_p(const char *p) {
2058     if (!hasId(p)) {
2059         cerr << "char-id not found: " << p << endl;
2060     }
2061 }
2062 
dump(const string & fmt)2063 void ParamMap::dump(const string& fmt) {
2064     gx_system::JsonWriter *p = 0;
2065     gx_system::JsonWriter jw;
2066     if (fmt == "json") {
2067         jw.set_stream(&cout);
2068         p = &jw;
2069         jw.begin_array();
2070         jw.newline();
2071     } else {
2072         printf("parameter map dump\n");
2073     }
2074     for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
2075         i->second->dump(p);
2076     }
2077     if (p) {
2078         jw.end_array();
2079         jw.close();
2080     } else {
2081         printf("---------------------\n");
2082     }
2083 }
2084 
dump(gx_system::JsonWriter * jw)2085 void Parameter::dump(gx_system::JsonWriter *jw) {
2086     if (jw) {
2087         jw->begin_array();
2088         jw->write(id());
2089         switch (c_type) {
2090         case None: jw->write("None"); break;
2091         case Continuous: jw->write("Cont"); break;
2092         case Switch: jw->write("Swth"); break;
2093         case Enum: jw->write("Enum"); break;
2094         default: assert(false);
2095         }
2096         if (save_in_preset) {
2097             jw->write("preset");
2098         }
2099         if (controllable) {
2100             jw->write("control");
2101         }
2102         jw->write(l_group());
2103         jw->write(l_name());
2104         /*
2105         switch (v_type) {
2106         case tp_float:  jw->write("f"); jw->write(getFloat().get_value());     break;
2107         case tp_int:    jw->write("i"); jw->write(getInt().get_value());       break;
2108         case tp_bool:   jw->write("b"); jw->write(getBool().get_value());      break;
2109         case tp_switch: jw->write("s"); jw->write(getSwitch().get());          break;
2110         case tp_file:   jw->write("F"); jw->write(getFile().get_parse_name()); break;
2111         case tp_string: jw->write("S"); jw->write(getString().get_value());    break;
2112         case tp_special: jw->write("G"); break;
2113         default: assert(false);
2114         }
2115         */
2116         jw->write(getLowerAsFloat());
2117         jw->write(getUpperAsFloat());
2118         jw->write(getStepAsFloat());
2119         const value_pair *vn = getValueNames();
2120         if (vn) {
2121             jw->begin_array();
2122             for (int n = 0; ; ++n) {
2123             if (!vn[n].value_id) {
2124                 break;
2125             }
2126             jw->begin_array();
2127             jw->write(vn[n].value_id);
2128             jw->write(vn[n].value_label ? vn[n].value_label : vn[n].value_id);
2129             jw->end_array();
2130             }
2131             jw->end_array();
2132         }
2133         jw->end_array();
2134         jw->newline();
2135     } else {
2136         printf("P: %s vt=%d ct=%d c=%d\n", _id.c_str(), v_type, c_type, controllable);
2137     }
2138 }
2139 #endif
2140 
insert(Parameter * param)2141 Parameter *ParamMap::insert(Parameter* param) {
2142     if (replace_mode) {
2143         map<string, Parameter*>::iterator ii = id_map.find(param->id());
2144         if (ii != id_map.end()) {
2145             Parameter *p = ii->second;
2146             insert_remove(p,false);
2147             id_map.erase(ii);
2148             delete p;
2149         }
2150     }
2151     debug_check(unique_id, param);
2152     id_map.insert(pair<string, Parameter*>(param->id(), param));
2153     insert_remove(param,true);
2154     return param;
2155 }
2156 
unregister(Parameter * p)2157 void ParamMap::unregister(Parameter *p) {
2158     if (!p) {
2159         return;
2160     }
2161     insert_remove(p, false);
2162     id_map.erase(p->id());
2163     delete p;
2164 }
2165 
unregister(const string & id)2166 void ParamMap::unregister(const string& id) {
2167     if (!hasId(id)) {
2168         return;
2169     }
2170     unregister(&(*this)[id]);
2171 }
2172 
set_init_values()2173 void ParamMap::set_init_values() {
2174     for (iterator i = id_map.begin(); i != id_map.end(); ++i) {
2175         i->second->stdJSON_value();
2176         i->second->setJSON_value();
2177     }
2178 }
2179 
compare_groups(const std::string & id,const char ** groups)2180 static inline bool compare_groups(const std::string& id, const char **groups) {
2181     if (!groups) {
2182         return false;
2183     }
2184     for (const char **g = groups; *g; g += 2) {
2185         const char *p = *g;
2186         if ((*p) != '.') {
2187             continue;
2188         }
2189         p++;
2190         int n = strlen(p);
2191         if (strncmp(id.c_str(), p, n) == 0 && id[n] == '.') {
2192             return true;
2193         }
2194     }
2195     return false;
2196 }
2197 
unit_has_std_values(const PluginDef * pdef) const2198 bool ParamMap::unit_has_std_values(const PluginDef *pdef) const {
2199     std::string group_id(pdef->id);
2200     group_id += ".";
2201     std::string on_off = group_id + "on_off";
2202     std::string pp = group_id + "pp";
2203     std::string position = group_id + "position";
2204     for (iterator i = begin(); i != end(); ++i) {
2205         if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
2206             if (i->second->isInPreset() && !i->second->isOutput()) {
2207             if (i->first != on_off && i->first != pp && i->first != position) {
2208                 i->second->stdJSON_value();
2209                 if (!i->second->compareJSON_value()) {
2210                 return false;
2211                 break;
2212                 }
2213             }
2214             }
2215         }
2216     }
2217     return true;
2218 }
2219 
2220 // reset all parameters to default settings
reset_unit(const PluginDef * pdef) const2221 void ParamMap::reset_unit(const PluginDef *pdef) const {
2222     std::string group_id(pdef->id);
2223     group_id += ".";
2224     std::string on_off = group_id + "on_off";
2225     std::string pp = group_id + "pp";
2226     std::string position = group_id + "position";
2227     for (iterator i = begin(); i != end(); ++i) {
2228         if (i->first.compare(0, group_id.size(), group_id) == 0 || compare_groups(i->first, pdef->groups)) {
2229             if (i->second->isInPreset()) {
2230                 if (i->first != on_off && i->first != pp && i->first != position) {
2231                     i->second->stdJSON_value();
2232                     i->second->setJSON_value();
2233                 }
2234             }
2235         }
2236     }
2237 }
2238 
2239 } // namespace gx_gui
2240