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