1 /*
2 ** Surge Synthesizer is Free and Open Source Software
3 **
4 ** Surge is made available under the Gnu General Public License, v3.0
5 ** https://www.gnu.org/licenses/gpl-3.0.en.html
6 **
7 ** Copyright 2004-2020 by various individuals as described by the Git transaction log
8 **
9 ** All source at: https://github.com/surge-synthesizer/surge.git
10 **
11 ** Surge was a commercial product from 2004-2018, with Copyright and ownership
12 ** in that period held by Claes Johanson at Vember Audio. Claes made Surge
13 ** open source in September 2018.
14 */
15 
16 #include "SurgeStorage.h"
17 #include "Parameter.h"
18 #include "DspUtilities.h"
19 #include <cstring>
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23 #include <cstdlib>
24 #include <algorithm>
25 #include <cctype>
26 #include <utility>
27 #include <UserDefaults.h>
28 #include "DebugHelpers.h"
29 #include "StringOps.h"
30 
Parameter()31 Parameter::Parameter()
32 {
33     val.i = 0;
34     posx = 0;
35     posy = 0;
36     posy_offset = 0;
37     storage = nullptr;
38 }
39 
40 Parameter::~Parameter() = default;
41 
get_prefix(char * txt,ControlGroup ctrlgroup,int ctrlgroup_entry,int scene)42 void get_prefix(char *txt, ControlGroup ctrlgroup, int ctrlgroup_entry, int scene)
43 {
44 #define PREFIX_SIZE 16
45     char prefix[PREFIX_SIZE];
46     switch (ctrlgroup)
47     {
48     case cg_OSC:
49         snprintf(prefix, PREFIX_SIZE, "osc%i_", ctrlgroup_entry + 1);
50         break;
51     case cg_FILTER:
52         snprintf(prefix, PREFIX_SIZE, "filter%i_", ctrlgroup_entry + 1);
53         break;
54     case cg_ENV:
55         snprintf(prefix, PREFIX_SIZE, "env%i_", ctrlgroup_entry + 1);
56         break;
57     /*case 6:
58             snprintf(prefix, PREFIX_SIZE, "ms%i_",ctrlgroup_entry+1);
59             break;*/
60     case cg_FX:
61         snprintf(prefix, PREFIX_SIZE, "fx%i_", ctrlgroup_entry + 1);
62         break;
63     default:
64         prefix[0] = '\0';
65         break;
66     };
67     if (scene == 2)
68         snprintf(txt, TXT_SIZE, "b_%s", prefix);
69     else if (scene == 1)
70         snprintf(txt, TXT_SIZE, "a_%s", prefix);
71     else
72         snprintf(txt, TXT_SIZE, "%s", prefix);
73 }
74 
create_fullname(const char * dn,char * fn,ControlGroup ctrlgroup,int ctrlgroup_entry,const char * lfoPrefixOverride)75 void Parameter::create_fullname(const char *dn, char *fn, ControlGroup ctrlgroup,
76                                 int ctrlgroup_entry, const char *lfoPrefixOverride)
77 {
78     char prefix[PREFIX_SIZE];
79     bool useprefix = true;
80     switch (ctrlgroup)
81     {
82     case cg_OSC:
83         snprintf(prefix, PREFIX_SIZE, "Osc %i", ctrlgroup_entry + 1);
84         break;
85     case cg_FILTER:
86         snprintf(prefix, PREFIX_SIZE, "Filter %i", ctrlgroup_entry + 1);
87         break;
88     case cg_ENV:
89         if (ctrlgroup_entry)
90             snprintf(prefix, PREFIX_SIZE, "Filter EG");
91         else
92             snprintf(prefix, PREFIX_SIZE, "Amp EG");
93         break;
94     case cg_LFO:
95     {
96         int a = ctrlgroup_entry + 1 - ms_lfo1;
97         if (lfoPrefixOverride)
98         {
99             strxcpy(prefix, lfoPrefixOverride, PREFIX_SIZE);
100         }
101         else
102         {
103             if (a > 6)
104                 snprintf(prefix, PREFIX_SIZE, "Scene LFO %i", a - 6);
105             else
106                 snprintf(prefix, PREFIX_SIZE, "LFO %i", a);
107         }
108     }
109     break;
110     case cg_FX:
111         switch (ctrlgroup_entry)
112         {
113         case 0:
114             snprintf(prefix, PREFIX_SIZE, "FX A1");
115             break;
116         case 1:
117             snprintf(prefix, PREFIX_SIZE, "FX A2");
118             break;
119         case 2:
120             snprintf(prefix, PREFIX_SIZE, "FX B1");
121             break;
122         case 3:
123             snprintf(prefix, PREFIX_SIZE, "FX B2");
124             break;
125         case 4:
126             snprintf(prefix, PREFIX_SIZE, "FX S1");
127             break;
128         case 5:
129             snprintf(prefix, PREFIX_SIZE, "FX S2");
130             break;
131         case 6:
132             snprintf(prefix, PREFIX_SIZE, "FX M1");
133             break;
134         case 7:
135             snprintf(prefix, PREFIX_SIZE, "FX M2");
136             break;
137         default:
138             snprintf(prefix, PREFIX_SIZE, "FXERR");
139             break;
140         }
141         break;
142     default:
143         prefix[0] = '\0';
144         useprefix = false;
145         break;
146     };
147 
148     // note for future devs: code here used to make a buffer of 256 bytes, write into it, then
149     // incorrectly truncate to NAMECHARS (which was 64 bytes) leading to unterminated strings.
150     // now tfn is also NAMECHARS and unterminated strings aren't possible. But if some behaviour
151     // changes -- this comment exists.
152     char tfn[NAMECHARS];
153     if (useprefix)
154         snprintf(tfn, NAMECHARS, "%s %s", prefix, dn);
155     else
156         snprintf(tfn, NAMECHARS, "%s", dn);
157     strxcpy(fn, tfn, NAMECHARS);
158 }
159 
set_name(const char * n)160 void Parameter::set_name(const char *n)
161 {
162     strxcpy(dispname, n, NAMECHARS);
163     create_fullname(dispname, fullname, ctrlgroup, ctrlgroup_entry);
164     parameterNameUpdated = true;
165 }
166 
assign(ParameterIDCounter::promise_t idp,int pid,const char * name,const char * dispname,int ctrltype,const Surge::Skin::Connector & c,int scene,ControlGroup ctrlgroup,int ctrlgroup_entry,bool modulateable,int ctrlstyle,bool defaultDeactivation)167 Parameter *Parameter::assign(ParameterIDCounter::promise_t idp, int pid, const char *name,
168                              const char *dispname, int ctrltype,
169 
170                              const Surge::Skin::Connector &c,
171 
172                              int scene, ControlGroup ctrlgroup, int ctrlgroup_entry,
173                              bool modulateable, int ctrlstyle, bool defaultDeactivation)
174 {
175     assert(c.payload);
176     auto r =
177         assign(idp, pid, name, dispname, ctrltype, c.payload->id, c.payload->posx, c.payload->posy,
178                scene, ctrlgroup, ctrlgroup_entry, modulateable, ctrlstyle, defaultDeactivation);
179     r->hasSkinConnector = true;
180     return r;
181 }
assign(ParameterIDCounter::promise_t idp,int pid,const char * name,const char * dispname,int ctrltype,std::string ui_identifier,int posx,int posy,int scene,ControlGroup ctrlgroup,int ctrlgroup_entry,bool modulateable,int ctrlstyle,bool defaultDeactivation)182 Parameter *Parameter::assign(ParameterIDCounter::promise_t idp, int pid, const char *name,
183                              const char *dispname, int ctrltype,
184 
185                              std::string ui_identifier, int posx, int posy, int scene,
186                              ControlGroup ctrlgroup, int ctrlgroup_entry, bool modulateable,
187                              int ctrlstyle, bool defaultDeactivation)
188 {
189     this->id_promise = idp.get();
190     this->id = -1;
191     this->param_id_in_scene = pid;
192     this->ctrlgroup = ctrlgroup;
193     this->ctrlgroup_entry = ctrlgroup_entry;
194     this->posx = posx;
195     this->posy = posy;
196     this->modulateable = modulateable;
197     this->scene = scene;
198     this->ctrlstyle = ctrlstyle;
199     this->storage = nullptr;
200     strxcpy(this->ui_identifier, ui_identifier.c_str(), NAMECHARS);
201 
202     strxcpy(this->name, name, NAMECHARS);
203     set_name(dispname);
204     char prefix[PREFIX_SIZE];
205     get_prefix(prefix, ctrlgroup, ctrlgroup_entry, scene);
206     snprintf(name_storage, NAMECHARS, "%s%s", prefix, name);
207     posy_offset = 0;
208     if (scene)
209         per_voice_processing = true;
210     else
211         per_voice_processing = false;
212     clear_flags();
213     this->deactivated = defaultDeactivation;
214     midictrl = -1;
215 
216     set_type(ctrltype);
217     if (valtype == vt_float)
218         val.f = val_default.f;
219 
220     bound_value();
221     return this;
222 }
223 
clear_flags()224 void Parameter::clear_flags()
225 {
226     temposync = false;
227     extend_range = false;
228     absolute = false;
229     deactivated = true; // CHOICE: if you are a deactivatble parameter make it so you are by default
230     porta_constrate = false;
231     porta_gliss = false;
232     porta_retrigger = false;
233     porta_curve = porta_lin;
234 }
235 
can_temposync()236 bool Parameter::can_temposync()
237 {
238     switch (ctrltype)
239     {
240     case ct_portatime:
241     case ct_lforate:
242     case ct_lforate_deactivatable:
243     case ct_envtime:
244     case ct_envtime_linkable_delay:
245     case ct_envtime_lfodecay:
246     case ct_reverbpredelaytime:
247         return true;
248     }
249     return false;
250 }
251 
can_extend_range()252 bool Parameter::can_extend_range()
253 {
254     switch (ctrltype)
255     {
256     case ct_pitch_semi7bp:
257     case ct_pitch_semi7bp_absolutable:
258     case ct_freq_reson_band1:
259     case ct_freq_reson_band2:
260     case ct_freq_reson_band3:
261     case ct_freq_shift:
262     case ct_decibel_extendable:
263     case ct_decibel_narrow_extendable:
264     case ct_decibel_narrow_short_extendable:
265     case ct_oscspread:
266     case ct_oscspread_bipolar:
267     case ct_osc_feedback:
268     case ct_osc_feedback_negative:
269     case ct_lfoamplitude:
270     case ct_fmratio:
271     case ct_reson_res_extendable:
272     case ct_freq_audible_with_tunability:
273     case ct_freq_audible_with_very_low_lowerbound:
274     case ct_percent_oscdrift:
275     case ct_twist_aux_mix:
276         return true;
277     }
278     return false;
279 }
280 
can_be_absolute()281 bool Parameter::can_be_absolute()
282 {
283     switch (ctrltype)
284     {
285     case ct_oscspread:
286     case ct_oscspread_bipolar:
287     case ct_pitch_semi7bp_absolutable:
288     case ct_fmratio:
289         return true;
290     }
291     return false;
292 }
293 
can_deactivate()294 bool Parameter::can_deactivate()
295 {
296     switch (ctrltype)
297     {
298     case ct_percent_deactivatable:
299     case ct_freq_hpf:
300     case ct_freq_audible_deactivatable:
301     case ct_lforate_deactivatable:
302     case ct_rotarydrive:
303     case ct_airwindows_fx:
304     case ct_decibel_deactivatable:
305     case ct_decibel_narrow_deactivatable:
306     case ct_decibel_extra_narrow_deactivatable:
307     case ct_envtime_linkable_delay:
308     case ct_tape_speed:
309         return true;
310     }
311     return false;
312 }
313 
has_portaoptions()314 bool Parameter::has_portaoptions()
315 {
316     if (ctrltype == ct_portatime)
317         return true;
318     else
319         return false;
320 }
321 
has_deformoptions()322 bool Parameter::has_deformoptions()
323 {
324     switch (ctrltype)
325     {
326     case ct_lfodeform:
327     case ct_modern_trimix:
328     case ct_alias_mask:
329         return true;
330     default:
331         break;
332     }
333 
334     return false;
335 }
336 
is_bipolar()337 bool Parameter::is_bipolar()
338 {
339     if (dynamicBipolar != nullptr)
340     {
341         auto res = dynamicBipolar->getValue(this);
342         return res;
343     }
344 
345     bool res = false;
346     switch (ctrltype)
347     {
348     case ct_decibel:
349     case ct_decibel_deactivatable:
350     case ct_decibel_narrow:
351     case ct_decibel_narrow_deactivatable:
352     case ct_decibel_narrow_extendable:
353     case ct_decibel_extra_narrow_deactivatable:
354     case ct_decibel_narrow_short_extendable:
355     case ct_decibel_extra_narrow:
356     case ct_decibel_extendable:
357     case ct_freq_mod:
358     case ct_percent_bipolar:
359     case ct_percent_bipolar_stereo:
360     case ct_percent_bipolar_w_dynamic_unipolar_formatting:
361     case ct_twist_aux_mix:
362     case ct_freq_shift:
363     case ct_osc_feedback_negative:
364     case ct_lfodeform:
365     case ct_airwindows_param_bipolar:
366     case ct_pitch:
367     case ct_pitch4oct:
368     case ct_modern_trimix:
369     case ct_oscspread_bipolar:
370         res = true;
371         break;
372     case ct_lfoamplitude:
373         if (extend_range)
374             res = true;
375         break;
376     case ct_fmratio:
377     {
378         if (extend_range && !absolute)
379             res = true;
380     }
381     break;
382     default:
383         res = false;
384     }
385     return res;
386 }
387 
is_discrete_selection()388 bool Parameter::is_discrete_selection()
389 {
390     switch (ctrltype)
391     {
392     case ct_sinefmlegacy:
393     case ct_wt2window:
394     case ct_airwindows_fx:
395     case ct_flangermode:
396     case ct_fxlfowave:
397     case ct_distortion_waveshape:
398     case ct_reson_mode:
399     case ct_vocoder_bandcount:
400     case ct_nimbusmode:
401     case ct_nimbusquality:
402     case ct_stringosc_excitation_model:
403     case ct_twist_engine:
404     case ct_ensemble_stages:
405     case ct_alias_wave:
406         return true;
407     default:
408         break;
409     }
410 
411     return false;
412 }
413 
is_nonlocal_on_change()414 bool Parameter::is_nonlocal_on_change()
415 {
416     switch (ctrltype)
417     {
418     case ct_twist_engine:
419     case ct_phaser_stages:
420     case ct_nimbusmode:
421         return true;
422     default:
423         break;
424     }
425     return false;
426 }
427 
appears_deactivated()428 bool Parameter::appears_deactivated()
429 {
430     if (dynamicDeactivation)
431         return dynamicDeactivation->getValue(this);
432 
433     if (can_deactivate())
434         return deactivated;
435 
436     return false;
437 }
438 
get_primary_deactivation_driver()439 Parameter *Parameter::get_primary_deactivation_driver()
440 {
441     if (dynamicDeactivation)
442         return dynamicDeactivation->getPrimaryDeactivationDriver(this);
443     return nullptr;
444 }
445 
set_user_data(ParamUserData * ud)446 void Parameter::set_user_data(ParamUserData *ud)
447 {
448     switch (ctrltype)
449     {
450     case ct_countedset_percent:
451         if (dynamic_cast<CountedSetUserData *>(ud))
452         {
453             user_data = ud;
454         }
455         else
456         {
457             user_data = nullptr;
458         }
459         break;
460     case ct_airwindows_fx:
461     case ct_filtertype:
462     case ct_alias_wave:
463         if (dynamic_cast<ParameterDiscreteIndexRemapper *>(ud))
464         {
465             user_data = ud;
466         }
467         else
468         {
469             user_data = nullptr;
470         }
471         break;
472     case ct_airwindows_param:
473     case ct_airwindows_param_bipolar:
474     case ct_airwindows_param_integral:
475         if (dynamic_cast<ParameterExternalFormatter *>(ud))
476         {
477             user_data = ud;
478         }
479         else
480         {
481             user_data = nullptr;
482         }
483         break;
484     default:
485         std::cout << "Setting userdata on a non-supporting param ignored" << std::endl;
486         user_data = nullptr;
487         break;
488     }
489 }
490 
set_type(int ctrltype)491 void Parameter::set_type(int ctrltype)
492 {
493     this->ctrltype = ctrltype;
494     posy_offset = 0;
495     moverate = 1.f;
496 
497     affect_other_parameters = false;
498     user_data = nullptr;
499     dynamicName = nullptr;
500     dynamicBipolar = nullptr;
501     dynamicDeactivation = nullptr;
502 
503     /*
504     ** Note we now have two ctrltype switches. This one sets ranges
505     ** and, grouped below, we set display info
506     */
507     switch (ctrltype)
508     {
509     case ct_pitch:
510         valtype = vt_float;
511         val_min.f = -60;
512         val_max.f = 60;
513         val_default.f = 0;
514         break;
515     case ct_pitch4oct:
516         valtype = vt_float;
517         val_min.f = -48;
518         val_max.f = 48;
519         val_default.f = 0;
520         break;
521     case ct_syncpitch:
522         valtype = vt_float;
523         val_min.f = 0;
524         val_max.f = 60;
525         val_default.f = 0;
526         break;
527     case ct_fmratio:
528         valtype = vt_float;
529         val_min.f = 0;
530         val_max.f = 32;
531         val_default.f = 1;
532         moverate = 0.5f;
533         break;
534     case ct_fmratio_int:
535         valtype = vt_int;
536         val_min.i = 1;
537         val_max.i = 32;
538         val_default.i = 1;
539         break;
540     case ct_pbdepth:
541         valtype = vt_int;
542         val_min.i = 0;
543         val_max.i = 24;
544         val_default.i = 2;
545         break;
546     case ct_pitch_semi7bp:
547     case ct_pitch_semi7bp_absolutable:
548         valtype = vt_float;
549         val_min.f = -7;
550         val_max.f = 7;
551         moverate = 0.5f;
552         val_default.f = 0;
553         break;
554     case ct_freq_audible:
555     case ct_freq_audible_deactivatable:
556     case ct_freq_audible_with_tunability:
557         valtype = vt_float;
558         val_min.f = -60;
559         val_max.f = 70;
560         val_default.f = 3;
561         break;
562     case ct_freq_audible_with_very_low_lowerbound:
563         valtype = vt_float;
564         val_min.f = -117.3763; // 0.5 Hz
565         val_max.f = 70;
566         val_default.f = 3;
567         break;
568     case ct_freq_hpf:
569         valtype = vt_float;
570         val_min.f = -72;
571         val_max.f = 15;
572         val_default.f = -72;
573         break;
574     case ct_freq_reson_band1:
575         valtype = vt_float;
576         val_min.f = -34.4936f;     // 60 Hz
577         val_max.f = -6.6305f;      // 300 Hz
578         val_default.f = -18.6305f; // 150 Hz
579         break;
580     case ct_freq_reson_band2:
581         valtype = vt_float;
582         val_min.f = -6.6305f;      // 300 Hz
583         val_max.f = 21.23265f;     // 1500 Hz
584         val_default.f = 8.038216f; // 700 Hz
585         break;
586     case ct_freq_reson_band3:
587         valtype = vt_float;
588         val_min.f = 21.23265f;     // 1500 Hz
589         val_max.f = 49.09578;      // 7500 Hz
590         val_default.f = 35.90135f; // 3500 Hz
591         break;
592     case ct_freq_vocoder_low:
593         valtype = vt_float;
594         val_min.f = -36; // 55 Hz
595         val_max.f = 36;  // 3520 Hz
596         val_default.f = -3;
597         break;
598     case ct_freq_vocoder_high:
599         valtype = vt_float;
600         val_min.f = 0;      // 440 Hz
601         val_max.f = 60;     // ~14.3 kHz
602         val_default.f = 49; // ~7.4 kHz
603         break;
604     case ct_freq_mod:
605         valtype = vt_float;
606         val_min.f = -96;
607         val_max.f = 96;
608         val_default.f = 0;
609         moverate = 0.5f;
610         break;
611     case ct_freq_shift:
612         valtype = vt_float;
613         val_min.f = -10;
614         val_max.f = 10;
615         val_default.f = 0;
616         break;
617     case ct_freq_ringmod:
618         valtype = vt_float;
619         val_min.f = 0;
620         val_max.f = 127;
621         val_default.f = 60;
622         break;
623     case ct_bandwidth:
624         valtype = vt_float;
625         val_min.f = 0;
626         val_max.f = 5;
627         val_default.f = 1;
628         break;
629     case ct_decibel:
630     case ct_decibel_extendable:
631     case ct_decibel_deactivatable:
632         valtype = vt_float;
633         val_min.f = -48;
634         val_max.f = 48;
635         val_default.f = 0;
636         break;
637     case ct_decibel_attenuation:
638     case ct_decibel_attenuation_clipper:
639         valtype = vt_float;
640         val_min.f = -48;
641         val_max.f = 0;
642         val_default.f = 0;
643         break;
644     case ct_decibel_attenuation_large:
645         valtype = vt_float;
646         val_min.f = -96;
647         val_max.f = 0;
648         val_default.f = 0;
649         break;
650     case ct_decibel_fmdepth:
651         valtype = vt_float;
652         val_min.f = -48;
653         val_max.f = 24;
654         val_default.f = 0;
655         break;
656     case ct_decibel_narrow:
657     case ct_decibel_narrow_deactivatable:
658     case ct_decibel_narrow_extendable:
659     case ct_decibel_narrow_short_extendable:
660         valtype = vt_float;
661         val_min.f = -24;
662         val_max.f = 24;
663         val_default.f = 0;
664         break;
665     case ct_decibel_extra_narrow:
666     case ct_decibel_extra_narrow_deactivatable:
667         valtype = vt_float;
668         val_min.f = -12;
669         val_max.f = 12;
670         val_default.f = 0;
671         break;
672     case ct_portatime:
673         valtype = vt_float;
674         val_min.f = -8;
675         val_max.f = 2;
676         val_default.f = -8;
677         break;
678     case ct_envtime:
679     case ct_envtime_linkable_delay:
680     case ct_envtime_lfodecay:
681         valtype = vt_float;
682         val_min.f = -8;
683         val_max.f = 5;
684         val_default.f = 0;
685         break;
686     case ct_delaymodtime:
687     case ct_chorusmodtime:
688         valtype = vt_float;
689         val_min.f = -11;
690         val_max.f = -3;
691         val_default.f = -6;
692         break;
693     case ct_reverbtime:
694         valtype = vt_float;
695         val_min.f = -4;
696         val_max.f = 6;
697         val_default.f = 1;
698         break;
699     case ct_reverbpredelaytime:
700         valtype = vt_float;
701         val_min.f = -8;
702         val_max.f = 1;
703         val_default.f = -2;
704         break;
705     case ct_lforate:
706     case ct_lforate_deactivatable:
707         valtype = vt_float;
708         val_min.f = -7;
709         val_max.f = 9;
710         val_default.f = 0;
711         moverate = 0.33f;
712         break;
713     case ct_ensemble_lforate:
714         valtype = vt_float;
715         val_min.f = log2(0.01f);
716         val_max.f = log2(20.f);
717         val_default.f = 0;
718         moverate = 0.5f;
719         break;
720     case ct_ensemble_clockrate:
721         valtype = vt_float;
722         val_min.f = 1.5f;
723         val_max.f = 100.f;
724         val_default.f = 40.f;
725         break;
726     case ct_lfotrigmode:
727         valtype = vt_int;
728         val_min.i = 0;
729         val_max.i = n_lfo_trigger_modes - 1;
730         val_default.i = 0;
731         break;
732     case ct_pitch_octave:
733         valtype = vt_int;
734         val_min.i = -3;
735         val_max.i = 3;
736         val_default.i = 0;
737         break;
738     case ct_bool_mute:
739     case ct_bool_solo:
740     case ct_bool_fm:
741     case ct_bool_keytrack:
742     case ct_bool_retrigger:
743     case ct_bool_relative_switch:
744     case ct_bool_link_switch:
745     case ct_bool_unipolar:
746     case ct_bool:
747         valtype = vt_bool;
748         val_min.i = 0;
749         val_max.i = 1;
750         val_default.i = 0;
751         break;
752     case ct_float_toggle:
753         valtype = vt_float;
754         val_min.f = 0.f;
755         val_max.f = 1.f;
756         val_default.f = 0.f;
757         break;
758     case ct_osctype:
759         valtype = vt_int;
760         val_min.i = 0;
761         val_default.i = 0;
762         val_max.i = n_osc_types - 1;
763         /*
764          * BP: We do, but this isn't how we load osces
765          */
766         affect_other_parameters = false;
767         break;
768     case ct_reverbshape:
769         valtype = vt_int;
770         val_min.i = 0;
771         val_default.i = 0;
772         val_max.i = 3;
773         break;
774     case ct_fxtype:
775         valtype = vt_int;
776         val_min.i = 0;
777         val_default.i = 0;
778         val_max.i = n_fx_types - 1;
779         // affect_other_parameters = true;	// Can not be added, before it has a custom
780         // controltype
781         break;
782     case ct_fxbypass:
783         valtype = vt_int;
784         val_min.i = 0;
785         val_default.i = 0;
786         val_max.i = n_fx_bypass - 1;
787         break;
788     case ct_oscroute:
789         valtype = vt_int;
790         val_min.i = 0;
791         val_max.i = 2;
792         val_default.i = 1;
793         break;
794     case ct_envshape:
795     case ct_envshape_attack:
796         valtype = vt_int;
797         val_min.i = 0;
798         val_max.i = 2;
799         val_default.i = 0;
800         break;
801     case ct_envmode:
802         valtype = vt_int;
803         val_min.i = 0;
804         val_max.i = 1;
805         val_default.i = 0;
806         break;
807     case ct_stereowidth:
808         valtype = vt_float;
809         val_min.f = 0;
810         val_max.f = 120;
811         val_default.f = 90;
812         break;
813     case ct_lfotype:
814         valtype = vt_int;
815         val_min.i = 0;
816         val_max.i = n_lfo_types - 1;
817         val_default.i = 0;
818         break;
819     case ct_fbconfig:
820         valtype = vt_int;
821         val_min.i = 0;
822         val_max.i = n_filter_configs - 1;
823         val_default.i = 0;
824         break;
825     case ct_fmconfig:
826         valtype = vt_int;
827         val_min.i = 0;
828         val_max.i = n_fm_routings - 1;
829         val_default.i = 0;
830         break;
831     case ct_filtertype:
832         valtype = vt_int;
833         val_min.i = 0;
834         val_max.i = n_fu_types - 1;
835         val_default.i = 0;
836         break;
837     case ct_filtersubtype:
838         valtype = vt_int;
839         val_min.i = 0;
840         val_max.i = n_max_filter_subtypes - 1;
841         val_default.i = 0;
842         break;
843     case ct_wstype:
844         valtype = vt_int;
845         val_min.i = 0;
846         val_max.i = n_ws_types - 1;
847         val_default.i = 0;
848         break;
849     case ct_midikey_or_channel:
850     case ct_midikey:
851         valtype = vt_int;
852         val_min.i = 0;
853         val_max.i = 127;
854         val_default.i = 60;
855         break;
856     case ct_wt2window:
857         valtype = vt_int;
858         val_min.i = 0;
859         val_max.i = 8;
860         val_default.i = 0;
861         break;
862     case ct_osccount:
863     case ct_osccountWT:
864         valtype = vt_int;
865         val_min.i = 1;
866         val_max.i = 16;
867         val_default.i = 1;
868         break;
869     case ct_scenemode:
870         valtype = vt_int;
871         val_min.i = 0;
872         val_max.i = n_scene_modes - 1;
873         val_default.i = 0;
874         break;
875     case ct_polymode:
876         valtype = vt_int;
877         val_min.i = 0;
878         val_max.i = n_play_modes - 1;
879         val_default.i = 0;
880         break;
881     case ct_polylimit:
882         valtype = vt_int;
883         val_min.i = 2;
884         val_max.i = 64;
885         val_default.i = 16;
886         break;
887     case ct_scenesel:
888         valtype = vt_int;
889         val_min.i = 0;
890         val_max.i = 1;
891         val_default.i = 0;
892         break;
893     case ct_percent:
894     case ct_percent_deactivatable:
895     case ct_percent_oscdrift:
896         val_min.f = 0;
897         val_max.f = 1;
898         valtype = vt_float;
899         val_default.f = 0;
900         break;
901     case ct_oscspread:
902         val_min.f = 0.f;
903         val_max.f = 1.f;
904         valtype = vt_float;
905         val_default.f = 0.1;
906         break;
907     case ct_oscspread_bipolar:
908         val_min.f = -1.f;
909         val_max.f = 1.f;
910         valtype = vt_float;
911         val_default.f = 0.0;
912         break;
913     case ct_detuning:
914         val_min.f = 0;
915         val_max.f = 2;
916         valtype = vt_float;
917         val_default.f = 0;
918         break;
919     case ct_lfodeform:
920         val_min.f = -1;
921         val_max.f = 1;
922         valtype = vt_float;
923         val_default.f = 0;
924         break;
925     case ct_amplitude:
926     case ct_amplitude_clipper:
927     case ct_lfoamplitude:
928         val_min.f = 0;
929         val_max.f = 1;
930         valtype = vt_float;
931         val_default.f = 1;
932         break;
933     case ct_modern_trimix:
934     case ct_percent_bipolar:
935     case ct_percent_bipolar_stereo:
936     case ct_percent_bipolar_stringbal:
937     case ct_percent_bipolar_w_dynamic_unipolar_formatting:
938     case ct_twist_aux_mix:
939         val_min.f = -1;
940         val_max.f = 1;
941         valtype = vt_float;
942         val_default.f = 0;
943         break;
944     case ct_character:
945         val_min.i = 0;
946         val_max.i = 2;
947         valtype = vt_int;
948         val_default.i = 1;
949         break;
950     case ct_sineoscmode:
951         val_min.i = 0;
952         val_max.i = 27;
953         valtype = vt_int;
954         val_default.i = 0;
955         break;
956     case ct_sinefmlegacy:
957         val_min.i = 0;
958         val_max.i = 1;
959         valtype = vt_int;
960         val_default.i = 0;
961         break;
962     case ct_reson_mode:
963         val_min.i = 0;
964         val_max.i = 3;
965         valtype = vt_int;
966         val_default.i = 1;
967         break;
968     case ct_reson_res_extendable:
969         val_min.f = 0;
970         val_max.f = 1;
971         valtype = vt_float;
972         val_default.f = 0.75f;
973         break;
974     case ct_vocoder_bandcount:
975         val_min.i = 4;
976         val_max.i = 20;
977         valtype = vt_int;
978         val_default.i = 20;
979         break;
980     case ct_vocoder_modulator_mode:
981         val_min.i = 0;
982         val_max.i = 3;
983         valtype = vt_int;
984         val_default.i = 0;
985         break;
986     case ct_distortion_waveshape:
987         val_min.i = 0;
988         val_max.i = n_ws_types - 2; // we want to skip none also
989         valtype = vt_int;
990         val_default.i = 0;
991         break;
992     case ct_countedset_percent:
993         val_min.f = 0;
994         val_max.f = 1;
995         valtype = vt_float;
996         val_default.f = 0;
997         break;
998     case ct_flangerpitch:
999         val_min.f = 0;
1000         val_max.f = 127;
1001         valtype = vt_float;
1002         val_default.f = 60;
1003         break;
1004     case ct_flangervoices:
1005         val_min.f = 1;
1006         val_max.f = 4;
1007         valtype = vt_float;
1008         val_default.f = 4;
1009         break;
1010     case ct_flangermode:
1011         val_min.i = 0;
1012         val_max.i = 3; // classic, dopler, arpmix, arpsolo
1013         valtype = vt_int;
1014         val_default.i = 0;
1015         break;
1016     case ct_fxlfowave:
1017         valtype = vt_int;
1018         val_min.i = 0;
1019         val_max.i = 5; // sin, tri, saw, s&g, s&h, square
1020         val_default.i = 0;
1021         break;
1022     case ct_twist_engine:
1023         valtype = vt_int;
1024         val_min.i = 0;
1025         val_max.i = 15;
1026         val_default.i = 0;
1027         break;
1028     case ct_ensemble_stages:
1029     {
1030         extern int ensemble_stage_count();
1031         valtype = vt_int;
1032         val_min.i = 0;
1033         val_max.i = ensemble_stage_count() - 1;
1034         val_default.i = 0;
1035         break;
1036     }
1037     case ct_stringosc_excitation_model:
1038     {
1039         extern int stringosc_excitations_count();
1040         valtype = vt_int;
1041         val_min.i = 0;
1042         val_max.i = stringosc_excitations_count() - 1;
1043         val_default.i = 0;
1044         break;
1045     }
1046     case ct_alias_wave:
1047     {
1048         extern int alias_waves_count();
1049         valtype = vt_int;
1050         val_min.i = 0;
1051         val_max.i = alias_waves_count() - 1;
1052         val_default.i = 0;
1053         break;
1054     }
1055     case ct_alias_mask:
1056     {
1057         valtype = vt_float;
1058         val_min.f = 0.f;
1059         val_max.f = 1.f;
1060         val_default.f = 0.f;
1061         break;
1062     }
1063     case ct_alias_bits:
1064     {
1065         valtype = vt_float;
1066         val_min.f = 1.f;
1067         val_max.f = 8.f;
1068         val_default.f = 8.f;
1069         break;
1070     }
1071     case ct_flangerspacing:
1072         val_min.f = 0;
1073         val_max.f = 12;
1074         valtype = vt_float;
1075         val_default.f = 0;
1076         break;
1077     case ct_osc_feedback:
1078         val_min.f = 0;
1079         val_max.f = 1;
1080         valtype = vt_float;
1081         val_default.f = 0;
1082         break;
1083     case ct_osc_feedback_negative:
1084         val_min.f = -1;
1085         val_max.f = 1;
1086         valtype = vt_float;
1087         val_default.f = 0;
1088         break;
1089     case ct_percent200:
1090         val_min.f = 0;
1091         val_max.f = 2;
1092         valtype = vt_float;
1093         val_default.f = 0;
1094         break;
1095     case ct_phaser_stages:
1096         val_min.i = 1;
1097         val_max.i = 16;
1098         valtype = vt_int;
1099         val_default.i = 4;
1100         break;
1101     case ct_rotarydrive:
1102         val_min.f = 0;
1103         val_max.f = 1;
1104         valtype = vt_float;
1105         val_default.f = 0;
1106         break;
1107     case ct_sendlevel:
1108         val_min.f = 0;
1109         val_max.f = 1.5874;
1110         valtype = vt_float;
1111         val_default.f = 0;
1112         break;
1113     case ct_airwindows_fx:
1114         val_min.i = 0;
1115         val_max.i = 10;
1116         valtype = vt_int;
1117         val_default.i = 0;
1118         break;
1119     case ct_airwindows_param:
1120     case ct_airwindows_param_bipolar: // it's still 0,1; this is just a display thing
1121         val_min.f = 0;
1122         val_max.f = 1;
1123         valtype = vt_float;
1124         val_default.f = 0;
1125         break;
1126     case ct_airwindows_param_integral:
1127         val_min.i = 0;
1128         val_max.i = 1;
1129         valtype = vt_int;
1130         val_default.i = 0;
1131         break;
1132     case ct_phaser_spread:
1133         val_min.f = 0;
1134         val_max.f = 1;
1135         valtype = vt_float;
1136         val_default.f = 0.5;
1137         break;
1138     case ct_chow_ratio:
1139         val_min.f = 1;
1140         val_max.f = 20;
1141         valtype = vt_float;
1142         val_default.f = 10.f;
1143         break;
1144 
1145     case ct_nimbusmode:
1146         valtype = vt_int;
1147         val_min.i = 0;
1148         val_max.i = 3; // sin, tri, saw, s&h
1149         val_default.i = 0;
1150         break;
1151 
1152     case ct_nimbusquality:
1153         valtype = vt_int;
1154         val_min.i = 0;
1155         val_max.i = 3; // mono LQ, stereo LQ, mono HQ, stereo HQ
1156         val_default.i = 0;
1157         break;
1158 
1159     case ct_comp_attack_ms:
1160     case ct_comp_release_ms:
1161         valtype = vt_float;
1162         val_min.f = 0.f;
1163         val_max.f = 1.f;
1164         val_default.f = 0.5f;
1165         break;
1166 
1167     case ct_tape_microns:
1168         valtype = vt_float;
1169         val_min.f = 0.f;
1170         val_max.f = 500.f;
1171         val_default.f = 50.0f;
1172         break;
1173 
1174     case ct_tape_speed:
1175         valtype = vt_float;
1176         val_min.f = 1.0f;
1177         val_max.f = 50.0f;
1178         val_default.f = 30.0f;
1179         break;
1180 
1181     case ct_none:
1182     default:
1183         snprintf(dispname, NAMECHARS, "-");
1184         valtype = vt_int;
1185 
1186         val_min.i = std::numeric_limits<int>::min();
1187         val_max.i = std::numeric_limits<int>::max();
1188         val_default.i = 0;
1189         break;
1190     }
1191 
1192     /*
1193     ** Setup display info here
1194     */
1195     displayType = Custom;
1196     DisplayInfo d; // reset everything to default
1197     displayInfo = d;
1198     displayInfo.unit[0] = 0;
1199     displayInfo.absoluteUnit[0] = 0;
1200     displayInfo.minLabel[0] = 0;
1201     displayInfo.maxLabel[0] = 0;
1202 
1203     switch (ctrltype)
1204     {
1205     case ct_percent:
1206     case ct_percent_deactivatable:
1207     case ct_percent_oscdrift:
1208     case ct_percent200:
1209     case ct_percent_bipolar:
1210     case ct_lfodeform:
1211     case ct_rotarydrive:
1212     case ct_countedset_percent:
1213     case ct_lfoamplitude:
1214     case ct_reson_res_extendable:
1215     case ct_modern_trimix:
1216     case ct_alias_mask:
1217         displayType = LinearWithScale;
1218         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "%%");
1219         displayInfo.scale = 100;
1220         break;
1221     case ct_percent_bipolar_w_dynamic_unipolar_formatting:
1222     case ct_twist_aux_mix:
1223         displayType = LinearWithScale;
1224         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "%%");
1225         displayInfo.scale = 100;
1226         displayInfo.customFeatures = ParamDisplayFeatures::kScaleBasedOnIsBiPolar;
1227         break;
1228     case ct_percent_bipolar_stereo:
1229         displayType = LinearWithScale;
1230         displayInfo.customFeatures = ParamDisplayFeatures::kHasCustomMinString |
1231                                      ParamDisplayFeatures::kHasCustomMaxString |
1232                                      ParamDisplayFeatures::kHasCustomDefaultString;
1233 
1234         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "%%");
1235         snprintf(displayInfo.minLabel, DISPLAYINFO_TXT_SIZE, "-100.00 %% (Left)");
1236         snprintf(displayInfo.defLabel, DISPLAYINFO_TXT_SIZE, "0.00 %% (Stereo)");
1237         snprintf(displayInfo.maxLabel, DISPLAYINFO_TXT_SIZE, "100.00 %% (Right)");
1238         displayInfo.scale = 100;
1239         break;
1240     case ct_percent_bipolar_stringbal:
1241         displayType = LinearWithScale;
1242         displayInfo.customFeatures = ParamDisplayFeatures::kHasCustomMinString |
1243                                      ParamDisplayFeatures::kHasCustomMaxString |
1244                                      ParamDisplayFeatures::kHasCustomDefaultString;
1245 
1246         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "%%");
1247         snprintf(displayInfo.minLabel, DISPLAYINFO_TXT_SIZE, "-100.00 %% (String 1)");
1248         snprintf(displayInfo.defLabel, DISPLAYINFO_TXT_SIZE, "0.00 %% (Strings 1+2)");
1249         snprintf(displayInfo.maxLabel, DISPLAYINFO_TXT_SIZE, "100.00 %% (String 2)");
1250         displayInfo.scale = 100;
1251         break;
1252 
1253         /*
1254           Again the missing breaks here are on purpose
1255          */
1256     case ct_pitch_semi7bp_absolutable:
1257         displayInfo.absoluteFactor = 10.0;
1258         snprintf(displayInfo.absoluteUnit, DISPLAYINFO_TXT_SIZE, "Hz");
1259     case ct_pitch_semi7bp:
1260     case ct_flangerspacing:
1261         displayInfo.extendFactor = 12.0;
1262     case ct_pitch:
1263     case ct_pitch4oct:
1264     case ct_syncpitch:
1265     case ct_freq_mod:
1266     case ct_flangerpitch:
1267         displayType = LinearWithScale;
1268         displayInfo.customFeatures = ParamDisplayFeatures::kUnitsAreSemitonesOrKeys;
1269         break;
1270     case ct_freq_hpf:
1271     case ct_freq_audible:
1272     case ct_freq_audible_deactivatable:
1273     case ct_freq_audible_with_tunability:
1274     case ct_freq_audible_with_very_low_lowerbound:
1275     case ct_freq_reson_band1:
1276     case ct_freq_reson_band2:
1277     case ct_freq_reson_band3:
1278     case ct_freq_vocoder_low:
1279     case ct_freq_vocoder_high:
1280     case ct_freq_ringmod:
1281         displayType = ATwoToTheBx;
1282         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "Hz");
1283         displayInfo.a = (ctrltype == ct_freq_ringmod) ? 8.175798 : 440.0;
1284         displayInfo.b = 1.0f / 12.0f;
1285         displayInfo.decimals = 2;
1286         displayInfo.modulationCap = 880.f * powf(2.0, (val_max.f) / 12.0f);
1287         displayInfo.supportsNoteName = true;
1288         break;
1289 
1290     case ct_freq_shift:
1291         displayType = LinearWithScale;
1292         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "Hz");
1293         displayInfo.extendFactor = 100.0;
1294         break;
1295 
1296     case ct_envtime_lfodecay:
1297         snprintf(displayInfo.maxLabel, DISPLAYINFO_TXT_SIZE, "Forever");
1298         displayInfo.customFeatures = ParamDisplayFeatures::kHasCustomMaxString;
1299         // THERE IS NO BREAK HERE ON PURPOSE so we group to the others
1300     case ct_portatime:
1301     case ct_envtime:
1302     case ct_envtime_linkable_delay:
1303     case ct_reverbtime:
1304     case ct_reverbpredelaytime:
1305     case ct_chorusmodtime:
1306     case ct_delaymodtime:
1307         displayType = ATwoToTheBx;
1308         displayInfo.customFeatures |= ParamDisplayFeatures::kHasCustomMinValue;
1309         displayInfo.minLabelValue = 0.f;
1310         displayInfo.tempoSyncNotationMultiplier = 1.f;
1311         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "s");
1312         displayInfo.decimals = 3;
1313         break;
1314 
1315     case ct_lforate:
1316     case ct_lforate_deactivatable:
1317     case ct_ensemble_lforate:
1318         displayType = ATwoToTheBx;
1319         displayInfo.decimals = 3;
1320         displayInfo.tempoSyncNotationMultiplier = -1.0f;
1321         displayInfo.modulationCap = 512 * 8;
1322         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "Hz");
1323         break;
1324 
1325     case ct_decibel_extendable:
1326         displayType = LinearWithScale;
1327         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "dB");
1328         displayInfo.extendFactor = 3;
1329         break;
1330 
1331     case ct_decibel_narrow_extendable:
1332         displayType = LinearWithScale;
1333         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "dB");
1334         displayInfo.extendFactor = 5;
1335         break;
1336 
1337     case ct_decibel_narrow_short_extendable:
1338         displayType = LinearWithScale;
1339         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "dB");
1340         displayInfo.extendFactor = 2;
1341         break;
1342 
1343     case ct_decibel:
1344     case ct_decibel_attenuation:
1345     case ct_decibel_attenuation_clipper:
1346     case ct_decibel_attenuation_large:
1347     case ct_decibel_fmdepth:
1348     case ct_decibel_narrow:
1349     case ct_decibel_extra_narrow:
1350     case ct_decibel_deactivatable:
1351     case ct_decibel_narrow_deactivatable:
1352     case ct_decibel_extra_narrow_deactivatable:
1353         displayType = LinearWithScale;
1354         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "dB");
1355         break;
1356 
1357     case ct_bandwidth:
1358         displayType = LinearWithScale;
1359         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "octaves");
1360         break;
1361 
1362     case ct_detuning:
1363         displayType = LinearWithScale;
1364         displayInfo.scale = 100.0;
1365         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "cents");
1366         break;
1367 
1368     case ct_stereowidth:
1369         displayType = LinearWithScale;
1370         displayInfo.scale = 1.0;
1371         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "º");
1372         break;
1373 
1374     case ct_oscspread:
1375     case ct_oscspread_bipolar:
1376         displayType = LinearWithScale;
1377         displayInfo.scale = 100.0;
1378         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "cents");
1379         snprintf(displayInfo.absoluteUnit, DISPLAYINFO_TXT_SIZE, "Hz");
1380         displayInfo.absoluteFactor =
1381             0.16; // absolute factor also takes scale into account hence the /100
1382         displayInfo.extendFactor = 12;
1383         break;
1384 
1385     case ct_osc_feedback:
1386     case ct_osc_feedback_negative:
1387         displayType = LinearWithScale;
1388         displayInfo.scale = 100.0;
1389         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "%%");
1390         displayInfo.extendFactor = 4;
1391         break;
1392 
1393     case ct_amplitude:
1394     case ct_amplitude_clipper:
1395     case ct_sendlevel:
1396         displayType = Decibel;
1397         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "dB");
1398         break;
1399 
1400     case ct_airwindows_param:
1401     case ct_airwindows_param_bipolar:
1402     case ct_airwindows_param_integral:
1403         displayType = DelegatedToFormatter;
1404         displayInfo.scale = 1.0;
1405         displayInfo.unit[0] = 0;
1406         displayInfo.decimals = 3;
1407         break;
1408 
1409     case ct_comp_attack_ms:
1410         displayType = ATwoToTheBx;
1411         displayInfo.a = 1.0f;
1412         displayInfo.b = std::log2(100.0f / 1.0f);
1413         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "ms");
1414         break;
1415 
1416     case ct_comp_release_ms:
1417         displayType = ATwoToTheBx;
1418         displayInfo.a = 10.0f;
1419         displayInfo.b = std::log2(1000.0f / 10.0f);
1420         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "ms");
1421         break;
1422 
1423     case ct_ensemble_clockrate:
1424         displayType = LinearWithScale;
1425         displayInfo.scale = 1.f;
1426         displayInfo.decimals = 2;
1427         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "kHz");
1428         break;
1429 
1430     case ct_alias_bits:
1431         displayType = LinearWithScale;
1432         displayInfo.scale = 1.f;
1433         displayInfo.decimals = 2;
1434         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "bits");
1435         break;
1436 
1437     case ct_tape_microns:
1438         displayType = LinearWithScale;
1439         displayInfo.scale = 1.0f;
1440         displayInfo.decimals = 2;
1441         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "μm");
1442         break;
1443 
1444     case ct_tape_speed:
1445         displayType = LinearWithScale;
1446         displayInfo.scale = 1.0f;
1447         displayInfo.decimals = 2;
1448         snprintf(displayInfo.unit, DISPLAYINFO_TXT_SIZE, "ips");
1449         break;
1450     }
1451 }
1452 
bound_value(bool force_integer)1453 void Parameter::bound_value(bool force_integer)
1454 {
1455     if (temposync && (valtype == vt_float))
1456     {
1457         float a, b = modff(val.f, &a);
1458         if (b < 0)
1459         {
1460             b += 1.f;
1461             a -= 1.f;
1462         }
1463         b = powf(2.0f, b);
1464 
1465         if (b > 1.41f)
1466         {
1467             b = log2(1.5f);
1468         }
1469         else if (b > 1.167f)
1470         {
1471             b = log2(1.3333333333f);
1472         }
1473         else
1474         {
1475             b = 0.f;
1476         }
1477 
1478         val.f = a + b;
1479     }
1480 
1481     if (force_integer && (valtype == vt_float))
1482     {
1483         switch (ctrltype)
1484         {
1485         case ct_percent:
1486         case ct_percent_deactivatable:
1487         case ct_percent_oscdrift:
1488         case ct_percent200:
1489         case ct_percent_bipolar:
1490         case ct_percent_bipolar_stereo:
1491         case ct_percent_bipolar_stringbal:
1492         case ct_percent_bipolar_w_dynamic_unipolar_formatting:
1493         case ct_twist_aux_mix:
1494         case ct_rotarydrive:
1495         case ct_osc_feedback:
1496         case ct_osc_feedback_negative:
1497         case ct_detuning:
1498         case ct_lfoamplitude:
1499         case ct_airwindows_param:
1500         case ct_airwindows_param_bipolar:
1501         case ct_lfodeform:
1502         case ct_reson_res_extendable:
1503         case ct_modern_trimix:
1504         {
1505             val.f = floor(val.f * 100) / 100.0;
1506             break;
1507         }
1508         case ct_pitch:
1509         case ct_pitch4oct:
1510         case ct_pitch_semi7bp:
1511         case ct_syncpitch:
1512         {
1513             if (!extend_range)
1514             {
1515                 val.f = floor(val.f + 0.5f);
1516             }
1517 
1518             break;
1519         }
1520         case ct_oscspread:
1521         case ct_oscspread_bipolar:
1522         {
1523             if (absolute)
1524             {
1525                 if (extend_range)
1526                 {
1527                     val.f = floor(val.f * 192) / 192.0;
1528                 }
1529                 else
1530                 {
1531                     val.f = floor(val.f * 16) / 16.0;
1532                 }
1533             }
1534             else if (extend_range)
1535             {
1536                 val.f = floor(val.f * 120) / 120.0;
1537             }
1538             else
1539             {
1540                 val.f = floor(val.f * 100) / 100.0;
1541             }
1542 
1543             break;
1544         }
1545         case ct_pitch_semi7bp_absolutable:
1546         {
1547             if (absolute)
1548                 if (extend_range)
1549                 {
1550                     val.f = floor(val.f * 120) / 120.0;
1551                 }
1552                 else
1553                 {
1554                     val.f = floor(val.f * 12) / 12.0;
1555                 }
1556             else
1557             {
1558                 val.f = floor(val.f + 0.5f);
1559             }
1560             break;
1561         }
1562         case ct_amplitude:
1563         case ct_amplitude_clipper:
1564         case ct_sendlevel:
1565         {
1566             if (val.f != 0)
1567             {
1568                 val.f = db_to_amp(round(
1569                     amp_to_db(val.f))); // we use round instead of floor because with some params
1570                                         // it wouldn't snap to max value (i.e. send levels)
1571             }
1572             else
1573             {
1574                 val.f = -INFINITY; // this is so that the popup shows -inf proper instead of -192.0
1575             }
1576             break;
1577         }
1578         case ct_decibel:
1579         case ct_decibel_narrow:
1580         case ct_decibel_narrow_extendable:
1581         case ct_decibel_narrow_short_extendable:
1582         case ct_decibel_extra_narrow:
1583         case ct_decibel_attenuation:
1584         case ct_decibel_attenuation_clipper:
1585         case ct_decibel_attenuation_large:
1586         case ct_decibel_fmdepth:
1587         case ct_decibel_extendable:
1588         case ct_decibel_deactivatable:
1589         case ct_decibel_narrow_deactivatable:
1590         case ct_decibel_extra_narrow_deactivatable:
1591         {
1592             val.f = floor(val.f);
1593             break;
1594         }
1595         case ct_chorusmodtime:
1596         {
1597             val.f = limit_range((float)log2(round(powf(2.0f, val.f) * 100) / 100.f), val_min.f,
1598                                 val_max.f);
1599             break;
1600         }
1601         case ct_portatime:
1602         case ct_envtime:
1603         case ct_envtime_linkable_delay:
1604         case ct_envtime_lfodecay:
1605         case ct_reverbtime:
1606         case ct_reverbpredelaytime:
1607         case ct_delaymodtime:
1608             if (temposync)
1609             {
1610                 val.f = floor(val.f + 0.5f);
1611             }
1612             else
1613             {
1614                 val.f = log2(round(powf(2.0f, val.f) * 10) / 10.f);
1615             }
1616             break;
1617         case ct_ensemble_lforate:
1618         case ct_lforate:
1619         case ct_lforate_deactivatable:
1620         {
1621             if (temposync)
1622             {
1623                 val.f = floor(val.f + 0.5f);
1624             }
1625             else if (val.f < 0)
1626             {
1627                 val.f = limit_range((float)log2(round(powf(2.0f, val.f) * 10) / 10.f), val_min.f,
1628                                     val_max.f);
1629             }
1630             else
1631             {
1632                 val.f = log2(round(powf(2.0f, val.f)));
1633             }
1634 
1635             break;
1636         }
1637         case ct_bandwidth:
1638         {
1639             val.f = floor(val.f * 10) / 10.0;
1640             break;
1641         }
1642         case ct_freq_shift:
1643         {
1644             if (extend_range)
1645             {
1646                 val.f = floor(val.f * 100) / 100.0;
1647             }
1648             else
1649             {
1650                 val.f = floor(val.f + 0.5f);
1651             }
1652             break;
1653         }
1654         case ct_countedset_percent:
1655         {
1656             CountedSetUserData *cs = reinterpret_cast<CountedSetUserData *>(user_data);
1657             auto count = cs->getCountedSetSize();
1658             // OK so now val.f is between 0 and 1. So
1659             auto fraccount = val.f * count;
1660             auto intcount = (int)fraccount;
1661             val.f = 1.0 * intcount / count;
1662             break;
1663         }
1664         case ct_alias_mask:
1665         {
1666             auto fraccount = val.f * 255;
1667             auto intcount = (int)fraccount;
1668             val.f = 1.0 * intcount / 255;
1669             break;
1670         }
1671         case ct_fmratio:
1672         {
1673             if (absolute)
1674             {
1675                 auto bpv = (val.f - 16.0) / 16.0;
1676                 auto note = 69.0 + (69.0 * bpv);
1677                 note = round(note);
1678 
1679                 val.f = note / 4.3125;
1680             }
1681             else if (extend_range)
1682             {
1683                 float ratio;
1684 
1685                 if (val.f > 16.f)
1686                 {
1687                     ratio = round((val.f - 16.f) * 31.f / 16.f + 1.f);
1688                     val.f = 16.f + ((ratio - 1.f) / 1.9375); // 1.9375 = 31 / 16
1689                 }
1690                 else
1691                 {
1692                     ratio = -round((16.f - val.f) * 31.f / 16.f + 1.f);
1693                     val.f = 16.f + ((ratio + 1.f) / 1.9375);
1694                 }
1695             }
1696             else
1697             {
1698                 val.f = floor(val.f + 0.5f);
1699             }
1700 
1701             break;
1702         }
1703         default:
1704         {
1705             val.f = floor(val.f + 0.5f);
1706             break;
1707         }
1708         }
1709     }
1710 
1711     if (ctrltype == ct_vocoder_bandcount)
1712     {
1713         val.i = val.i - val.i % 4;
1714     }
1715 
1716     switch (valtype)
1717     {
1718     case vt_float:
1719     {
1720         val.f = limit_range(val.f, val_min.f, val_max.f);
1721         break;
1722     }
1723     case vt_int:
1724     {
1725         val.i = limit_range(val.i, val_min.i, val_max.i);
1726         break;
1727     }
1728     };
1729 }
1730 
supportsDynamicName()1731 bool Parameter::supportsDynamicName()
1732 {
1733     switch (ctrltype)
1734     {
1735     case ct_modern_trimix:
1736     case ct_percent:
1737     case ct_percent_bipolar:
1738     case ct_percent_bipolar_w_dynamic_unipolar_formatting:
1739     case ct_twist_aux_mix:
1740     case ct_percent_deactivatable:
1741         return true;
1742     default:
1743         break;
1744     }
1745     return false;
1746 }
get_name()1747 const char *Parameter::get_name()
1748 {
1749     // We only even want to try this for specific types we know support it
1750     if (supportsDynamicName() && dynamicName)
1751         return dynamicName->getName(this);
1752 
1753     return dispname;
1754 }
1755 
get_full_name()1756 const char *Parameter::get_full_name()
1757 {
1758     if (supportsDynamicName() && dynamicName)
1759     {
1760         auto nm = dynamicName->getName(this);
1761         static char res[1024];
1762         create_fullname(nm, res, ctrlgroup, ctrlgroup_entry);
1763         return res;
1764     }
1765 
1766     return fullname;
1767 }
1768 
get_internal_name()1769 const char *Parameter::get_internal_name() { return name; }
1770 
get_storage_name()1771 const char *Parameter::get_storage_name() { return name_storage; }
1772 
get_storage_value(char * str)1773 char *Parameter::get_storage_value(char *str)
1774 {
1775     switch (valtype)
1776     {
1777     case vt_int:
1778         snprintf(str, TXT_SIZE, "%i", val.i);
1779         break;
1780     case vt_bool:
1781         snprintf(str, TXT_SIZE, "%i", val.b ? 1 : 0);
1782         break;
1783     case vt_float:
1784         std::stringstream sst;
1785         sst.imbue(std::locale::classic());
1786         sst << std::fixed;
1787         sst << std::showpoint;
1788         sst << std::setprecision(6);
1789         sst << val.f;
1790         strxcpy(str, sst.str().c_str(), TXT_SIZE);
1791         break;
1792     };
1793 
1794     return str;
1795 }
1796 
set_storage_value(int i)1797 void Parameter::set_storage_value(int i)
1798 {
1799     switch (ctrltype)
1800     {
1801     default:
1802     {
1803         val.i = i;
1804         break;
1805     }
1806     }
1807 }
set_storage_value(float f)1808 void Parameter::set_storage_value(float f)
1809 {
1810     switch (ctrltype)
1811     {
1812     default:
1813     {
1814         val.f = f;
1815         break;
1816     }
1817     }
1818 }
1819 
get_extended(float f)1820 float Parameter::get_extended(float f)
1821 {
1822     if (!extend_range)
1823     {
1824         switch (ctrltype)
1825         {
1826         case ct_freq_reson_band1:
1827         {
1828             val_max.f = -6.6305f; // 300 Hz
1829             return f;
1830         }
1831         case ct_freq_reson_band2:
1832         {
1833             val_min.f = -6.6305f;  // 300 Hz
1834             val_max.f = 21.23265f; // 1500 Hz
1835             return f;
1836         }
1837         case ct_freq_reson_band3:
1838         {
1839             val_min.f = 21.23265f; // 1500 Hz
1840             return f;
1841         }
1842         default:
1843         {
1844             return f;
1845         }
1846         }
1847     }
1848 
1849     switch (ctrltype)
1850     {
1851     case ct_freq_reson_band1:
1852     case ct_freq_reson_band2:
1853     case ct_freq_reson_band3:
1854     {
1855         val_min.f = -34.4936f; // 60 Hz
1856         val_max.f = 49.09578;  // 7500 Hz
1857         return f;
1858     }
1859     case ct_freq_shift:
1860         return 100.f * f;
1861     case ct_pitch_semi7bp:
1862     case ct_pitch_semi7bp_absolutable:
1863         return 12.f * f;
1864     case ct_decibel_extendable:
1865         return 3.f * f;
1866     case ct_decibel_narrow_extendable:
1867         return 5.f * f;
1868     case ct_decibel_narrow_short_extendable:
1869         return 2.f * f;
1870     case ct_oscspread:
1871     case ct_oscspread_bipolar:
1872         return 12.f * f;
1873     case ct_osc_feedback:
1874         return 8.f * f - 4.f * f;
1875     case ct_osc_feedback_negative:
1876         return 4.f * f;
1877     case ct_lfoamplitude:
1878         return (2.f * f) - 1.f;
1879     case ct_fmratio:
1880     {
1881         if (f > 16)
1882         {
1883             return ((f - 16) * 31.f / 16.f + 1);
1884         }
1885         else
1886         {
1887             return -((16 - f) * 31.f / 16.f + 1);
1888         }
1889     }
1890     default:
1891     {
1892         return f;
1893     }
1894     }
1895 }
1896 
tempoSyncNotationValue(float f)1897 std::string Parameter::tempoSyncNotationValue(float f)
1898 {
1899     float a, b = modff(f, &a);
1900 
1901     if (b >= 0)
1902     {
1903         b -= 1.0;
1904         a += 1.0;
1905     }
1906 
1907     float d, q;
1908     std::string nn, t;
1909     char tmp[1024];
1910 
1911     if (f >= 1)
1912     {
1913         q = pow(2.0, f - 1);
1914         nn = "whole";
1915         if (q >= 3)
1916         {
1917             if (abs(q - floor(q + 0.01)) < 0.01)
1918             {
1919                 snprintf(tmp, 1024, "%d whole notes", (int)floor(q + 0.01));
1920             }
1921             else
1922             {
1923                 // this is the triplet case
1924                 snprintf(tmp, 1024, "%d whole triplets", (int)floor(q * 3.0 / 2.0 + 0.02));
1925             }
1926             std::string res = tmp;
1927             return res;
1928         }
1929         else if (q >= 2)
1930         {
1931             nn = "double whole";
1932             q /= 2;
1933         }
1934 
1935         if (q < 1.3)
1936         {
1937             t = "note";
1938         }
1939         else if (q < 1.4)
1940         {
1941             t = "triplet";
1942             if (nn == "whole")
1943             {
1944                 nn = "double whole";
1945             }
1946             else
1947             {
1948                 q = pow(2.0, f - 1);
1949                 snprintf(tmp, 1024, "%d whole triplets", (int)floor(q * 3.0 / 2.0 + 0.02));
1950                 std::string res = tmp;
1951                 return res;
1952             }
1953         }
1954         else
1955         {
1956             t = "dotted";
1957         }
1958     }
1959     else
1960     {
1961         d = pow(2.0, -(a - 2));
1962         q = pow(2.0, (b + 1));
1963 
1964         if (q < 1.3)
1965         {
1966             t = "note";
1967         }
1968         else if (q < 1.4)
1969         {
1970             t = "triplet";
1971             d = d / 2;
1972         }
1973         else
1974         {
1975             t = "dotted";
1976         }
1977         if (d == 1)
1978         {
1979             nn = "whole";
1980         }
1981         else
1982         {
1983             char tmp[1024];
1984             snprintf(tmp, 1024, "1/%d", (int)d);
1985             nn = tmp;
1986         }
1987     }
1988     std::string res = nn + " " + t;
1989 
1990     return res;
1991 }
1992 
get_display_of_modulation_depth(char * txt,float modulationDepth,bool isBipolar,ModulationDisplayMode displaymode,ModulationDisplayInfoWindowStrings * iw)1993 void Parameter::get_display_of_modulation_depth(char *txt, float modulationDepth, bool isBipolar,
1994                                                 ModulationDisplayMode displaymode,
1995                                                 ModulationDisplayInfoWindowStrings *iw)
1996 {
1997     int detailedMode = false;
1998 
1999     if (storage)
2000         detailedMode = Surge::Storage::getUserDefaultValue(storage, "highPrecisionReadouts", 0);
2001 
2002     int dp = (detailedMode ? 6 : displayInfo.decimals);
2003 
2004     const char *lowersep = "<", *uppersep = ">";
2005 
2006     float mf = modulationDepth;
2007     float f = val.f;
2008     switch (displayType)
2009     {
2010     case Custom:
2011         // handled below
2012         break;
2013     case DelegatedToFormatter:
2014         // For now do LinearWithScale
2015     case LinearWithScale:
2016     {
2017         std::string u = displayInfo.unit;
2018         if (displayInfo.customFeatures & ParamDisplayFeatures::kUnitsAreSemitonesOrKeys)
2019         {
2020             u = "semitones";
2021             if (storage && !storage->isStandardTuning &&
2022                 storage->tuningApplicationMode == SurgeStorage::RETUNE_ALL)
2023                 u = "keys";
2024         }
2025 
2026         if (displayInfo.customFeatures & ParamDisplayFeatures::kScaleBasedOnIsBiPolar)
2027         {
2028             if (!is_bipolar())
2029             {
2030                 f = (f + 1) * 0.5;
2031                 mf = mf * 0.5;
2032             }
2033         }
2034         if (can_extend_range())
2035         {
2036             f = get_extended(f);
2037             // mf is handed to me extended already
2038         }
2039         if (can_be_absolute() && absolute)
2040         {
2041             f = displayInfo.absoluteFactor * f;
2042             mf = displayInfo.absoluteFactor * mf;
2043             u = displayInfo.absoluteUnit;
2044         }
2045         f *= displayInfo.scale;
2046         mf *= displayInfo.scale;
2047         switch (displaymode)
2048         {
2049         case TypeIn:
2050             snprintf(txt, TXT_SIZE, "%.*f %s", dp, mf, u.c_str());
2051             return;
2052         case Menu:
2053             if (isBipolar)
2054                 snprintf(txt, TXT_SIZE, "%s %.*f %s", (mf >= 0 ? "+/-" : "-/+"), dp, fabs(mf),
2055                          u.c_str());
2056             else
2057                 snprintf(txt, TXT_SIZE, "%.*f %s", dp, mf, u.c_str());
2058             return;
2059             break;
2060         case InfoWindow:
2061         {
2062             if (isBipolar)
2063             {
2064                 if (iw)
2065                 {
2066 #define ITXT_SIZE 1024
2067                     char itxt[ITXT_SIZE];
2068                     snprintf(itxt, ITXT_SIZE, "%.*f %s", dp, f, u.c_str());
2069                     iw->val = itxt;
2070                     snprintf(itxt, ITXT_SIZE, "%.*f", dp, f + mf);
2071                     iw->valplus = itxt;
2072                     snprintf(itxt, ITXT_SIZE, "%.*f", dp, f - mf);
2073                     iw->valminus = itxt;
2074                     snprintf(itxt, ITXT_SIZE, "%s%.*f", (mf > 0 ? "+" : ""), dp, +mf);
2075                     iw->dvalplus = itxt;
2076                     snprintf(itxt, ITXT_SIZE, "%s%.*f", (mf < 0 ? "+" : ""), dp, -mf);
2077                     iw->dvalminus = itxt;
2078                 }
2079                 snprintf(txt, TXT_SIZE, "%.*f %s %.*f %s %.*f %s", dp, f - mf, lowersep, dp, f,
2080                          uppersep, dp, f + mf, u.c_str());
2081             }
2082             else
2083             {
2084                 if (iw)
2085                 {
2086                     char itxt[ITXT_SIZE];
2087                     snprintf(itxt, ITXT_SIZE, "%.*f %s", dp, f, u.c_str());
2088                     iw->val = itxt;
2089                     snprintf(itxt, ITXT_SIZE, "%.*f", dp, f + mf);
2090                     iw->valplus = itxt;
2091                     iw->valminus = "";
2092                     snprintf(itxt, ITXT_SIZE, "%s%.*f", (mf > 0 ? "+" : ""), dp, mf);
2093                     iw->dvalplus = itxt;
2094                     iw->dvalminus = "";
2095                 }
2096                 snprintf(txt, TXT_SIZE, "%.*f %s %.*f %s", dp, f, uppersep, dp, f + mf, u.c_str());
2097             }
2098             return;
2099             break;
2100         }
2101         }
2102 
2103         break;
2104     }
2105     case ATwoToTheBx:
2106     {
2107         if (temposync)
2108         {
2109             dp = (detailedMode ? 6 : 2);
2110 
2111             switch (displaymode)
2112             {
2113             case TypeIn:
2114                 snprintf(txt, TXT_SIZE, "%.*f %c", dp, 100.f * modulationDepth, '%');
2115                 break;
2116             case Menu:
2117                 snprintf(txt, TXT_SIZE, "%s%.*f %s", (modulationDepth > 0) ? "+" : "", dp,
2118                          modulationDepth * 100, "%");
2119                 break;
2120             case InfoWindow:
2121                 if (iw)
2122                 {
2123                     iw->val = tempoSyncNotationValue(val.f);
2124 
2125                     char ltxt[TXT_SIZE];
2126                     snprintf(ltxt, TXT_SIZE, "%.*f %c", dp, 100.f * modulationDepth, '%');
2127                     iw->dvalplus = ltxt;
2128                     snprintf(ltxt, TXT_SIZE, "%.*f %c", dp, -100.f * modulationDepth, '%');
2129                     iw->dvalminus = ltxt;
2130                     iw->valplus = iw->dvalplus;
2131                     iw->valminus = iw->dvalminus;
2132                 }
2133                 break;
2134             }
2135         }
2136         else
2137         {
2138             float v = displayInfo.a * powf(2.0f, displayInfo.b * val.f);
2139             float mp = displayInfo.a * powf(2.0f, (val.f + modulationDepth) * displayInfo.b);
2140             float mn = displayInfo.a * powf(2.0f, (val.f - modulationDepth) * displayInfo.b);
2141 
2142             if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMinValue)
2143             {
2144                 if (val.f <= val_min.f)
2145                     v = displayInfo.minLabelValue;
2146                 ;
2147                 if (val.f - modulationDepth <= val_min.f)
2148                     mn = displayInfo.minLabelValue;
2149                 if (val.f + modulationDepth <= val_min.f)
2150                     mp = displayInfo.minLabelValue;
2151             }
2152 
2153             if (displayInfo.modulationCap > 0)
2154             {
2155                 mp = std::min(mp, displayInfo.modulationCap);
2156                 mn = std::min(mn, displayInfo.modulationCap);
2157             }
2158 
2159             std::string u = displayInfo.unit;
2160             if (displayInfo.customFeatures & ParamDisplayFeatures::kUnitsAreSemitonesOrKeys)
2161             {
2162                 u = "semitones";
2163                 if (storage && !storage->isStandardTuning &&
2164                     storage->tuningApplicationMode == SurgeStorage::RETUNE_ALL)
2165                     u = "keys";
2166             }
2167 
2168             switch (displaymode)
2169             {
2170             case TypeIn:
2171                 snprintf(txt, TXT_SIZE, "%.*f %s", dp, mp - v, u.c_str());
2172                 break;
2173             case Menu:
2174                 // if( isBipolar )
2175                 //   snprintf( txt, TXT_SIZE, "%.*f / %.*f %s", dp, mn-v, dp, mp-v, u.c_str() );
2176                 // else
2177                 snprintf(txt, TXT_SIZE, "%s%.*f %s", (mp - v > 0) ? "+" : "", dp, mp - v,
2178                          u.c_str());
2179                 if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMaxString &&
2180                     mp > val_max.f)
2181                 {
2182                     snprintf(txt, TXT_SIZE, "%s", displayInfo.maxLabel);
2183                 }
2184 
2185                 break;
2186             case InfoWindow:
2187             {
2188                 if (isBipolar)
2189                 {
2190                     if (iw)
2191                     {
2192                         char itxt[ITXT_SIZE];
2193                         snprintf(itxt, ITXT_SIZE, "%.*f %s", dp, v, u.c_str());
2194                         iw->val = itxt;
2195                         snprintf(itxt, ITXT_SIZE, "%.*f", dp, mp);
2196                         iw->valplus = itxt;
2197                         snprintf(itxt, ITXT_SIZE, "%.*f", dp, mn);
2198                         iw->valminus = itxt;
2199                         snprintf(itxt, ITXT_SIZE, "%s%.*f", (mp - v > 0 ? "+" : ""), dp, mp - v);
2200                         iw->dvalplus = itxt;
2201                         snprintf(itxt, ITXT_SIZE, "%s%.*f", (mn - v > 0 ? "+" : ""), dp, mn - v);
2202                         iw->dvalminus = itxt;
2203 
2204                         if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMaxString)
2205                         {
2206                             if (v >= val_max.f)
2207                                 iw->val = displayInfo.maxLabel;
2208                             if (val.f + modulationDepth >= val_max.f)
2209                                 iw->valplus = displayInfo.maxLabel;
2210                             if (val.f - modulationDepth >= val_max.f)
2211                                 iw->valminus = displayInfo.maxLabel;
2212                             if (val.f + modulationDepth >= val_max.f)
2213                                 iw->dvalplus = displayInfo.maxLabel;
2214                             if (val.f - modulationDepth >= val_max.f)
2215                                 iw->dvalminus = displayInfo.maxLabel;
2216                         }
2217                     }
2218 
2219                     snprintf(txt, TXT_SIZE, "%.*f %s %.*f %s %.*f %s", dp, mn, lowersep, dp, v,
2220                              uppersep, dp, mp, u.c_str());
2221                 }
2222                 else
2223                 {
2224                     if (iw)
2225                     {
2226                         char itxt[ITXT_SIZE];
2227                         snprintf(itxt, ITXT_SIZE, "%.*f %s", dp, v, u.c_str());
2228                         iw->val = itxt;
2229                         snprintf(itxt, ITXT_SIZE, "%.*f", dp, mn);
2230                         iw->valplus = itxt;
2231                         iw->valminus = "";
2232                         snprintf(itxt, ITXT_SIZE, "%s%.*f", (mp - v > 0 ? "+" : ""), dp, mp - v);
2233                         iw->dvalplus = itxt;
2234                         iw->dvalminus = "";
2235                     }
2236 
2237                     snprintf(txt, TXT_SIZE, "%.*f %s %.*f %s", dp, v, uppersep, dp, mp, u.c_str());
2238                 }
2239                 break;
2240             }
2241             }
2242             return;
2243         }
2244 
2245         break;
2246     }
2247     case Decibel:
2248     {
2249         float v = amp_to_db(val.f);
2250         float mp = amp_to_db(val.f + modulationDepth);
2251         float mn = amp_to_db(val.f - modulationDepth);
2252 
2253         char posval[TXT_SIZE];
2254         char negval[TXT_SIZE];
2255         char val[TXT_SIZE];
2256 
2257         if (mn <= -192.f)
2258             snprintf(negval, TXT_SIZE, "-inf %s", displayInfo.unit);
2259         else
2260             snprintf(negval, TXT_SIZE, "%.*f %s", dp, mn, displayInfo.unit);
2261 
2262         if (mp <= -192.f)
2263             snprintf(posval, TXT_SIZE, "-inf %s", displayInfo.unit);
2264         else
2265             snprintf(posval, TXT_SIZE, "%.*f %s", dp, mp, displayInfo.unit);
2266 
2267         if (v <= -192.f)
2268             snprintf(val, TXT_SIZE, "-inf %s", displayInfo.unit);
2269         else
2270             snprintf(val, TXT_SIZE, "%.*f %s", dp, v, displayInfo.unit);
2271 
2272         switch (displaymode)
2273         {
2274         case TypeIn:
2275         case Menu:
2276             snprintf(txt, TXT_SIZE, "%.*f %s", dp,
2277                      limit_range(mp, -192.f, 500.f) - limit_range(v, -192.f, 500.f),
2278                      displayInfo.unit);
2279             break;
2280         case InfoWindow:
2281             if (iw)
2282             {
2283                 iw->val = val;
2284                 iw->valplus = posval;
2285                 iw->valminus = isBipolar ? negval : "";
2286 
2287                 char dtxt[TXT_SIZE];
2288                 snprintf(dtxt, TXT_SIZE, "%s%.*f %s", (mp - v > 0 ? "+" : ""), dp,
2289                          limit_range(mp, -192.f, 500.f) - limit_range(v, -192.f, 500.f),
2290                          displayInfo.unit);
2291                 iw->dvalplus = dtxt;
2292 
2293                 snprintf(dtxt, TXT_SIZE, "%s%.*f %s", (mn - v > 0 ? "+" : ""), dp,
2294                          limit_range(mn, -192.f, 500.f) - limit_range(v, -192.f, 500.f),
2295                          displayInfo.unit);
2296                 iw->dvalminus = isBipolar ? dtxt : "";
2297             }
2298             if (isBipolar)
2299             {
2300                 snprintf(txt, TXT_SIZE, "%s %s %s %s %s dB", negval, lowersep, val, uppersep,
2301                          posval);
2302             }
2303             else
2304             {
2305                 snprintf(txt, TXT_SIZE, "%s %s %s dB", val, uppersep, posval);
2306             }
2307             break;
2308         }
2309         return;
2310         break;
2311     }
2312     }
2313 
2314     switch (ctrltype)
2315     {
2316     case ct_fmratio:
2317     {
2318         if (absolute)
2319         {
2320             float bpv = (f - 16.0) / 16.0;
2321             float bpu = (f + modulationDepth - 16.0) / 16.0;
2322             float bpd = (f - modulationDepth - 16.0) / 16.0;
2323             float mul = 69;
2324             float note = 69 + mul * bpv;
2325             float noteup = 69 + mul * bpu;
2326             float notedn = 60 + mul * bpd;
2327 
2328             auto freq = 440.0 * pow(2.0, (note - 69.0) / 12);
2329             auto frequp = 440.0 * pow(2.0, (noteup - 69.0) / 12);
2330             auto freqdn = 440.0 * pow(2.0, (notedn - 69.0) / 12);
2331             int dp = (detailedMode ? 6 : 2);
2332 
2333             switch (displaymode)
2334             {
2335             case TypeIn:
2336             case Menu:
2337                 snprintf(txt, TXT_SIZE, "%.*f Hz", dp, frequp - freq);
2338                 break;
2339             case InfoWindow:
2340                 if (iw)
2341                 {
2342                     auto put = [dp](std::string &tg, float val) {
2343                         char txt[TXT_SIZE];
2344                         snprintf(txt, TXT_SIZE, "%.*f Hz", dp, val);
2345                         tg = txt;
2346                     };
2347                     put(iw->val, freq);
2348                     put(iw->valplus, frequp);
2349                     put(iw->valminus, freqdn);
2350                     put(iw->dvalplus, frequp - freq);
2351                     put(iw->dvalminus, freq - freqdn);
2352                     snprintf(txt, TXT_SIZE, "%.*f Hz %.*f Hz %.*f Hz", dp, freqdn, dp, freq, dp,
2353                              frequp);
2354                     break;
2355                 }
2356             }
2357             return;
2358         }
2359         float mf = modulationDepth;
2360         // OK so this is already handed to us extended and this one is wierd so
2361         auto qq = mf;
2362         if (extend_range)
2363         {
2364             if (mf < 0)
2365             {
2366                 qq = mf + 1;
2367             }
2368             else
2369             {
2370                 qq = mf - 1;
2371             }
2372             qq = (qq + 31) / 64;
2373         }
2374 
2375         float exmf = qq;
2376         int dp = (detailedMode ? 6 : 2);
2377         switch (displaymode)
2378         {
2379         case TypeIn:
2380             if (extend_range)
2381             {
2382                 snprintf(txt, TXT_SIZE, "C : %.*f", dp, qq * 31 * 2);
2383             }
2384             else
2385             {
2386                 snprintf(txt, TXT_SIZE, "C : %.*f", dp, mf);
2387             }
2388             return;
2389             break;
2390         case Menu:
2391         {
2392             if (extend_range)
2393             {
2394                 if (isBipolar)
2395                 {
2396                     snprintf(txt, TXT_SIZE, "C : %s %.*f", (mf >= 0 ? "+/-" : "-/+"), dp,
2397                              fabs(qq * 31 * 2));
2398                 }
2399                 else
2400                 {
2401                     snprintf(txt, TXT_SIZE, "C : %.*f", dp, qq * 31 * 2);
2402                 }
2403             }
2404             else
2405             {
2406                 if (isBipolar)
2407                 {
2408                     snprintf(txt, TXT_SIZE, "C : %s %.*f", (mf >= 0 ? "+/-" : "-/+"), dp, fabs(mf));
2409                 }
2410                 else
2411                 {
2412                     snprintf(txt, TXT_SIZE, "C : %.*f", dp, mf);
2413                 }
2414             }
2415             return;
2416             break;
2417         }
2418         case InfoWindow:
2419             if (iw)
2420             {
2421                 if (extend_range)
2422                 {
2423                     char dtxt[TXT_SIZE];
2424                     float ev = get_extended(val.f);
2425                     if (ev < 0)
2426                     {
2427                         snprintf(dtxt, TXT_SIZE, "C : 1 / %.*f", dp, -ev);
2428                     }
2429                     else
2430                     {
2431                         snprintf(dtxt, TXT_SIZE, "C : %.*f", dp, ev);
2432                     }
2433                     iw->val = dtxt;
2434 
2435                     auto upval = get_extended(val.f + (qq * 32));
2436                     auto dnval = get_extended(val.f - (qq * 32));
2437 
2438                     if (upval < 0)
2439                         snprintf(dtxt, TXT_SIZE, "C : 1 / %.*f", dp, -upval);
2440                     else
2441                         snprintf(dtxt, TXT_SIZE, "C : %.*f", dp, upval);
2442                     iw->valplus = dtxt;
2443                     snprintf(dtxt, TXT_SIZE, "%.*f", dp, qq * 31 * 2);
2444                     iw->dvalplus = dtxt;
2445                     if (isBipolar)
2446                     {
2447                         if (dnval < 0)
2448                             snprintf(dtxt, TXT_SIZE, "C : 1/%.*f", dp, -dnval);
2449                         else
2450                             snprintf(dtxt, TXT_SIZE, "C : %.*f", dp, dnval);
2451                         iw->valminus = dtxt;
2452 
2453                         snprintf(dtxt, TXT_SIZE, "%.*f", dp, -(qq * 31 * 2));
2454                         iw->dvalminus = dtxt;
2455                     }
2456                 }
2457                 else
2458                 {
2459                     char dtxt[TXT_SIZE];
2460                     snprintf(dtxt, TXT_SIZE, "C : %.*f", dp, val.f);
2461                     iw->val = dtxt;
2462                     snprintf(dtxt, TXT_SIZE, "%.*f", dp, val.f + mf);
2463                     iw->valplus = dtxt;
2464                     snprintf(dtxt, TXT_SIZE, "%.*f", dp, mf);
2465                     iw->dvalplus = dtxt;
2466                     if (isBipolar)
2467                     {
2468                         snprintf(dtxt, TXT_SIZE, "%.*f", dp, val.f - mf);
2469                         iw->valminus = dtxt;
2470                         snprintf(dtxt, TXT_SIZE, "%.*f", dp, -mf);
2471                         iw->dvalminus = dtxt;
2472                     }
2473                 }
2474             }
2475             // not really used any more bot don't leave it uninit
2476             snprintf(txt, TXT_SIZE, "C: %.*f %s %.*f", 2, val.f, (mf >= 0 ? "+/-" : "-/+"), 2, mf);
2477             return;
2478             break;
2479         }
2480     }
2481     default:
2482     {
2483         if (temposync)
2484         {
2485             dp = (detailedMode ? 6 : 2);
2486 
2487             auto mp = modulationDepth;
2488             auto mn = -modulationDepth;
2489             switch (displaymode)
2490             {
2491             case TypeIn:
2492             {
2493                 snprintf(txt, TXT_SIZE, "%.*f %c", dp, 100.f * modulationDepth, '%');
2494                 break;
2495             }
2496             case Menu:
2497             {
2498                 if (isBipolar)
2499                 {
2500                     snprintf(txt, TXT_SIZE, "+/- %.*f %c", dp, 100.f * mp, '%');
2501                 }
2502                 else
2503                 {
2504                     snprintf(txt, TXT_SIZE, "%.*f %c", dp, 100.f * mp, '%');
2505                 }
2506                 break;
2507             }
2508             case InfoWindow:
2509             {
2510                 std::string vs = tempoSyncNotationValue(val.f);
2511                 if (isBipolar)
2512                 {
2513                     snprintf(txt, TXT_SIZE, "%.*f %s %s %s %.*f %c", dp, mn, lowersep, vs.c_str(),
2514                              uppersep, dp, mp, '%');
2515                 }
2516                 else
2517                 {
2518                     snprintf(txt, TXT_SIZE, "%s %s %.*f %c", vs.c_str(), uppersep, dp, mp, '%');
2519                 }
2520                 break;
2521             }
2522             }
2523         }
2524         else
2525         {
2526             float v = val.f * 100.f;
2527             float mp = (val.f + modulationDepth) * 100.f;
2528             float mn = (val.f - modulationDepth) * 100.f;
2529 
2530             switch (displaymode)
2531             {
2532             case TypeIn:
2533                 snprintf(txt, TXT_SIZE, "%.*f", dp, mp - v);
2534                 break;
2535             case Menu:
2536                 if (isBipolar)
2537                 {
2538                     snprintf(txt, TXT_SIZE, "%.*f ... %.*f %c", dp, mn, dp, mp, '%');
2539                 }
2540                 else
2541                     snprintf(txt, TXT_SIZE, "%.*f ... %.*f %c", dp, v, dp, mp, '%');
2542                 break;
2543             case InfoWindow:
2544             {
2545                 if (isBipolar)
2546                 {
2547                     snprintf(txt, TXT_SIZE, "%.*f %s %.*f %s %.*f %c", dp, mn, lowersep, dp, v,
2548                              uppersep, dp, mp, '%');
2549                 }
2550                 else
2551                     snprintf(txt, TXT_SIZE, "%.*f %s %.*f %c", dp, v, uppersep, dp, mp, '%');
2552                 break;
2553             }
2554             }
2555         }
2556         break;
2557     }
2558     }
2559 }
2560 
quantize_modulation(float inputval)2561 float Parameter::quantize_modulation(float inputval)
2562 {
2563     float res;
2564 
2565     if (temposync)
2566     {
2567         auto sv = inputval * (val_max.f - val_min.f); // this is now a 0 -> 1 for 0 -> 100%
2568         res = (float)((int)(sv * 10.0) / 10.f);
2569 
2570         return res / (val_max.f - val_min.f);
2571     }
2572 
2573     switch (displayType)
2574     {
2575     case Custom:
2576         // handled below but let's set up a good default
2577         res = (float)(round(inputval * 100) / 100);
2578         break;
2579     case DelegatedToFormatter:
2580         // fall back
2581     case LinearWithScale:
2582     {
2583         float ext_mul = (can_extend_range() && extend_range) ? displayInfo.extendFactor : 1.0;
2584         float abs_mul = (can_be_absolute() && absolute) ? displayInfo.absoluteFactor : 1.0;
2585         float factor = ext_mul * abs_mul;
2586         float tempval = (val_max.f - val_min.f) * displayInfo.scale * factor;
2587 
2588         res = (float)((int)(inputval * tempval) / tempval);
2589 
2590         break;
2591     }
2592     case Decibel:
2593     {
2594         float scaledval = val.f * (1.f / val_max.f);
2595         float v = amp_to_db(scaledval);
2596         float vmod = amp_to_db(scaledval + inputval);
2597         float floorvmod = floor(vmod - v) + v;
2598 
2599         // so we want to find a new integer value which satisfies:
2600         // 18 * log2(oldval + newval) = floorvmod, or
2601         // 2^(floorvmod / 18) - oldval = newval
2602 
2603         res = powf(2.f, floorvmod / 18.f) - scaledval;
2604 
2605         break;
2606     }
2607     case ATwoToTheBx:
2608     {
2609         // for these control types only snap to semitones
2610         switch (ctrltype)
2611         {
2612         case ct_freq_hpf:
2613         case ct_freq_audible:
2614         case ct_freq_audible_deactivatable:
2615         case ct_freq_audible_with_tunability:
2616         case ct_freq_audible_with_very_low_lowerbound:
2617         case ct_freq_reson_band1:
2618         case ct_freq_reson_band2:
2619         case ct_freq_reson_band3:
2620         case ct_freq_vocoder_low:
2621         case ct_freq_vocoder_high:
2622         case ct_freq_ringmod:
2623         {
2624             auto range = val_max.f - val_min.f;
2625             return floor(inputval * range) / range;
2626             break;
2627         }
2628         }
2629 
2630         /*
2631          * OK so the display value is A e^val and we want to quantize in that space and then
2632          * find the res. So first of all let's find the endpoint. Remember this calculation
2633          * is basically a 2^bx
2634          */
2635         auto mdepth = inputval * (val_max.f - val_min.f);
2636         auto center = displayInfo.a * pow(2.0, displayInfo.b * val.f);
2637         auto modpoint = displayInfo.a * pow(2.0, displayInfo.b * (val.f + mdepth));
2638         auto moddist = modpoint - center;
2639 
2640         /*
2641          * OK so now we want the mod distance to be quantized but quantized in units of
2642          * what? Well let's use a simple heuristic that we are roughly 5% of our center
2643          * as a tick but, you know, nice and integral. This method has the problem that
2644          * the tick size gets 'smaller' as you move up. You also need to scale the integrality
2645          * depending on starting point.
2646          */
2647         float scaleFactor = 1;
2648 
2649         if (center > 100)
2650         {
2651             scaleFactor = 0.1;
2652         }
2653         if (center < 10)
2654         {
2655             scaleFactor = 10;
2656         }
2657         if (center < 1)
2658         {
2659             scaleFactor = 100;
2660         }
2661 
2662         auto stepsize = abs(ceil(0.05 * center * scaleFactor) / scaleFactor);
2663         moddist = round(moddist / stepsize) * stepsize;
2664         auto modresult = center + moddist;
2665 
2666         if (modresult <= 0)
2667         {
2668             res = -1.f;
2669         }
2670         else
2671         {
2672             auto modresult_exponent = log2(modresult / displayInfo.a) / displayInfo.b; // = val + d
2673             res = limit_range((float)(modresult_exponent - val.f) / (val_max.f - val_min.f), -1.f,
2674                               1.f);
2675         }
2676 
2677         break;
2678     }
2679     default:
2680     {
2681         float tempval = (val_max.f - val_min.f) * displayInfo.scale;
2682 
2683         res = (float)((int)(inputval * tempval) / tempval);
2684 
2685         break;
2686     }
2687     }
2688 
2689     return res;
2690 }
2691 
get_display_alt(char * txt,bool external,float ef)2692 void Parameter::get_display_alt(char *txt, bool external, float ef)
2693 {
2694 
2695     txt[0] = 0;
2696     switch (ctrltype)
2697     {
2698     case ct_freq_hpf:
2699     case ct_freq_audible:
2700     case ct_freq_audible_deactivatable:
2701     case ct_freq_audible_with_tunability:
2702     case ct_freq_audible_with_very_low_lowerbound:
2703     case ct_freq_reson_band1:
2704     case ct_freq_reson_band2:
2705     case ct_freq_reson_band3:
2706     case ct_freq_vocoder_low:
2707     case ct_freq_vocoder_high:
2708     case ct_freq_ringmod:
2709     {
2710         float f = val.f;
2711         int i_value = round(f) + ((ctrltype != ct_freq_ringmod) ? 69 : 0);
2712         int oct_offset = 1;
2713         char notename[16];
2714 
2715         if (storage)
2716         {
2717             oct_offset = Surge::Storage::getUserDefaultValue(storage, "middleC", 1);
2718         }
2719 
2720         snprintf(txt, TXT_SIZE, "~%s", get_notename(notename, i_value, oct_offset));
2721 
2722         break;
2723     }
2724     case ct_flangerpitch:
2725     {
2726         float f = val.f;
2727         int i_value = (int)(f);
2728         int oct_offset = 1;
2729         char notename[16];
2730 
2731         if (storage)
2732         {
2733             oct_offset = Surge::Storage::getUserDefaultValue(storage, "middleC", 1);
2734         }
2735 
2736         snprintf(txt, TXT_SIZE, "~%s", get_notename(notename, i_value, oct_offset));
2737 
2738         break;
2739     }
2740     case ct_countedset_percent:
2741         if (user_data != nullptr)
2742         {
2743             // We check when set so the reinterpret cast is safe and fast
2744             float f = val.f;
2745             CountedSetUserData *cs = reinterpret_cast<CountedSetUserData *>(user_data);
2746             auto count = cs->getCountedSetSize();
2747             auto tl = count * f;
2748             snprintf(txt, TXT_SIZE, "%.2f / %d", tl, count);
2749         }
2750 
2751         break;
2752     case ct_alias_mask:
2753     {
2754         int bits = 8;
2755         int mask = 1 << bits;
2756         std::string bin;
2757 
2758         while (bits--)
2759         {
2760             mask >>= 1;
2761             bin += ((int)(val.f * 255) & mask) ? "1" : "0";
2762         }
2763 
2764         snprintf(txt, TXT_SIZE, "%s", bin.c_str());
2765         break;
2766     }
2767     }
2768 }
2769 
get_display(char * txt,bool external,float ef)2770 void Parameter::get_display(char *txt, bool external, float ef)
2771 {
2772     if (ctrltype == ct_none)
2773     {
2774         snprintf(txt, TXT_SIZE, "-");
2775         return;
2776     }
2777 
2778     int i;
2779     float f;
2780     bool b;
2781 
2782     int detailedMode = 0;
2783 
2784     if (storage)
2785         detailedMode = Surge::Storage::getUserDefaultValue(storage, "highPrecisionReadouts", 0);
2786 
2787     switch (valtype)
2788     {
2789     case vt_float:
2790         if (external)
2791         {
2792             f = ef * (val_max.f - val_min.f) + val_min.f;
2793         }
2794         else
2795         {
2796             f = val.f;
2797         }
2798 
2799         switch (displayType)
2800         {
2801         case Custom:
2802             // Custom cases are handled below
2803             break;
2804         case DelegatedToFormatter:
2805         {
2806             auto ef = dynamic_cast<ParameterExternalFormatter *>(user_data);
2807             if (ef)
2808             {
2809                 // parameter called 'len' not 'size', be on the safe side here, do - 1.
2810                 // It used to say just '64' anyway.
2811                 ef->formatValue(f, txt, TXT_SIZE - 1);
2812                 return;
2813             }
2814             // We do not break on purpose here. DelegatedToFormatter falls back to Linear with Scale
2815         }
2816         case LinearWithScale:
2817         {
2818             std::string u = displayInfo.unit;
2819             if (displayInfo.customFeatures & ParamDisplayFeatures::kUnitsAreSemitonesOrKeys)
2820             {
2821                 u = "semitones";
2822                 if (storage && !storage->isStandardTuning &&
2823                     storage->tuningApplicationMode == SurgeStorage::RETUNE_ALL)
2824                     u = "keys";
2825             }
2826             if (displayInfo.customFeatures & ParamDisplayFeatures::kScaleBasedOnIsBiPolar)
2827             {
2828                 if (!is_bipolar())
2829                 {
2830                     f = (f + 1) * 0.5;
2831                 }
2832             }
2833             if (can_extend_range())
2834             {
2835                 f = get_extended(f);
2836             }
2837 
2838             if (can_be_absolute() && absolute)
2839             {
2840                 f = displayInfo.absoluteFactor * f;
2841                 u = displayInfo.absoluteUnit;
2842             }
2843             snprintf(txt, TXT_SIZE, "%.*f %s", (detailedMode ? 6 : displayInfo.decimals),
2844                      displayInfo.scale * f, u.c_str());
2845 
2846             if (f >= val_max.f &&
2847                 (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMaxString))
2848             {
2849                 strxcpy(txt, displayInfo.maxLabel, TXT_SIZE);
2850             }
2851             if (f <= val_min.f &&
2852                 (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMinString))
2853             {
2854                 strxcpy(txt, displayInfo.minLabel, TXT_SIZE);
2855             }
2856             if (f == val_default.f &&
2857                 (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomDefaultString))
2858             {
2859                 strxcpy(txt, displayInfo.defLabel, TXT_SIZE);
2860             }
2861             return;
2862             break;
2863         }
2864         case ATwoToTheBx:
2865         {
2866             if (can_temposync() && temposync)
2867             {
2868                 std::string res =
2869                     tempoSyncNotationValue(displayInfo.tempoSyncNotationMultiplier * f);
2870                 snprintf(txt, TXT_SIZE, "%s", res.c_str());
2871                 return;
2872             }
2873             if (can_extend_range() && extend_range)
2874             {
2875                 f = get_extended(f);
2876             }
2877             std::string u = displayInfo.unit;
2878 
2879             if (displayInfo.customFeatures & ParamDisplayFeatures::kUnitsAreSemitonesOrKeys)
2880             {
2881                 u = "semitones";
2882                 if (storage && !storage->isStandardTuning &&
2883                     storage->tuningApplicationMode == SurgeStorage::RETUNE_ALL)
2884                     u = "keys";
2885             }
2886 
2887             float dval = displayInfo.a * powf(2.0f, f * displayInfo.b);
2888             if (f >= val_max.f)
2889             {
2890                 if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMaxString)
2891                 {
2892                     snprintf(txt, TXT_SIZE, "%s", displayInfo.maxLabel);
2893                     return;
2894                 }
2895                 if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMaxValue)
2896                 {
2897                     dval = displayInfo.maxLabelValue;
2898                 }
2899             }
2900             if (f <= val_min.f)
2901             {
2902                 if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMinString)
2903                 {
2904                     snprintf(txt, TXT_SIZE, "%s", displayInfo.minLabel);
2905                     return;
2906                 }
2907                 if (displayInfo.customFeatures & ParamDisplayFeatures::kHasCustomMinValue)
2908                 {
2909                     dval = displayInfo.minLabelValue;
2910                 }
2911             }
2912             snprintf(txt, TXT_SIZE, "%.*f %s", (detailedMode ? 6 : displayInfo.decimals), dval,
2913                      u.c_str());
2914             return;
2915             break;
2916         }
2917         case Decibel:
2918         {
2919             if (f == 0)
2920                 snprintf(txt, TXT_SIZE, "-inf dB");
2921             else
2922                 snprintf(txt, TXT_SIZE, "%.*f dB", (detailedMode ? 6 : 2), amp_to_db(f));
2923             return;
2924             break;
2925         }
2926         }
2927 
2928         switch (ctrltype)
2929         {
2930         case ct_fmratio:
2931         {
2932             if (absolute)
2933             {
2934                 /*
2935                  * OK so I am 0 to 32. So let's define a note
2936                  */
2937                 float bpv = (f - 16.0) / 16.0;
2938                 auto note = 69 + 69 * bpv;
2939                 auto freq = 440.0 * pow(2.0, (note - 69.0) / 12);
2940                 snprintf(txt, TXT_SIZE, "%.*f Hz", (detailedMode ? 6 : 2), freq);
2941             }
2942             else
2943             {
2944                 auto q = get_extended(f);
2945 
2946                 if (extend_range && q < 0)
2947                 {
2948                     snprintf(txt, TXT_SIZE, "C : 1 / %.*f", (detailedMode ? 6 : 2),
2949                              -get_extended(f));
2950                 }
2951                 else
2952                 {
2953                     snprintf(txt, TXT_SIZE, "C : %.*f", (detailedMode ? 6 : 2), get_extended(f));
2954                 }
2955             }
2956             break;
2957         }
2958         case ct_chow_ratio:
2959         {
2960             snprintf(txt, TXT_SIZE, "1 : %.*f", (detailedMode ? 6 : 2), f);
2961             break;
2962         }
2963         case ct_float_toggle:
2964         {
2965             snprintf(txt, TXT_SIZE, f > 0.5 ? "On" : "Off");
2966             break;
2967         }
2968         default:
2969             snprintf(txt, TXT_SIZE, "%.*f", (detailedMode ? 6 : 2), f);
2970             break;
2971         }
2972         break;
2973     case vt_int:
2974     {
2975         if (external)
2976             i = Parameter::intUnscaledFromFloat(ef, val_max.i, val_min.i);
2977         else
2978             i = val.i;
2979 
2980         if (displayType == DelegatedToFormatter)
2981         {
2982             float fv = Parameter::intScaledToFloat(i, val_max.i, val_min.i);
2983 
2984             char vt[TXT_SIZE];
2985 
2986             auto ef = dynamic_cast<ParameterExternalFormatter *>(user_data);
2987             if (ef)
2988             {
2989                 ef->formatValue(fv, vt, TXT_SIZE - 1);
2990                 snprintf(txt, TXT_SIZE, "%s", vt);
2991                 return;
2992             }
2993         }
2994         switch (ctrltype)
2995         {
2996         case ct_midikey_or_channel:
2997         {
2998             auto sm = storage->getPatch().scenemode.val.i;
2999 
3000             if (sm == sm_chsplit)
3001             {
3002                 snprintf(txt, TXT_SIZE, "Channel %d", (val.i / 8) + 1);
3003                 break;
3004             }
3005         }
3006         case ct_midikey:
3007         {
3008             int oct_offset = 1;
3009             char notename[16];
3010 
3011             if (storage)
3012             {
3013                 oct_offset = Surge::Storage::getUserDefaultValue(storage, "middleC", 1);
3014             }
3015 
3016             snprintf(txt, TXT_SIZE, "%s", get_notename(notename, val.i, oct_offset));
3017 
3018             break;
3019         }
3020         case ct_osctype:
3021             snprintf(txt, TXT_SIZE, "%s", osc_type_names[limit_range(i, 0, (int)n_osc_types - 1)]);
3022             break;
3023         case ct_wt2window:
3024             snprintf(txt, TXT_SIZE, "%s", window_names[limit_range(i, 0, 8)]);
3025             break;
3026         case ct_osccount:
3027         case ct_osccountWT:
3028             snprintf(txt, TXT_SIZE, "%d voice%s", i, (i > 1 ? "s" : ""));
3029             break;
3030         case ct_fxtype:
3031             snprintf(txt, TXT_SIZE, "%s", fx_type_names[limit_range(i, 0, (int)n_fx_types - 1)]);
3032             break;
3033         case ct_reverbshape:
3034             snprintf(txt, TXT_SIZE, "Type %d", i + 1);
3035             break;
3036         case ct_fxbypass:
3037             snprintf(txt, TXT_SIZE, "%s", fxbypass_names[limit_range(i, 0, (int)n_fx_bypass - 1)]);
3038             break;
3039         case ct_filtertype:
3040             snprintf(txt, TXT_SIZE, "%s", fut_names[limit_range(i, 0, (int)n_fu_types - 1)]);
3041             break;
3042         case ct_filtersubtype:
3043         {
3044             auto &patch = storage->getPatch();
3045 
3046             for (int scene = 0; scene < n_scenes; ++scene)
3047                 for (int unit = 0; unit < n_filterunits_per_scene; ++unit)
3048                     if (id == patch.scene[scene].filterunit[unit].subtype.id)
3049                     {
3050                         int type = patch.scene[scene].filterunit[unit].type.val.i;
3051                         fu_type fType = (fu_type)type;
3052                         if (i >= fut_subcount[type])
3053                         {
3054                             snprintf(txt, TXT_SIZE, "None");
3055                         }
3056                         else
3057                             switch (fType)
3058                             {
3059                             case fut_lpmoog:
3060                             case fut_diode:
3061                                 snprintf(txt, TXT_SIZE, "%s", fut_ldr_subtypes[i]);
3062                                 break;
3063                             case fut_bp12:
3064                             case fut_bp24:
3065                                 snprintf(txt, TXT_SIZE, "%s", fut_bp_subtypes[i]);
3066                                 break;
3067                             case fut_notch12:
3068                             case fut_notch24:
3069                             case fut_apf:
3070                                 snprintf(txt, TXT_SIZE, "%s", fut_notch_subtypes[i]);
3071                                 break;
3072                             case fut_comb_pos:
3073                             case fut_comb_neg:
3074                                 snprintf(txt, TXT_SIZE, "%s", fut_comb_subtypes[i]);
3075                                 break;
3076                             case fut_vintageladder:
3077                                 snprintf(txt, TXT_SIZE, "%s", fut_vintageladder_subtypes[i]);
3078                                 break;
3079                             case fut_obxd_2pole_lp:
3080                             case fut_obxd_2pole_hp:
3081                             case fut_obxd_2pole_n:
3082                             case fut_obxd_2pole_bp:
3083                                 snprintf(txt, TXT_SIZE, "%s", fut_obxd_2p_subtypes[i]);
3084                                 break;
3085                             case fut_obxd_4pole:
3086                                 snprintf(txt, TXT_SIZE, "%s", fut_obxd_4p_subtypes[i]);
3087                                 break;
3088                             case fut_k35_lp:
3089                             case fut_k35_hp:
3090                                 snprintf(txt, TXT_SIZE, "%s", fut_k35_subtypes[i]);
3091                                 break;
3092                             case fut_cutoffwarp_lp:
3093                             case fut_cutoffwarp_hp:
3094                             case fut_cutoffwarp_n:
3095                             case fut_cutoffwarp_bp:
3096                             case fut_cutoffwarp_ap:
3097                             case fut_resonancewarp_lp:
3098                             case fut_resonancewarp_hp:
3099                             case fut_resonancewarp_n:
3100                             case fut_resonancewarp_bp:
3101                             case fut_resonancewarp_ap:
3102                                 // "i & 3" selects the lower two bits that represent the stage
3103                                 // count.
3104                                 // "(i >> 2) & 3" selects the next two bits that represent the
3105                                 // saturator.
3106                                 snprintf(txt, TXT_SIZE, "%s %s", fut_nlf_subtypes[i & 3],
3107                                          fut_nlf_saturators[(i >> 2) & 3]);
3108                                 break;
3109                             // don't default any more so compiler catches new ones we add
3110                             case fut_none:
3111                             case fut_lp12:
3112                             case fut_lp24:
3113                             case fut_hp12:
3114                             case fut_hp24:
3115                             case fut_SNH:
3116                                 snprintf(txt, TXT_SIZE, "%s", fut_def_subtypes[i]);
3117                                 break;
3118 
3119                             case n_fu_types:
3120                                 snprintf(txt, TXT_SIZE, "ERROR");
3121                                 break;
3122                             }
3123                     }
3124             break;
3125         }
3126         case ct_wstype:
3127             snprintf(txt, TXT_SIZE, "%s", wst_names[limit_range(i, 0, (int)n_ws_types - 1)]);
3128             break;
3129         case ct_envmode:
3130             snprintf(txt, TXT_SIZE, "%s", em_names[limit_range(i, 0, (int)n_env_modes - 1)]);
3131             break;
3132         case ct_fbconfig:
3133             snprintf(txt, TXT_SIZE, "%s", fbc_names[limit_range(i, 0, (int)n_filter_configs - 1)]);
3134             break;
3135         case ct_fmconfig:
3136             snprintf(txt, TXT_SIZE, "%s", fmr_names[limit_range(i, 0, (int)n_fm_routings - 1)]);
3137             break;
3138         case ct_lfotype:
3139             snprintf(txt, TXT_SIZE, "%s", lt_names[limit_range(i, 0, (int)n_lfo_types - 1)]);
3140             break;
3141         case ct_scenemode:
3142             snprintf(txt, TXT_SIZE, "%s",
3143                      scene_mode_names[limit_range(i, 0, (int)n_scene_modes - 1)]);
3144             break;
3145         case ct_polymode:
3146             snprintf(txt, TXT_SIZE, "%s",
3147                      play_mode_names[limit_range(i, 0, (int)n_play_modes - 1)]);
3148             break;
3149         case ct_lfotrigmode:
3150             snprintf(txt, TXT_SIZE, "%s",
3151                      lfo_trigger_mode_names[limit_range(i, 0, (int)n_lfo_trigger_modes - 1)]);
3152             break;
3153         case ct_character:
3154             snprintf(txt, TXT_SIZE, "%s",
3155                      character_names[limit_range(i, 0, (int)n_character_modes - 1)]);
3156             break;
3157         case ct_fmratio_int:
3158             snprintf(txt, TXT_SIZE, "C : %d", i);
3159             break;
3160         case ct_phaser_stages:
3161             if (i == 1)
3162             {
3163                 snprintf(txt, TXT_SIZE, "Legacy (4 stages)");
3164             }
3165             else
3166             {
3167                 snprintf(txt, TXT_SIZE, "%d", i);
3168             }
3169             break;
3170 
3171         case ct_envshape:
3172             switch (i)
3173             {
3174             case 0:
3175                 snprintf(txt, TXT_SIZE, "Linear");
3176                 break;
3177             case 1:
3178                 snprintf(txt, TXT_SIZE, "Quadratic");
3179                 break;
3180             case 2:
3181                 snprintf(txt, TXT_SIZE, "Cubic");
3182                 break;
3183             default:
3184                 snprintf(txt, TXT_SIZE, "%d", i);
3185                 break;
3186             }
3187             break;
3188         case ct_envshape_attack:
3189             switch (i)
3190             {
3191             case 0:
3192                 snprintf(txt, TXT_SIZE, "Convex");
3193                 break;
3194             case 1:
3195                 snprintf(txt, TXT_SIZE, "Linear");
3196                 break;
3197             case 2:
3198                 snprintf(txt, TXT_SIZE, "Concave");
3199                 break;
3200             default:
3201                 snprintf(txt, TXT_SIZE, "%d", i);
3202                 break;
3203             }
3204             break;
3205         case ct_sineoscmode:
3206             switch (i)
3207             {
3208             case 0:
3209             case 1:
3210             case 2:
3211             case 3:
3212             case 4:
3213             case 5:
3214             case 6:
3215             case 7:
3216                 snprintf(txt, TXT_SIZE, "Wave %d (TX %d)", i + 1, i + 1);
3217                 break;
3218             default:
3219                 snprintf(txt, TXT_SIZE, "Wave %d", i + 1);
3220             }
3221             break;
3222         case ct_sinefmlegacy:
3223             if (i == 0)
3224                 snprintf(txt, TXT_SIZE, "Legacy (<v1.6.2)");
3225             else
3226                 snprintf(txt, TXT_SIZE, "Same as FM2/3");
3227             break;
3228         case ct_vocoder_bandcount:
3229             snprintf(txt, TXT_SIZE, "%d bands", i);
3230             break;
3231         case ct_distortion_waveshape:
3232             snprintf(txt, TXT_SIZE, "%s", wst_names[wst_soft + i]);
3233             break;
3234         case ct_oscroute:
3235             switch (i)
3236             {
3237             case 0:
3238                 snprintf(txt, TXT_SIZE, "Filter 1");
3239                 break;
3240             case 1:
3241                 snprintf(txt, TXT_SIZE, "Both");
3242                 break;
3243             case 2:
3244                 snprintf(txt, TXT_SIZE, "Filter 2");
3245                 break;
3246             }
3247             break;
3248         case ct_flangermode:
3249         {
3250             int mode = i;
3251 
3252             std::string types;
3253             switch (mode)
3254             {
3255             case 0:
3256                 types = "Dry + Combs";
3257                 break;
3258             case 1:
3259                 types = "Combs Only";
3260                 break;
3261             case 2:
3262                 types = "Dry + Arp Combs";
3263                 break;
3264             case 3:
3265                 types = "Arp Combs Only";
3266                 break;
3267             }
3268             snprintf(txt, TXT_SIZE, "%s", types.c_str());
3269         }
3270         break;
3271         case ct_fxlfowave:
3272         {
3273             switch (i)
3274             {
3275             case 0:
3276                 snprintf(txt, TXT_SIZE, "Sine");
3277                 break;
3278             case 1:
3279                 snprintf(txt, TXT_SIZE, "Triangle");
3280                 break;
3281             case 2:
3282                 snprintf(txt, TXT_SIZE, "Sawtooth");
3283                 break;
3284             case 3:
3285                 snprintf(txt, TXT_SIZE, "Noise");
3286                 break;
3287             case 4:
3288                 snprintf(txt, TXT_SIZE, "Sample & Hold");
3289                 break;
3290             case 5:
3291                 snprintf(txt, TXT_SIZE, "Square");
3292                 break;
3293             }
3294         }
3295         break;
3296         case ct_stringosc_excitation_model:
3297         {
3298             extern std::string stringosc_excitation_name(int);
3299             auto n = stringosc_excitation_name(i);
3300             snprintf(txt, TXT_SIZE, "%s", n.c_str());
3301         }
3302         break;
3303         case ct_alias_wave:
3304         {
3305             extern const char *alias_wave_name[];
3306             extern int alias_waves_count();
3307             snprintf(txt, TXT_SIZE, "%s",
3308                      alias_wave_name[std::max(0, std::min(i, alias_waves_count() - 1))]);
3309         }
3310         break;
3311         case ct_twist_engine:
3312         {
3313             extern std::string twist_engine_name(int);
3314             auto n = twist_engine_name(i);
3315             snprintf(txt, TXT_SIZE, "%s", n.c_str());
3316         }
3317         break;
3318         case ct_ensemble_stages:
3319         {
3320             extern std::string ensemble_stage_name(int);
3321             auto n = ensemble_stage_name(i);
3322             snprintf(txt, TXT_SIZE, "%s", n.c_str());
3323         }
3324         break;
3325         case ct_reson_mode:
3326             switch (i)
3327             {
3328             case 0:
3329                 snprintf(txt, TXT_SIZE, "Lowpass");
3330                 break;
3331             case 1:
3332                 snprintf(txt, TXT_SIZE, "Bandpass");
3333                 break;
3334             case 2:
3335                 snprintf(txt, TXT_SIZE, "Bandpass+Notch");
3336                 break;
3337             case 3:
3338                 snprintf(txt, TXT_SIZE, "Highpass");
3339                 break;
3340             }
3341             break;
3342         case ct_vocoder_modulator_mode:
3343         {
3344             std::string type;
3345             switch (i)
3346             {
3347             case 0:
3348                 type = "Monosum";
3349                 break;
3350             case 1:
3351                 type = "Left Only";
3352                 break;
3353             case 2:
3354                 type = "Right Only";
3355                 break;
3356             case 3:
3357                 type = "Stereo";
3358                 break;
3359             }
3360             snprintf(txt, TXT_SIZE, "%s", type.c_str());
3361         }
3362         break;
3363 
3364         case ct_airwindows_fx:
3365         {
3366             // These are all the ones with a ParameterDiscreteIndexRemapper
3367             auto pd = dynamic_cast<ParameterDiscreteIndexRemapper *>(user_data);
3368             if (pd)
3369             {
3370                 snprintf(txt, TXT_SIZE, "%s", pd->nameAtStreamedIndex(i).c_str());
3371             }
3372             else
3373             {
3374                 snprintf(txt, TXT_SIZE, "%i", i);
3375             }
3376             break;
3377         }
3378         case ct_nimbusmode:
3379         {
3380             switch (i)
3381             {
3382             case 0:
3383                 snprintf(txt, TXT_SIZE, "Granularizer");
3384                 break;
3385             case 1:
3386                 snprintf(txt, TXT_SIZE, "Pitch Shifter");
3387                 break;
3388             case 2:
3389                 snprintf(txt, TXT_SIZE, "Looping Delay");
3390                 break;
3391             case 3:
3392                 snprintf(txt, TXT_SIZE, "Spectral Madness");
3393                 break;
3394             }
3395         }
3396         break;
3397         case ct_nimbusquality:
3398         {
3399             // https://github.com/pichenettes/eurorack/blob/84f4f67aaa25bf696093b224e2a51a5c18143e4f/clouds/dsp/granular_processor.h#L125-L128
3400             // [input value] [channels] [low fidelity]
3401             //     0b00          2          false
3402             //     0b01          1          false
3403             //     0b10          2          true
3404             //     0b11          1          true
3405             switch (i)
3406             {
3407             case 0: // binary 00
3408                 snprintf(txt, TXT_SIZE, "32k 16-bit Stereo");
3409                 break;
3410             case 1: // 0b01
3411                 snprintf(txt, TXT_SIZE, "32k 16-bit Mono");
3412                 break;
3413             case 2: // 0b10
3414                 snprintf(txt, TXT_SIZE, "16k 8-bit Stereo");
3415                 break;
3416             default: // 0b11
3417                 snprintf(txt, TXT_SIZE, "16k 8-bit Mono");
3418                 break;
3419             }
3420         }
3421         break;
3422         default:
3423             snprintf(txt, TXT_SIZE, "%i", i);
3424             break;
3425         };
3426         break;
3427     }
3428     case vt_bool:
3429         if (external)
3430             b = ef > 0.5f;
3431         else
3432             b = val.b;
3433         if (b)
3434             snprintf(txt, TXT_SIZE, "On");
3435         else
3436             snprintf(txt, TXT_SIZE, "Off");
3437         break;
3438     };
3439 }
3440 
get_value_f01()3441 float Parameter::get_value_f01()
3442 {
3443     if (ctrltype == ct_none)
3444         return 0;
3445     switch (valtype)
3446     {
3447     case vt_float:
3448         return (val.f - val_min.f) / (val_max.f - val_min.f);
3449         break;
3450     case vt_int:
3451         return Parameter::intScaledToFloat(val.i, val_max.i, val_min.i);
3452         break;
3453     case vt_bool:
3454         return val.b ? 1.f : 0.f;
3455         break;
3456     };
3457     return 0;
3458 }
3459 
normalized_to_value(float value)3460 float Parameter::normalized_to_value(float value)
3461 {
3462     switch (valtype)
3463     {
3464     case vt_float:
3465         return value * (val_max.f - val_min.f) + val_min.f;
3466         break;
3467     case vt_int:
3468         return value * ((float)val_max.i - (float)val_min.i) + (float)val_min.i;
3469         break;
3470     case vt_bool:
3471         return (value > 0.5f) ? 1.f : 0.f;
3472         break;
3473     };
3474     return 0;
3475 }
3476 
value_to_normalized(float value)3477 float Parameter::value_to_normalized(float value)
3478 {
3479     switch (valtype)
3480     {
3481     case vt_float:
3482         return (value - val_min.f) / (val_max.f - val_min.f);
3483         break;
3484     case vt_int:
3485         return ((float)value - (float)val_min.i) / ((float)val_max.i - (float)val_min.i);
3486         break;
3487     case vt_bool:
3488         return (value > 0.5) ? 1.f : 0.f;
3489         break;
3490     };
3491     return 0;
3492 }
3493 
getUnit() const3494 const wchar_t *Parameter::getUnit() const { return L""; }
3495 
get_default_value_f01()3496 float Parameter::get_default_value_f01()
3497 {
3498     if (ctrltype == ct_none)
3499         return 0;
3500     switch (valtype)
3501     {
3502     case vt_float:
3503         return (val_default.f - val_min.f) / (val_max.f - val_min.f);
3504         break;
3505     case vt_int:
3506         return Parameter::intScaledToFloat(val_default.i, val_max.i, val_min.i);
3507         break;
3508     case vt_bool:
3509         return val_default.b ? 1.f : 0.f;
3510         break;
3511     };
3512     return 0;
3513 }
3514 
set_value_f01(float v,bool force_integer)3515 void Parameter::set_value_f01(float v, bool force_integer)
3516 {
3517     switch (valtype)
3518     {
3519     case vt_float:
3520         val.f = v * (val_max.f - val_min.f) + val_min.f;
3521         break;
3522     case vt_int:
3523         val.i = Parameter::intUnscaledFromFloat(v, val_max.i, val_min.i);
3524         break;
3525     case vt_bool:
3526         val.b = (v > 0.5f);
3527         break;
3528     }
3529     bound_value(force_integer);
3530 }
3531 
get_modulation_f01(float mod)3532 float Parameter::get_modulation_f01(float mod)
3533 {
3534     if (ctrltype == ct_none)
3535         return 0;
3536     if (valtype != vt_float)
3537         return 0;
3538     //	float v = ((val.f+mod)-val_min.f)/(val_max.f - val_min.f);
3539     float v = (mod) / (val_max.f - val_min.f);
3540     // return limit_range(v,val_min.f,val_max.f);
3541     // return limit_range(v,0.0f,1.0f);
3542     return limit_range(v, -1.0f, 1.0f);
3543 }
3544 
set_modulation_f01(float v)3545 float Parameter::set_modulation_f01(float v)
3546 {
3547     if (ctrltype == ct_none)
3548         return 0;
3549     if (valtype != vt_float)
3550         return 0;
3551 
3552     // float mod = v*(val_max.f - val_min.f) + val_min.f - val.f;
3553     float mod = v * (val_max.f - val_min.f);
3554     return mod;
3555 }
3556 
3557 //
morph(Parameter * b,float x)3558 pdata Parameter::morph(Parameter *b, float x)
3559 {
3560     pdata rval;
3561     if ((valtype == vt_float) && (b->valtype == vt_float) && (ctrltype == b->ctrltype))
3562     {
3563         rval.f = (1 - x) * val.f + x * b->val.f;
3564     }
3565     else
3566     {
3567         if (x > 0.5)
3568             rval.i = b->val.i;
3569         else
3570             rval.i = this->val.i;
3571     }
3572     return rval;
3573 }
3574 
3575 // uses "this" as parameter a
3576 /*void parameter::morph(parameter *b, float x)
3577 {
3578         if((valtype == vt_float)&&(b->valtype == vt_float)&&(ctrltype == b->ctrltype))
3579         {
3580                 val.f = (1-x)*val.f + x*b->val.f;
3581         }
3582         else
3583         {
3584                                         if (x>0.5)
3585                                                 memcpy(this,b,sizeof(parameter));
3586         }
3587 }*/
3588 
3589 // uses two other parameters
morph(Parameter * a,Parameter * b,float x)3590 void Parameter::morph(Parameter *a, Parameter *b, float x)
3591 {
3592     if ((a->valtype == vt_float) && (b->valtype == vt_float) && (a->ctrltype == b->ctrltype))
3593     {
3594         memcpy((void *)this, (void *)a, sizeof(Parameter));
3595         val.f = (1 - x) * a->val.f + x * b->val.f;
3596     }
3597     else
3598     {
3599         if (x > 0.5)
3600             memcpy((void *)this, (void *)b, sizeof(Parameter));
3601         else
3602             memcpy((void *)this, (void *)a, sizeof(Parameter));
3603     }
3604 }
3605 
can_setvalue_from_string()3606 bool Parameter::can_setvalue_from_string()
3607 {
3608     switch (ctrltype)
3609     {
3610     case ct_percent:
3611     case ct_percent_deactivatable:
3612     case ct_percent_oscdrift:
3613     case ct_percent200:
3614     case ct_percent_bipolar:
3615     case ct_percent_bipolar_stereo:
3616     case ct_percent_bipolar_stringbal:
3617     case ct_percent_bipolar_w_dynamic_unipolar_formatting:
3618     case ct_twist_aux_mix:
3619     case ct_pitch_semi7bp:
3620     case ct_pitch_semi7bp_absolutable:
3621     case ct_pitch:
3622     case ct_pitch4oct:
3623     case ct_fmratio:
3624     case ct_syncpitch:
3625     case ct_amplitude:
3626     case ct_amplitude_clipper:
3627     case ct_decibel:
3628     case ct_decibel_narrow:
3629     case ct_decibel_narrow_deactivatable:
3630     case ct_decibel_narrow_extendable:
3631     case ct_decibel_narrow_short_extendable:
3632     case ct_decibel_extra_narrow:
3633     case ct_decibel_extra_narrow_deactivatable:
3634     case ct_decibel_attenuation:
3635     case ct_decibel_attenuation_clipper:
3636     case ct_decibel_attenuation_large:
3637     case ct_decibel_fmdepth:
3638     case ct_decibel_extendable:
3639     case ct_decibel_deactivatable:
3640     case ct_envtime_linkable_delay:
3641     case ct_freq_audible:
3642     case ct_freq_audible_deactivatable:
3643     case ct_freq_audible_with_tunability:
3644     case ct_freq_audible_with_very_low_lowerbound:
3645     case ct_freq_reson_band1:
3646     case ct_freq_reson_band2:
3647     case ct_freq_reson_band3:
3648     case ct_freq_shift:
3649     case ct_freq_hpf:
3650     case ct_freq_vocoder_low:
3651     case ct_freq_vocoder_high:
3652     case ct_bandwidth:
3653     case ct_envtime:
3654     case ct_envtime_lfodecay:
3655     case ct_delaymodtime:
3656     case ct_reverbtime:
3657     case ct_reverbpredelaytime:
3658     case ct_portatime:
3659     case ct_ensemble_lforate:
3660     case ct_lforate:
3661     case ct_lforate_deactivatable:
3662     case ct_lfoamplitude:
3663     case ct_lfodeform:
3664     case ct_detuning:
3665     case ct_oscspread:
3666     case ct_oscspread_bipolar:
3667     case ct_countedset_percent:
3668     case ct_flangerpitch:
3669     case ct_flangervoices:
3670     case ct_flangerspacing:
3671     case ct_osc_feedback:
3672     case ct_osc_feedback_negative:
3673     case ct_chorusmodtime:
3674     case ct_pbdepth:
3675     case ct_polylimit:
3676     case ct_midikey:
3677     case ct_midikey_or_channel:
3678     case ct_phaser_stages:
3679     case ct_phaser_spread:
3680     case ct_rotarydrive:
3681     case ct_sendlevel:
3682     case ct_freq_mod:
3683     case ct_airwindows_param:
3684     case ct_airwindows_param_bipolar:
3685     case ct_reson_res_extendable:
3686     case ct_chow_ratio:
3687     case ct_comp_attack_ms:
3688     case ct_comp_release_ms:
3689     case ct_freq_ringmod:
3690     case ct_modern_trimix:
3691     case ct_ensemble_clockrate:
3692     case ct_alias_mask:
3693     case ct_alias_bits:
3694     case ct_tape_microns:
3695     case ct_tape_speed:
3696     {
3697         return true;
3698         break;
3699     }
3700     }
3701     return false;
3702 }
3703 
set_value_from_string(std::string s)3704 bool Parameter::set_value_from_string(std::string s) { return set_value_from_string_onto(s, val); }
3705 
set_value_from_string_onto(std::string s,pdata & onto)3706 bool Parameter::set_value_from_string_onto(std::string s, pdata &onto)
3707 {
3708     const char *c = s.c_str();
3709 
3710     if (valtype == vt_int)
3711     {
3712         int ni = val_min.i - 1; // default out of range value to test against later
3713 
3714         try
3715         {
3716             ni = std::stoi(c);
3717         }
3718         catch (const std::invalid_argument &)
3719         {
3720             ni = val_min.i - 1; // set value of ni out of range on invalid input
3721         }
3722         catch (const std::out_of_range &)
3723         {
3724             ni = val_min.i - 1; // same for out of range input
3725         }
3726 
3727         switch (ctrltype)
3728         {
3729         case ct_midikey_or_channel:
3730         {
3731             auto sm = storage->getPatch().scenemode.val.i;
3732 
3733             if (sm == sm_chsplit)
3734             {
3735                 const char *strip = &(c[0]);
3736                 while (*strip != '\0' && !std::isdigit(*strip))
3737                     ++strip;
3738                 ni = (std::atof(strip) * 8) - 1;
3739 
3740                 // breaks case after channel number input, but if we're in split mode we fall
3741                 // through to ct_midikey
3742                 break;
3743             }
3744         }
3745         case ct_midikey:
3746         {
3747             if (ni == val_min.i - 1) // if integer input failed, try note recognition
3748             {
3749                 std::string::size_type n;
3750                 std::string::size_type m;
3751                 std::string notes[7] = {"c", "d", "e", "f", "g", "a", "b"};
3752                 int pitches[7] = {0, 2, 4, 5, 7, 9, 11};
3753                 int val = 0;
3754                 int neg = 1;
3755 
3756                 // convert string to lowercase
3757                 std::for_each(s.begin(), s.end(),
3758                               [](char &c) { c = ::tolower(static_cast<unsigned char>(c)); });
3759 
3760                 // find the unmodified note
3761                 for (int i = 0; i < 7; i++)
3762                 {
3763                     n = s.find(notes[i]);
3764                     if (n != std::string::npos)
3765                     {
3766                         val = pitches[i];
3767                         break;
3768                     }
3769                 }
3770 
3771                 // check if the following character is sharp or flat, adjust val if so
3772                 n++;
3773                 if ((m = s.find("#", n, 1)) != std::string::npos)
3774                 {
3775                     val += 1;
3776                     n++;
3777                 }
3778                 else if ((m = s.find("b", n, 1)) != std::string::npos)
3779                 {
3780                     val -= 1;
3781                     n++;
3782                 }
3783 
3784                 // if neither note modifiers are found, check for minus
3785                 if ((m = s.find("-", n, 1)) != std::string::npos)
3786                 {
3787                     neg = -1;
3788                     n++;
3789                 }
3790 
3791                 // finally, octave number
3792                 s = s.substr(n, s.length() - n); // trim the fat to the left of current char
3793 
3794                 int oct;
3795                 try
3796                 {
3797                     oct = std::stoi(s);
3798                 }
3799                 catch (std::invalid_argument const &)
3800                 {
3801                     oct = -10; // throw things out of range on invalid input
3802                 }
3803 
3804                 // construct the integer note value
3805                 int oct_offset = 1;
3806                 if (storage)
3807                     oct_offset = Surge::Storage::getUserDefaultValue(storage, "middleC", 1);
3808 
3809                 ni = ((oct + oct_offset) * 12 * neg) + val;
3810             }
3811 
3812             break;
3813         }
3814         }
3815 
3816         if (ni >= val_min.i && ni <= val_max.i)
3817         {
3818             onto.i = ni;
3819             return true;
3820         }
3821 
3822         return false;
3823     }
3824 
3825     auto nv = std::atof(c);
3826 
3827     switch (displayType)
3828     {
3829     case Custom:
3830         // handled below
3831         break;
3832     case DelegatedToFormatter:
3833     {
3834         auto ef = dynamic_cast<ParameterExternalFormatter *>(user_data);
3835         if (ef)
3836         {
3837             float f;
3838             if (ef->stringToValue(c, f))
3839             {
3840                 onto.f = limit_range(f, val_min.f, val_max.f);
3841                 return true;
3842             }
3843         }
3844         // break; DO NOT break. Fall back
3845     }
3846     case LinearWithScale:
3847     {
3848         float ext_mul = (can_extend_range() && extend_range) ? displayInfo.extendFactor : 1.0;
3849         float abs_mul = (can_be_absolute() && absolute) ? displayInfo.absoluteFactor : 1.0;
3850         float factor = ext_mul * abs_mul;
3851         float res = nv / displayInfo.scale / factor;
3852 
3853         if (displayInfo.customFeatures & ParamDisplayFeatures::kScaleBasedOnIsBiPolar)
3854         {
3855             if (!is_bipolar())
3856             {
3857                 res = res * 2 - 1;
3858             }
3859         }
3860 
3861         if (res < val_min.f || res > val_max.f)
3862         {
3863             return false;
3864         }
3865 
3866         onto.f = res;
3867         return true;
3868 
3869         break;
3870     }
3871     case ATwoToTheBx:
3872     {
3873         if (displayInfo.supportsNoteName)
3874         {
3875             if ((s[0] >= 'a' && s[0] <= 'g') || (s[0] >= 'A' && s[0] <= 'G'))
3876             {
3877                 int oct_offset = 0;
3878                 if (storage)
3879                 {
3880                     oct_offset = Surge::Storage::getUserDefaultValue(storage, "middleC", 1);
3881                 }
3882                 int note = 0, sf = 0;
3883                 if (s[0] >= 'a' && s[0] <= 'g')
3884                 {
3885                     note = s[0] - 'a';
3886                 }
3887 
3888                 if (s[0] >= 'A' && s[0] <= 'G')
3889                 {
3890                     note = s[0] - 'A';
3891                 }
3892 
3893                 int octPos = 1;
3894                 while (s[octPos] == '#')
3895                 {
3896                     sf++;
3897                     octPos++;
3898                 }
3899                 while (s[octPos] == 'b')
3900                 {
3901                     sf--;
3902                     octPos++;
3903                 }
3904 
3905                 auto oct = std::atoi(s.c_str() + octPos) + oct_offset;
3906 
3907                 std::vector<int> df6 = {9, 11, 0, 2, 4, 5, 7};
3908 
3909                 auto mn = df6[note] + (oct)*12 + sf;
3910                 nv = 440.0 * pow(2.0, (mn - 69) / 12.0);
3911             }
3912         }
3913         /*
3914         ** v = a 2^bx
3915         ** log2(v/a) = bx
3916         ** log2(v/a)/b = x;
3917         */
3918         float res = log2f(nv / displayInfo.a) / displayInfo.b;
3919 
3920         if (res < val_min.f || res > val_max.f)
3921         {
3922             return false;
3923         }
3924         onto.f = res;
3925         return true;
3926         break;
3927     }
3928     case Decibel:
3929     {
3930         // typing in the maximum value for send levels (12 dB) didn't work
3931         // probably because of float precision (or lack thereof)
3932         // so special case them here
3933         // better solution welcome!
3934         if (nv >= 12)
3935         {
3936             nv = limit_range((float)db_to_amp(nv), val_min.f, val_max.f);
3937         }
3938         else
3939         {
3940             nv = db_to_amp(nv);
3941         }
3942 
3943         if (nv < val_min.f || nv > val_max.f)
3944         {
3945             return false;
3946         }
3947 
3948         onto.f = nv;
3949         return true;
3950     }
3951     break;
3952     }
3953 
3954     switch (ctrltype)
3955     {
3956     case ct_chow_ratio:
3957     {
3958         if (nv < val_min.f || nv > val_max.f)
3959         {
3960             return false;
3961         }
3962         onto.f = nv;
3963         return true;
3964     }
3965     break;
3966     case ct_fmratio:
3967     {
3968         if (absolute)
3969         {
3970             float uv = std::atof(c) / 440.f;
3971             float n = log2(uv) * 12 + 69;
3972             float bpv = (n - 69) / 69.f;
3973             onto.f = bpv * 16 + 16;
3974         }
3975         else
3976         {
3977             // In this case we have to set nv differently
3978             const char *strip = &(c[0]);
3979             while (*strip != '\0' && !std::isdigit(*strip) && *strip != '.')
3980                 ++strip;
3981 
3982             // OK so do we contain a /?
3983             const char *slp;
3984             if ((slp = strstr(strip, "/")) != nullptr)
3985             {
3986                 float num = std::atof(strip);
3987                 float den = std::atof(slp + 1);
3988                 if (den == 0)
3989                     nv = 1;
3990                 else
3991                     nv = num / den;
3992             }
3993             else
3994             {
3995                 nv = std::atof(strip);
3996             }
3997             if (extend_range)
3998             {
3999                 if (nv < 1)
4000                 {
4001                     float oonv = -1.0 / nv;
4002                     // oonv = - ( ( 16 - f ) * 2 + 1)
4003                     // -oonv-1 = (16-f)*2
4004                     // (1+oonv)/2 = f - 16;
4005                     // (1+oonv)/2 + 16 = f;
4006                     nv = 16.f / 31.f * (1 + oonv) + 16;
4007                 }
4008                 else
4009                 {
4010                     // nv = ( f - 16 ) * 2 + 1
4011                     // (nv - 1)/2 + 16 = f
4012                     nv = (nv - 1) * 16.f / 31.f + 16;
4013                 }
4014             }
4015             onto.f = nv;
4016         }
4017     }
4018     break;
4019 
4020     default:
4021         return false;
4022     }
4023     return true;
4024 }
4025 
4026 /*
4027 ** This function returns a value in range [-1.1] scaled by the mins and maxes
4028 */
calculate_modulation_value_from_string(const std::string & s,bool & valid)4029 float Parameter::calculate_modulation_value_from_string(const std::string &s, bool &valid)
4030 {
4031     valid = true;
4032 
4033     float mv = std::atof(s.c_str());
4034     switch (displayType)
4035     {
4036     case Custom:
4037         break;
4038     case DelegatedToFormatter:
4039     case LinearWithScale:
4040     {
4041         valid = true;
4042         auto mv = (float)std::atof(s.c_str());
4043         mv /= displayInfo.scale;
4044 
4045         if (displayInfo.customFeatures & ParamDisplayFeatures::kScaleBasedOnIsBiPolar)
4046         {
4047             if (!is_bipolar())
4048             {
4049                 mv = mv * 2;
4050             }
4051         }
4052 
4053         if (can_be_absolute() && absolute)
4054         {
4055             mv /= displayInfo.absoluteFactor;
4056         }
4057         auto rmv = mv / (val_max.f - val_min.f);
4058         if (can_extend_range() && extend_range)
4059         {
4060             // ModValu is in extended units already
4061             rmv = mv / (get_extended(val_max.f) - get_extended(val_min.f));
4062         }
4063 
4064         if (rmv > 1 || rmv < -1)
4065             valid = false;
4066         return rmv;
4067 
4068         break;
4069     }
4070     case ATwoToTheBx:
4071     {
4072         if (temposync)
4073         {
4074             auto mv = (float)std::atof(s.c_str()) / 100.0;
4075             auto rmv = mv / (get_extended(val_max.f) - get_extended(val_min.f));
4076             return rmv;
4077         }
4078 
4079         /* modulation is displayed as
4080         **
4081         ** d = mp - val
4082         **   = a2^b(v+m) - a2^bv
4083         ** d/a + 2^bv = 2^b(v+m)
4084         ** log2( d/a + 2^bv ) = b(v + m)
4085         ** log2( d/a + 2^bv )/b - v = m
4086         */
4087 
4088         auto d = (float)std::atof(s.c_str());
4089         auto a = displayInfo.a;
4090         auto b = displayInfo.b;
4091         auto mv = val_min.f;
4092 
4093         auto l2arg = d / a + pow(2.0, b * val.f);
4094         if (l2arg > 0)
4095             mv = log2f(l2arg) / b - val.f;
4096         else
4097             valid = false;
4098 
4099         auto rmv = mv / (get_extended(val_max.f) - get_extended(val_min.f));
4100         return rmv;
4101         break;
4102     }
4103     case Decibel:
4104     {
4105         /*
4106         ** amp2db is 18 * log2(x)
4107         **
4108         ** we have
4109         ** d = mp - val
4110         **   = 18 * ( log2( m + v ) - log2( v ) )
4111         ** d / 18 + log2(v) = log2( m + v )
4112         ** 2^(d/18 + log2(v) ) - v = m;
4113         **
4114         ** But there's a gotcha. The minimum dB is -192 so we have to set the val.f accordingly.
4115         ** That is we have some amp2db we have used, called av. So:
4116         **
4117         ** d = mv - av
4118         **   = 18 ( log2(m+v) ) - av
4119         ** d / 18 + av/18 = log2(m+v)
4120         ** 2^(d/18 + mv/18) - v = m
4121         */
4122         auto av = amp_to_db(val.f);
4123         auto d = (float)std::atof(s.c_str());
4124         auto mv = powf(2.0, (d / 18.0 + av / 18.0)) - val.f;
4125         auto rmv = mv / (get_extended(val_max.f) - get_extended(val_min.f));
4126         return rmv;
4127         break;
4128     }
4129     }
4130 
4131     switch (ctrltype)
4132     {
4133     case ct_fmratio:
4134         if (absolute)
4135         {
4136             auto dfreq = std::atof(s.c_str());
4137 
4138             float bpv = (val.f - 16.0) / 16.0;
4139             float mul = 69;
4140             float note = 69 + mul * bpv;
4141             auto freq = 440.0 * pow(2.0, (note - 69.0) / 12);
4142             auto tgfreq = freq + dfreq;
4143             auto tgnote = log2(tgfreq / 440.0) * 12 + 69;
4144             auto tgbpv = (tgnote - 69) / mul;
4145             auto dbpv = (tgbpv - bpv) / 2.0;
4146             return dbpv;
4147         }
4148         if (extend_range)
4149         {
4150             /*
4151              * OK so what's happening here? Well we need to give a number that
4152              * when handed in asfter going through get_extended gives us what
4153              * we typed in through the formatting.
4154              *
4155              * That is p->get_extended(mf) = v / 31 / 2. So lets get to work
4156              */
4157             float mv = 0.f;
4158             const char *strip = &(s.c_str()[0]);
4159             while (*strip != '\0' && !std::isdigit(*strip) && *strip != '.')
4160                 ++strip;
4161 
4162             // OK so do we contain a /?
4163             const char *slp;
4164             if ((slp = strstr(strip, "/")) != nullptr)
4165             {
4166                 float num = std::atof(strip);
4167                 float den = std::atof(slp + 1);
4168                 if (den == 0)
4169                     mv = 1;
4170                 else
4171                 {
4172                     mv = num / den;
4173                     if (mv < 1)
4174                         mv = -1 / mv;
4175                 }
4176             }
4177             else
4178             {
4179                 mv = std::atof(strip);
4180             }
4181             // Normalized value
4182             auto exmf = (mv) / 31.0 / 2.0;
4183             // This reverses the scaling for extended mode. We now have
4184             // p->get_extended(val) = qq so reverse extended
4185             auto qq = exmf * 64 - 31 + (mv < 0 ? 1 : -1);
4186 
4187             // so the transformation out of extended is
4188             // x = (f-16) * 31/16 +- 1
4189             // ( x -+ 1 ) * 16 / 31 + 16 = f
4190 
4191             auto res = (qq + ((qq >= -32) ? +1 : -1)) * 16.f / 31.f + 16.f;
4192             return res / 32;
4193         }
4194     default:
4195     {
4196         // This works in all the linear cases so we need to handle fewer above than we'd think
4197         auto mv = (float)std::atof(s.c_str()) / (get_extended(val_max.f) - get_extended(val_min.f));
4198 
4199         if (mv < -1 || mv > 1)
4200             valid = false;
4201         return mv;
4202     }
4203     }
4204     valid = false;
4205     return 0.0;
4206 }
4207 
4208 std::atomic<bool> parameterNameUpdated(false);
4209