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 "Parameter.h"
17 #pragma once
18 
19 /*
20  * OK so what the heck is happening here, you may ask? Well, let me explain. Grab a cup of tea.
21  *
22  * As we approached Surge 1.8 with new filters, we realized our filter list was getting
23  * long. So we decided to use submenus. But when doing that, we realized that the
24  * natural grouping of filters (LP, BP, HP, Notch, Special...) didn't work with the way
25  * our filter models had worked. We had things like "bandpass doesn't split 12 dB/24 dB" into
26  * separate types, and "OB-Xd is kinda all sorts of filters". So, over in issue #3006,
27  * we decided that some filters needed splitting, kinda like what Luna had done in the non-linear
28  * feedback set. But splitting means that subtype counts change and streaming breaks.
29  * And we wanted to split filters which weren't in streaming version 14 (1.7->1.8) either.
30  *
31  * So what we did was add in streaming version 15 a "post patch streaming fixup" operation
32  * which allows you to see the prior version, the current version, and adjust. That way we can
33  * do things like "OB-Xd subtype 7 in streaming version 14 is actually OB-Xd highpass subtype 3
34  * in streaming version 15 and above". Or whatever.
35  *
36  * But to do *that*, we need to keep the old enums around so we can write that code. So these
37  * are the old enums.
38  *
39  * Then the only question left is - how to split? I chose the 'add at end for splits' method. That
40  * is, fut_14_bp12 splits into fut_bp12 and fut_bp24, but I added fut_bp24 at the end of the list.
41  * Pros and cons: if I added it adjacent, the names in the name array would line up, but the
42  * remapping code would be wildly more complicated. I chose simple remapping code (that is S&H and
43  * vintage ladder are no-ops in remap) at the cost of an oddly ordered filter name list. That's the
44  * right choice, but when you curse me for the odd name list, you can come back and read this
45  * comment and feel slightly better. Finally, items which split and changed meaning got a new name
46  * (so fut_comb is now fut_comp_pos and fut_comb_neg, say), which requires us to go and fix up any
47  * code which refered to the old values.
48  */
49 
50 enum fu_type_sv14
51 {
52     fut_14_none = 0,
53     fut_14_lp12,
54     fut_14_lp24,
55     fut_14_lpmoog,
56     fut_14_hp12,
57     fut_14_hp24,
58     fut_14_bp12,
59     fut_14_notch12,
60     fut_14_comb,
61     fut_14_SNH,
62     fut_14_vintageladder,
63     fut_14_obxd_2pole,
64     fut_14_obxd_4pole,
65     fut_14_k35_lp,
66     fut_14_k35_hp,
67     fut_14_diode,
68     fut_14_cutoffwarp_lp,
69     fut_14_cutoffwarp_hp,
70     fut_14_cutoffwarp_n,
71     fut_14_cutoffwarp_bp,
72     n_fu_14_types,
73 };
74 
75 enum fu_type
76 {
77     fut_none = 0,
78     fut_lp12,
79     fut_lp24,
80     fut_lpmoog,
81     fut_hp12,
82     fut_hp24,
83     fut_bp12,    // ADJ
84     fut_notch12, // ADH
85     fut_comb_pos,
86     fut_SNH,
87     fut_vintageladder,
88     fut_obxd_2pole_lp, // ADJ
89     fut_obxd_4pole,
90     fut_k35_lp,
91     fut_k35_hp,
92     fut_diode,
93     fut_cutoffwarp_lp,
94     fut_cutoffwarp_hp,
95     fut_cutoffwarp_n,
96     fut_cutoffwarp_bp,
97     fut_obxd_2pole_hp,
98     fut_obxd_2pole_n,
99     fut_obxd_2pole_bp,
100     fut_bp24,
101     fut_notch24,
102     fut_comb_neg,
103     fut_apf,
104     fut_cutoffwarp_ap,
105     fut_resonancewarp_lp,
106     fut_resonancewarp_hp,
107     fut_resonancewarp_n,
108     fut_resonancewarp_bp,
109     fut_resonancewarp_ap,
110     n_fu_types,
111 };
112 
113 /*
114  * Each filter needs w names (alas). there's the name we show in the automation parameter and
115  * so on (the value for get_display_name) which is in 'fut_names'. There's the value we put
116  * in the menu which generally strips out Lowpass and Highpass and stuff, since they are already
117  * grouped in submenus, and this is in fut_menu array
118  */
119 const char fut_names[n_fu_types][32] = {
120     "Off",               // fut_none
121     "LP 12 dB",          // fut_lp12
122     "LP 24 dB",          // fut_lp24
123     "LP Legacy Ladder",  // fut_lpmoog
124     "HP 12 dB",          // fut_hp12
125     "HP 24 dB",          // fut_hp24
126     "BP 12 dB",          // fut_bp12
127     "N 12 dB",           // fut_notch12
128     "FX Comb +",         // fut_comb_pos
129     "FX Sample & Hold",  // fut_SNH
130     "LP Vintage Ladder", // fut_vintageladder
131     "LP OB-Xd 12 dB",    // fut_obxd_2pole_lp
132     "LP OB-Xd 24 dB",    // fut_obxd_4pole
133     "LP K35",            // fut_k35_lp
134     "HP K35",            // fut_k35_hp
135     "LP Diode Ladder",   // fut_diode
136     "LP Cutoff Warp",    // fut_cutoffwarp_lp
137     "HP Cutoff Warp",    // fut_cutoffwarp_hp
138     "N Cutoff Warp",     // fut_cutoffwarp_n
139     "BP Cutoff Warp",    // fut_cutoffwarp_bp
140     "HP OB-Xd 12 dB",    // fut_obxd_2pole_hp
141     "N OB-Xd 12 dB",     // fut_obxd_2pole_n
142     "BP OB-Xd 12 dB",    // fut_obxd_2pole_bp
143     "BP 24 dB",          // fut_bp24
144     "N 24 dB",           // fut_notch24
145     "FX Comb -",         // fut_comb_neg
146     "FX Allpass",        // fut_apf
147     "FX Cutoff Warp AP", // fut_cutoffwarp_ap
148     "LP Res Warp",       // fut_resonancewarp_lp
149     "HP Res Warp",       // fut_resonancewarp_hp
150     "N Res Warp",        // fut_resonancewarp_n
151     "BP Res Warp",       // fut_resonancewarp_bp
152     "FX Res Warp AP",    // fut_resonancewarp_ap
153     /* this is a ruler to ensure names do not exceed 31 characters
154      0123456789012345678901234567890
155     */
156 };
157 
158 const char fut_menu_names[n_fu_types][32] = {
159     "Off",
160     "12 dB", // LP
161     "24 dB", // LP
162     "Legacy Ladder",
163     "12 dB", // HP
164     "24 dB", // HP
165     "12 dB", // BP
166     "12 dB", // N
167     "Comb +",
168     "Sample & Hold",
169     "Vintage Ladder",
170     "OB-Xd 12 dB", // LP
171     "OB-Xd 24 dB", // LP
172     "K35",         // LP
173     "K35",         // HP
174     "Diode Ladder",
175     "Cutoff Warp", // LP
176     "Cutoff Warp", // HP
177     "Cutoff Warp", // N
178     "Cutoff Warp", // BP
179     "OB-Xd 12 dB", // HP
180     "OB-Xd 12 dB", // N
181     "OB-Xd 12 dB", // BP
182     "24 dB",       // BP
183     "24 dB",       // N
184     "Comb -",
185     "Allpass",
186     "Cutoff Warp Allpass",
187     "Resonance Warp", // LP
188     "Resonance Warp", // HP
189     "Resonance Warp", // N
190     "Resonance Warp", // BP
191     "Resonance Warp Allpass",
192     /* this is a ruler to ensure names do not exceed 31 characters
193      0123456789012345678901234567890
194     */
195 };
196 
197 const char fut_bp_subtypes[3][32] = {
198     "Clean",
199     "Driven",
200     "Smooth",
201 };
202 
203 const char fut_notch_subtypes[2][32] = {
204     "Standard",
205     "Mild",
206 };
207 
208 const char fut_comb_subtypes[2][64] = {
209     "50% Wet",
210     "100% Wet",
211 };
212 
213 const char fut_def_subtypes[3][32] = {
214     "Clean",
215     "Driven",
216     "Smooth",
217 };
218 
219 const char fut_ldr_subtypes[4][32] = {
220     "6 dB",
221     "12 dB",
222     "18 dB",
223     "24 dB",
224 };
225 
226 const char fut_vintageladder_subtypes[6][32] = {
227     "Type 1",
228     "Type 1 Compensated",
229     "Type 2",
230     "Type 2 Compensated",
231 };
232 
233 const char fut_obxd_2p_subtypes[2][32] = {"Standard", "Pushed"};
234 
235 const char fut_obxd_4p_subtypes[4][32] = {
236     "6 dB",
237     "12 dB",
238     "18 dB",
239     "24 dB",
240 };
241 
242 const char fut_k35_subtypes[5][32] = {"No Saturation", "Mild Saturation", "Moderate Saturation",
243                                       "Heavy Saturation", "Extreme Saturation"};
244 
245 const float fut_k35_saturations[5] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f};
246 
247 const char fut_nlf_subtypes[4][32] = {
248     "1 Stage",
249     "2 Stages",
250     "3 Stages",
251     "4 Stages",
252 };
253 
254 const char fut_nlf_saturators[4][16] = {
255     "tanh",
256     "Soft Clip",
257     "OJD",
258     "Sine",
259 };
260 
261 const int fut_subcount[n_fu_types] = {
262     0,  // fut_none
263     3,  // fut_lp12
264     3,  // fut_lp24
265     4,  // fut_lpmoog
266     3,  // fut_hp12
267     3,  // fut_hp24
268     3,  // fut_bp12
269     2,  // fut_notch12
270     2,  // fut_comb_pos
271     0,  // fut_SNH
272     4,  // fut_vintageladder
273     2,  // fut_obxd_2pole
274     4,  // fut_obxd_4pole
275     5,  // fut_k35_lp
276     5,  // fut_k35_hp
277     4,  // fut_diode
278     12, // fut_cutoffwarp_lp
279     12, // fut_cutoffwarp_hp
280     12, // fut_cutoffwarp_n
281     12, // fut_cutoffwarp_bp
282     2,  // fut_obxd_2pole_hp,
283     2,  // fut_obxd_2pole_n,
284     2,  // fut_obxd_2pole_bp,
285     3,  // fut_bp24,
286     2,  // fut_notch24,
287     2,  // fut_comb_neg,
288     0,  // fut_apf
289     12, // fut_cutoffwarp_ap
290     8,  // fut_resonancewarp_lp
291     8,  // fut_resonancewarp_hp
292     8,  // fut_resonancewarp_n
293     8,  // fut_resonancewarp_bp
294     8,  // fut_resonancewarp_ap
295 };
296 
297 enum fu_subtype
298 {
299     st_SVF = 0,
300     st_Rough = 1,
301     st_Smooth = 2,
302     st_Medium = 3, // disabled
303     st_Notch = 0,
304     st_NotchMild = 1,
305 };
306 
307 struct FilterSelectorMapper : public ParameterDiscreteIndexRemapper
308 {
309     std::vector<std::pair<int, std::string>> mapping;
310     std::unordered_map<int, int> inverseMapping;
pFilterSelectorMapper311     void p(int i, std::string s) { mapping.push_back(std::make_pair(i, s)); }
FilterSelectorMapperFilterSelectorMapper312     FilterSelectorMapper()
313     {
314         p(fut_none, "");
315 
316         p(fut_lp12, "Lowpass");
317         p(fut_lp24, "Lowpass");
318         p(fut_lpmoog, "Lowpass");
319         p(fut_vintageladder, "Lowpass");
320         p(fut_k35_lp, "Lowpass");
321         p(fut_diode, "Lowpass");
322         p(fut_obxd_2pole_lp, "Lowpass"); // ADJ
323         p(fut_obxd_4pole, "Lowpass");
324         p(fut_cutoffwarp_lp, "Lowpass");
325         p(fut_resonancewarp_lp, "Lowpass");
326 
327         p(fut_bp12, "Bandpass");
328         p(fut_bp24, "Bandpass");
329         p(fut_obxd_2pole_bp, "Bandpass");
330         p(fut_cutoffwarp_bp, "Bandpass");
331         p(fut_resonancewarp_bp, "Bandpass");
332 
333         p(fut_hp12, "Highpass");
334         p(fut_hp24, "Highpass");
335         p(fut_k35_hp, "Highpass");
336         p(fut_obxd_2pole_hp, "Highpass");
337         p(fut_cutoffwarp_hp, "Highpass");
338         p(fut_resonancewarp_hp, "Highpass");
339 
340         p(fut_notch12, "Notch");
341         p(fut_notch24, "Notch");
342         p(fut_obxd_2pole_n, "Notch");
343         p(fut_cutoffwarp_n, "Notch");
344         p(fut_resonancewarp_n, "Notch");
345 
346         p(fut_apf, "Effect");
347         p(fut_cutoffwarp_ap, "Effect");
348         p(fut_resonancewarp_ap, "Effect");
349         p(fut_comb_pos, "Effect");
350         p(fut_comb_neg, "Effect");
351         p(fut_SNH, "Effect");
352 
353         int c = 0;
354         for (auto e : mapping)
355             inverseMapping[e.first] = c++;
356 
357         if (mapping.size() != n_fu_types)
358             std::cout << "BAD MAPPING TYPES" << std::endl;
359     }
360 
remapStreamedIndexToDisplayIndexFilterSelectorMapper361     virtual int remapStreamedIndexToDisplayIndex(int i) override { return inverseMapping[i]; }
nameAtStreamedIndexFilterSelectorMapper362     virtual std::string nameAtStreamedIndex(int i) override { return fut_menu_names[i]; }
hasGroupNamesFilterSelectorMapper363     virtual bool hasGroupNames() override { return true; };
364 
groupNameAtStreamedIndexFilterSelectorMapper365     virtual std::string groupNameAtStreamedIndex(int i) override
366     {
367         return mapping[inverseMapping[i]].second;
368     }
369 
sortGroupNamesFilterSelectorMapper370     virtual bool sortGroupNames() override { return false; }
useRemappedOrderingForGroupsIfNotSortedFilterSelectorMapper371     bool useRemappedOrderingForGroupsIfNotSorted() override { return true; }
372 
supportsTotalIndexOrderingFilterSelectorMapper373     virtual bool supportsTotalIndexOrdering() override { return true; }
totalIndexOrderingFilterSelectorMapper374     virtual const std::vector<int> totalIndexOrdering() override
375     {
376         auto res = std::vector<int>();
377         for (auto m : mapping)
378             res.push_back(m.first);
379         return res;
380     }
381 };
382 
383 /*
384  * Finally we need to map streaming indices to positions on the glyph display. This
385  * should *really* be in UI code but it is just a declaration and having all the declarations
386  * together is useful. In the far distant future perhaps we customize this by skin.
387  */
388 
389 const int lprow = 1;
390 const int bprow = 2;
391 const int hprow = 3;
392 const int nrow = 4;
393 const int fxrow = 5;
394 const int fut_glyph_index[n_fu_types][2] = {
395     {0, 0},     // fut_none
396     {0, lprow}, // fut_lp12
397     {1, lprow}, // fut_lp24
398     {3, lprow}, // fut_lpmoog
399     {0, hprow}, // fut_hp12
400     {1, hprow}, // fut_hp24
401     {0, bprow}, // fut_bp12
402     {0, nrow},  // fut_notch12
403     {1, fxrow}, // fut_comb_pos
404     {3, fxrow}, // fut_SNH
405     {4, lprow}, // fut_vintageladder
406     {6, lprow}, // fut_obxd_2pole
407     {7, lprow}, // fut_obxd_4pole
408     {2, lprow}, // fut_k35_lp
409     {2, hprow}, // fut_k35_hp
410     {5, lprow}, // fut_diode
411     {8, lprow}, // fut_cutoffwarp_lp
412     {4, hprow}, // fut_cutoffwarp_hp
413     {3, nrow},  // fut_cutoffwarp_n
414     {3, bprow}, // fut_cutoffwarp_bp
415     {3, hprow}, // fut_obxd_2pole_hp,
416     {2, nrow},  // fut_obxd_2pole_n,
417     {2, bprow}, // fut_obxd_2pole_bp,
418     {1, bprow}, // fut_bp24,
419     {1, nrow},  // fut_notch24,
420     {2, fxrow}, // fut_comb_neg,
421     {0, fxrow}, // fut_apf
422     {0, fxrow}, // fut_cutoffwarp_ap (this is temporarily set to just use the regular AP glyph)
423     {9, lprow}, // fut_resonancewarp_lp
424     {5, hprow}, // fut_resonancewarp_hp
425     {4, nrow},  // fut_resonancewarp_n
426     {4, bprow}, // fut_resonancewarp_bp
427     {0, fxrow}, // fut_resonancewarp_ap (also temporarily set to just use the regular AP glyph)
428 };
429