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 #pragma once
17
18 #include <random>
19
20 enum modsrctype
21 {
22 mst_undefined = 0,
23 mst_controller,
24 mst_adsr,
25 mst_lfo,
26 mst_stepseq,
27 };
28
29 enum modsources
30 {
31 ms_original = 0,
32 ms_velocity,
33 ms_keytrack,
34 ms_polyaftertouch,
35 ms_aftertouch,
36 ms_pitchbend,
37 ms_modwheel,
38 ms_ctrl1,
39 ms_ctrl2,
40 ms_ctrl3,
41 ms_ctrl4,
42 ms_ctrl5,
43 ms_ctrl6,
44 ms_ctrl7,
45 ms_ctrl8,
46 ms_ampeg,
47 ms_filtereg,
48 ms_lfo1,
49 ms_lfo2,
50 ms_lfo3,
51 ms_lfo4,
52 ms_lfo5,
53 ms_lfo6,
54 ms_slfo1,
55 ms_slfo2,
56 ms_slfo3,
57 ms_slfo4,
58 ms_slfo5,
59 ms_slfo6,
60 ms_timbre,
61 ms_releasevelocity,
62 ms_random_bipolar,
63 ms_random_unipolar,
64 ms_alternate_bipolar,
65 ms_alternate_unipolar,
66 ms_breath,
67 ms_expression,
68 ms_sustain,
69 ms_lowest_key,
70 ms_highest_key,
71 ms_latest_key,
72 n_modsources,
73 };
74
75 const int modsource_display_order[n_modsources] = {
76 ms_original,
77 ms_velocity,
78 ms_releasevelocity,
79 ms_keytrack,
80 ms_lowest_key,
81 ms_highest_key,
82 ms_latest_key,
83 ms_polyaftertouch,
84 ms_aftertouch,
85 ms_modwheel,
86 ms_breath,
87 ms_expression,
88 ms_sustain,
89 ms_pitchbend,
90 ms_timbre,
91 ms_alternate_bipolar,
92 ms_alternate_unipolar,
93 ms_random_bipolar,
94 ms_random_unipolar,
95 ms_filtereg,
96 ms_ampeg,
97 ms_lfo1,
98 ms_lfo2,
99 ms_lfo3,
100 ms_lfo4,
101 ms_lfo5,
102 ms_lfo6,
103 ms_slfo1,
104 ms_slfo2,
105 ms_slfo3,
106 ms_slfo4,
107 ms_slfo5,
108 ms_slfo6,
109 ms_ctrl1,
110 ms_ctrl2,
111 ms_ctrl3,
112 ms_ctrl4,
113 ms_ctrl5,
114 ms_ctrl6,
115 ms_ctrl7,
116 ms_ctrl8,
117 };
118
119 const int n_customcontrollers = 8;
120 const int num_metaparameters = n_customcontrollers;
121 extern float samplerate_inv;
122 extern float samplerate;
123
124 const char modsource_names_button[n_modsources][32] = {
125 "Off", "Velocity", "Keytrack", "Poly AT", "Channel AT", "Pitch Bend",
126 "Modwheel", "Macro 1", "Macro 2", "Macro 3", "Macro 4", "Macro 5",
127 "Macro 6", "Macro 7", "Macro 8", "Amp EG", "Filter EG", "LFO 1",
128 "LFO 2", "LFO 3", "LFO 4", "LFO 5", "LFO 6", "S-LFO 1",
129 "S-LFO 2", "S-LFO 3", "S-LFO 4", "S-LFO 5", "S-LFO 6", "MPE Timbre",
130 "Rel Velocity", "Random", "Random Uni", "Alternate", "Alternate Uni", "Breath",
131 "Expression", "Sustain", "Lowest Key", "Highest Key", "Latest Key",
132 };
133
134 const char modsource_names[n_modsources][32] = {
135 "Off",
136 "Velocity",
137 "Keytrack",
138 "Polyphonic Aftertouch",
139 "Channel Aftertouch",
140 "Pitch Bend",
141 "Modulation Wheel",
142 "Macro 1",
143 "Macro 2",
144 "Macro 3",
145 "Macro 4",
146 "Macro 5",
147 "Macro 6",
148 "Macro 7",
149 "Macro 8",
150 "Amp EG",
151 "Filter EG",
152 "Voice LFO 1",
153 "Voice LFO 2",
154 "Voice LFO 3",
155 "Voice LFO 4",
156 "Voice LFO 5",
157 "Voice LFO 6",
158 "Scene LFO 1",
159 "Scene LFO 2",
160 "Scene LFO 3",
161 "Scene LFO 4",
162 "Scene LFO 5",
163 "Scene LFO 6",
164 "MPE Timbre",
165 "Release Velocity",
166 "Random Bipolar",
167 "Random Unipolar",
168 "Alternate Bipolar",
169 "Alternate Unipolar",
170 "Breath",
171 "Expression",
172 "Sustain Pedal",
173 "Lowest Key",
174 "Highest Key",
175 "Latest Key",
176 };
177
178 const char modsource_names_tag[n_modsources][32] = {
179 "off", "vel", "keytrack", "poly_at", "chan_at", "pbend", "mwheel",
180 "macro1", "macro2", "macro3", "macro4", "macro5", "macro6", "macro7",
181 "macro8", "amp_eg", "filter_eg", "lfo1", "lfo2", "lfo3", "lfo4",
182 "lfo5", "lfo6", "slfo1", "slfo2", "slfo3", "slfo4", "slfo5",
183 "slfo6", "timbre", "release_vel", "random", "random_uni", "alt", "alt_uni",
184 "breath", "expr", "sustain", "lowest_key", "highest_key", "latest_key",
185 };
186
187 const int modsource_grid_xy[n_modsources][2] = {
188 {0, 0}, // Velocity
189 {0, 3}, // Keytrack
190 {6, 7}, // Poly AT
191 {2, 3}, // Channel
192 {3, 3}, // AT
193 {4, 3}, // Pitch Bend
194 {5, 3}, // Modwheel
195 {0, 0}, // Macro 1
196 {1, 0}, // Macro 2
197 {2, 0}, // Macro 3
198 {3, 0}, // Macro 4
199 {4, 0}, // Macro 5
200 {5, 0}, // Macro 6
201 {6, 0}, // Macro 7
202 {7, 0}, // Macro 8
203 {7, 5}, // AEG
204 {6, 5}, // FEG
205 {0, 5}, // LFO 1
206 {1, 5}, // LFO 2
207 {2, 5}, // LFO 3
208 {3, 5}, // LFO 4
209 {4, 5}, // LFO 5
210 {5, 5}, // LFO 6
211 {0, 7}, // S-LFO 1
212 {1, 7}, // S-LFO 2
213 {2, 7}, // S-LFO 3
214 {3, 7}, // S-LFO 4
215 {4, 7}, // S-LFO 5
216 {5, 7}, // S-LFO 6
217 {9, 3}, // Timbre
218 {1, 3}, // Release Velocity
219 {8, 5}, // Random Bi
220 {8, 5}, // Random Uni
221 {9, 5}, // Alternate Bi
222 {9, 5}, // Alternate Uni
223 {6, 3}, // Breath
224 {7, 3}, // Expression
225 {8, 3}, // Sustain
226 {7, 7}, // Lowest Key
227 {8, 7}, // Highest Key
228 {9, 7}, // Latest Key
229 };
230
isScenelevel(modsources ms)231 inline bool isScenelevel(modsources ms)
232 {
233 return (((ms <= ms_ctrl8) || ((ms >= ms_slfo1) && (ms <= ms_slfo6))) &&
234 ((ms != ms_velocity) && (ms != ms_keytrack) && (ms != ms_polyaftertouch) &&
235 (ms != ms_releasevelocity))) ||
236 ((ms >= ms_breath) && (ms <= ms_latest_key));
237 }
238
canModulateMonophonicTarget(modsources ms)239 inline bool canModulateMonophonicTarget(modsources ms)
240 {
241 return isScenelevel(ms) || ms == ms_aftertouch;
242 }
243
isCustomController(modsources ms)244 inline bool isCustomController(modsources ms) { return (ms >= ms_ctrl1) && (ms <= ms_ctrl8); }
245
isEnvelope(modsources ms)246 inline bool isEnvelope(modsources ms) { return (ms == ms_ampeg) || (ms == ms_filtereg); }
247
isLFO(modsources ms)248 inline bool isLFO(modsources ms) { return (ms >= ms_lfo1) && (ms <= ms_slfo6); }
249
canModulateModulators(modsources ms)250 inline bool canModulateModulators(modsources ms) { return (ms != ms_ampeg) && (ms != ms_filtereg); }
251
isVoiceModulator(modsources ms)252 inline bool isVoiceModulator(modsources ms) { return !((ms >= ms_slfo1) && (ms <= ms_slfo6)); }
253
canModulateVoiceModulators(modsources ms)254 inline bool canModulateVoiceModulators(modsources ms)
255 {
256 return (ms <= ms_ctrl8) || ms == ms_timbre;
257 }
258
259 struct ModulationRouting
260 {
261 int source_id;
262 int destination_id;
263 float depth;
264 };
265
266 class ModulationSource
267 {
268 public:
ModulationSource()269 ModulationSource() {}
~ModulationSource()270 virtual ~ModulationSource() {}
get_title()271 virtual const char *get_title() { return 0; }
get_type()272 virtual int get_type() { return mst_undefined; }
process_block()273 virtual void process_block() {}
attack()274 virtual void attack(){};
release()275 virtual void release(){};
reset()276 virtual void reset(){};
get_output()277 virtual float get_output() { return output; }
get_output01()278 virtual float get_output01() { return output; }
per_voice()279 virtual bool per_voice() { return false; }
is_bipolar()280 virtual bool is_bipolar() { return false; }
set_bipolar(bool b)281 virtual void set_bipolar(bool b) {}
282 float output;
283 };
284
285 class ControllerModulationSource : public ModulationSource
286 {
287 public:
288 // Smoothing and Shaping Behaviors
289 enum SmoothingMode
290 {
291 LEGACY = -1, // This is (1) the exponential backoff and (2) not streamed.
292 SLOW_EXP, // Legacy with a sigma clamp
293 FAST_EXP, // Faster Legacy with a sigma clamp
294 FAST_LINE, // Linearly move
295 DIRECT // Apply the value directly
296 } smoothingMode = LEGACY;
297
ControllerModulationSource()298 ControllerModulationSource()
299 {
300 target = 0.f;
301 output = 0.f;
302 bipolar = false;
303 changed = true;
304 smoothingMode = LEGACY;
305 }
ControllerModulationSource(SmoothingMode mode)306 ControllerModulationSource(SmoothingMode mode) : ControllerModulationSource()
307 {
308 smoothingMode = mode;
309 }
310
~ControllerModulationSource()311 virtual ~ControllerModulationSource() {}
set_target(float f)312 void set_target(float f)
313 {
314 target = f;
315 startingpoint = output;
316 changed = true;
317 }
318
init(float f)319 void init(float f)
320 {
321 target = f;
322 output = f;
323 startingpoint = f;
324 changed = true;
325 }
326
327 void set_target01(float f, bool updatechanged = true)
328 {
329 if (bipolar)
330 target = 2.f * f - 1.f;
331 else
332 target = f;
333 startingpoint = output;
334 if (updatechanged)
335 changed = true;
336 }
337
get_output01()338 virtual float get_output01() override
339 {
340 if (bipolar)
341 return 0.5f + 0.5f * output;
342 return output;
343 }
344
get_target01()345 virtual float get_target01()
346 {
347 if (bipolar)
348 return 0.5f + 0.5f * target;
349 return target;
350 }
351
has_changed(bool reset)352 virtual bool has_changed(bool reset)
353 {
354 if (changed)
355 {
356 if (reset)
357 changed = false;
358 return true;
359 }
360 return false;
361 }
362
reset()363 virtual void reset() override
364 {
365 target = 0.f;
366 output = 0.f;
367 bipolar = false;
368 }
processSmoothing(SmoothingMode mode,float sigma)369 inline void processSmoothing(SmoothingMode mode, float sigma)
370 {
371 if (mode == LEGACY || mode == SLOW_EXP || mode == FAST_EXP)
372 {
373 float b = fabs(target - output);
374 if (b < sigma && mode != LEGACY)
375 {
376 output = target;
377 }
378 else
379 {
380 float a = (mode == FAST_EXP ? 0.99f : 0.9f) * 44100 * samplerate_inv * b;
381 output = (1 - a) * output + a * target;
382 }
383 return;
384 };
385 if (mode == FAST_LINE)
386 {
387 /*
388 * Apply a constant change until we get there.
389 * Rate is set so we cover the entire range (0,1)
390 * in 50 blocks at 44k
391 */
392 float sampf = samplerate / 44100;
393 float da = (target - startingpoint) / (50 * sampf);
394 float b = target - output;
395 if (fabs(b) < fabs(da))
396 {
397 output = target;
398 }
399 else
400 {
401 output += da;
402 }
403 }
404 if (mode == DIRECT)
405 {
406 output = target;
407 }
408 }
process_block()409 virtual void process_block() override
410 {
411 processSmoothing(smoothingMode, smoothingMode == FAST_EXP ? 0.005f : 0.0025f);
412 }
413
process_block_until_close(float sigma)414 virtual bool process_block_until_close(float sigma)
415 {
416 if (smoothingMode == LEGACY)
417 processSmoothing(SLOW_EXP, sigma);
418 else
419 processSmoothing(smoothingMode, sigma);
420
421 return (output != target); // continue
422 }
423
is_bipolar()424 virtual bool is_bipolar() override { return bipolar; }
set_bipolar(bool b)425 virtual void set_bipolar(bool b) override { bipolar = b; }
426
427 float target, startingpoint;
428 int id; // can be used to assign the controller to a parameter id
429 bool bipolar;
430 bool changed;
431 };
432
433 class RandomModulationSource : public ModulationSource
434 {
435 public:
RandomModulationSource(bool bp)436 RandomModulationSource(bool bp) : bipolar(bp)
437 {
438 std::random_device rd;
439 gen = std::minstd_rand(rd());
440 if (bp)
441 dis = std::uniform_real_distribution<float>(-1.0, 1.0);
442 else
443 dis = std::uniform_real_distribution<float>(0.0, 1.0);
444 }
445
attack()446 virtual void attack() override { output = dis(gen); }
447
448 bool bipolar;
449 std::minstd_rand gen;
450 std::uniform_real_distribution<float> dis;
451 };
452
453 class AlternateModulationSource : public ModulationSource
454 {
455 public:
AlternateModulationSource(bool bp)456 AlternateModulationSource(bool bp) : state(false)
457 {
458 if (bp)
459 nv = -1;
460 else
461 nv = 0;
462
463 pv = 1;
464 }
465
attack()466 virtual void attack() override
467 {
468 if (state)
469 output = pv;
470 else
471 output = nv;
472 state = !state;
473 }
474
475 bool state;
476 float nv, pv;
477 };
478