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-2021 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 "globals.h"
17 #include "FastMath.h"
18 
19 /*
20  * String oscillator is a self-oscillating delay with various filters and
21  * feedback options.
22  *
23  * The basic circuit is
24  *
25  * At init:
26  * - Excite the delay line with an input. In 'chirp' mode this is only pre-play and
27  *   in 'continous' mode it is scaled by the amplitude during play
28  *
29  * At runtime:
30  * - run two delay lines seeded the same and take two taps, tap1 and tap2,
31  *   and create an output which is (1-mix) * tap1 + mix * tap2
32  * - create a feedback signal fb* tap + excitation in each line
33  * - run that feedback signal through a tone filter in each line
34  * - drive that feedback signal and run it through a soft clipper in each line
35  * - write that feedback signal to the head of the delay line
36  *
37  */
38 
39 #include "StringOscillator.h"
40 
stringosc_excitations_count()41 int stringosc_excitations_count() { return 15; }
42 
stringosc_excitation_name(int i)43 std::string stringosc_excitation_name(int i)
44 {
45     auto m = (StringOscillator::exciter_modes)i;
46 
47     switch (m)
48     {
49     case StringOscillator::burst_noise:
50         return "Burst Noise";
51     case StringOscillator::burst_pink_noise:
52         return "Burst Pink Noise";
53     case StringOscillator::burst_sine:
54         return "Burst Sine";
55     case StringOscillator::burst_ramp:
56         return "Burst Ramp";
57     case StringOscillator::burst_tri:
58         return "Burst Triangle";
59     case StringOscillator::burst_square:
60         return "Burst Square";
61     case StringOscillator::burst_sweep:
62         return "Burst Sweep";
63     case StringOscillator::constant_noise:
64         return "Constant Noise";
65     case StringOscillator::constant_pink_noise:
66         return "Constant Pink Noise";
67     case StringOscillator::constant_sine:
68         return "Constant Sine";
69     case StringOscillator::constant_tri:
70         return "Constant Triangle";
71     case StringOscillator::constant_ramp:
72         return "Constant Ramp";
73     case StringOscillator::constant_square:
74         return "Constant Square";
75     case StringOscillator::constant_sweep:
76         return "Constant Sweep";
77     case StringOscillator::constant_audioin:
78         return "Audio In";
79     }
80     return "Unknown";
81 }
82 
init(float pitch,bool is_display,bool nzi)83 void StringOscillator::init(float pitch, bool is_display, bool nzi)
84 {
85     memset((void *)dustBuffer, 0, 2 * (BLOCK_SIZE_OS) * sizeof(float));
86 
87     id_exciterlvl = oscdata->p[str_exciter_level].param_id_in_scene;
88     id_str1decay = oscdata->p[str_str1_decay].param_id_in_scene;
89     id_str2decay = oscdata->p[str_str2_decay].param_id_in_scene;
90     id_str2detune = oscdata->p[str_str2_detune].param_id_in_scene;
91     id_strbalance = oscdata->p[str_str_balance].param_id_in_scene;
92     id_stiffness = oscdata->p[str_stiffness].param_id_in_scene;
93 
94     if (is_display)
95     {
96         gen = std::minstd_rand(8675309);
97     }
98     else
99     {
100         gen = std::minstd_rand(storage->rand());
101     }
102 
103     urd = std::uniform_real_distribution<float>(0.0, 1.0);
104 
105     auto pitch_t = std::min(148.f, pitch);
106     auto pitchmult_inv =
107         std::max(1.0, dsamplerate_os * (1 / 8.175798915) * storage->note_to_pitch_inv(pitch_t));
108     auto p2off = oscdata->p[str_str2_detune].get_extended(localcopy[id_str2detune].f);
109     double pitch2_t = 1, pitchmult2_inv = 1;
110 
111     if (oscdata->p[str_str2_detune].absolute)
112     {
113         pitch2_t = std::min(148.f, pitch);
114 
115         auto frequency = Tunings::MIDI_0_FREQ * storage->note_to_pitch(pitch2_t);
116         auto fac = oscdata->p[str_str2_detune].extend_range ? 12 * 16 : 16;
117         auto detune = localcopy[id_str2detune].f * fac;
118 
119         frequency = std::max(10.0, frequency + detune);
120         pitchmult2_inv = std::max(1.0, dsamplerate_os / frequency);
121     }
122     else
123     {
124         pitch2_t = std::min(148.f, pitch + p2off);
125         pitchmult2_inv = std::max(1.0, dsamplerate_os * (1 / 8.175798915) *
126                                            storage->note_to_pitch_inv(pitch2_t));
127     }
128 
129     noiseLp.coeff_LP2B(noiseLp.calc_omega(0) * OSC_OVERSAMPLING, 0.9);
130     for (int i = 0; i < 3; ++i)
131     {
132         fillDustBuffer(pitchmult_inv, pitchmult2_inv);
133     }
134 
135     tap[0].startValue(pitchmult_inv);
136     tap[1].startValue(pitchmult2_inv);
137     t2level.startValue(0.5 * limit_range(localcopy[id_strbalance].f, -1.f, 1.f) + 0.5);
138 
139     // we need a big prefill to supprot the delay line for FM
140     auto prefill = (int)floor(10 * std::max(pitchmult_inv, pitchmult2_inv));
141 
142     for (int i = 0; i < 2; ++i)
143     {
144         delayLine[i].clear();
145         driftLFO[i].init(nzi);
146     }
147 
148     auto mode = (exciter_modes)oscdata->p[str_exciter_mode].val.i;
149     phase1 = 0.0, phase2 = 0.0;
150 
151     if (!oscdata->retrigger.val.b && !is_display)
152     {
153         phase1 = urd(gen);
154         phase2 = urd(gen);
155     }
156 
157     auto r1 = 1.0 / pitchmult_inv;
158     auto r2 = 1.0 / pitchmult2_inv;
159     auto d0 = limit_range(localcopy[id_exciterlvl].f, 0.f, 1.f);
160     d0 *= d0 * d0 * d0;
161 
162     int dustrp = BLOCK_SIZE_OS;
163     configureLpAndHpFromTone();
164 
165     for (int i = 0; i < prefill; ++i)
166     {
167         float dlv[2] = {0, 0};
168 
169         switch (mode)
170         {
171         case burst_sine:
172             d0 = 1;
173         case constant_sine:
174         {
175             dlv[0] = (0.707 * d0 * std::sin(2.0 * M_PI * phase1));
176             dlv[1] = (0.707 * d0 * std::sin(2.0 * M_PI * phase2));
177 
178             phase1 += r1;
179             phase2 += r2;
180         }
181         break;
182         case burst_tri:
183             d0 = 1;
184         case constant_tri:
185         {
186             // phase is 0,1 so tri is
187             auto t1 = (phase1 < 0.5) ? (phase1 * 4 - 1) : ((1 - phase1)) * 4 - 1;
188             auto t2 = (phase2 < 0.5) ? (phase2 * 4 - 1) : ((1 - phase2)) * 4 - 1;
189 
190             dlv[0] = (0.707 * d0 * t1);
191             dlv[1] = (0.707 * d0 * t2);
192 
193             phase1 += r1;
194             phase2 += r2;
195 
196             if (phase1 > 1)
197             {
198                 phase1 -= 1;
199             }
200 
201             if (phase2 > 1)
202             {
203                 phase2 -= 1;
204             }
205         }
206         break;
207         case burst_square:
208             d0 = 1;
209         case constant_square:
210         {
211             dlv[0] = (0.707 * d0 * ((phase1 > 0.5) * 2 - 1));
212             dlv[1] = (0.707 * d0 * ((phase2 > 0.5) * 2 - 1));
213 
214             phase1 += r1;
215             phase2 += r2;
216 
217             if (phase1 > 1)
218             {
219                 phase1 -= 1;
220             }
221 
222             if (phase2 > 1)
223             {
224                 phase2 -= 1;
225             }
226         }
227         break;
228         case burst_ramp:
229             d0 = 1;
230         case constant_ramp:
231         {
232             dlv[0] = (0.707 * d0 * (phase1 * 2 - 1));
233             dlv[1] = (0.707 * d0 * (phase2 * 2 - 1));
234 
235             phase1 += r1;
236             phase2 += r2;
237 
238             if (phase1 > 1)
239             {
240                 phase1 -= 1;
241             }
242 
243             if (phase2 > 1)
244             {
245                 phase2 -= 1;
246             }
247         }
248         break;
249         case burst_sweep:
250             d0 = 1;
251         case constant_sweep:
252         {
253             if (phase1 == 0)
254             {
255                 dlv[0] = (0.707 * d0);
256             }
257             else
258             {
259                 dlv[0] = (0.707 * d0 * std::sin(2.0 * M_PI / phase1));
260             }
261 
262             if (phase2 == 0)
263             {
264                 dlv[1] = (0.707 * d0);
265             }
266             else
267             {
268                 dlv[1] = (0.707 * d0 * std::sin(2.0 * M_PI / phase2));
269             }
270 
271             phase1 += r1;
272             phase2 += r2;
273 
274             if (phase1 > 1)
275             {
276                 phase1 -= 1;
277             }
278 
279             if (phase2 > 1)
280             {
281                 phase2 -= 1;
282             }
283         }
284         break;
285 
286         case constant_audioin:
287             dlv[0] = (0);
288             dlv[1] = (0);
289             break;
290 
291         case burst_pink_noise:
292             d0 = 1.0;
293         case constant_pink_noise:
294         {
295             if (dustrp >= BLOCK_SIZE_OS)
296             {
297                 dustrp = 0;
298                 fillDustBuffer(pitchmult_inv, pitchmult2_inv);
299             }
300 
301             dlv[0] = (d0 * dustBuffer[0][dustrp]);
302             dlv[1] = (d0 * dustBuffer[1][dustrp]);
303 
304             dustrp++;
305         }
306         break;
307         case burst_noise:
308             d0 = 1;
309         case constant_noise:
310         default:
311             dlv[0] = (d0 * (urd(gen) * 2 - 1));
312             dlv[1] = (d0 * (urd(gen) * 2 - 1));
313             break;
314         }
315 
316         float lpt[2], hpt[2];
317         lp.process_sample(dlv[0], dlv[1], lpt[0], lpt[1]);
318         hp.process_sample(dlv[0], dlv[1], hpt[0], hpt[1]);
319 
320         for (int t = 0; t < 2; ++t)
321         {
322             delayLine[t].write(tone.v < 0 ? lpt[t] : hpt[t]);
323         }
324     }
325     lp.flush_sample_denormal();
326     hp.flush_sample_denormal();
327 
328     for (int t = 0; t < 2; ++t)
329     {
330         priorSample[t] = delayLine[t].buffer[(delayLine[t].wp - 1) & delayLine[t].comb_size];
331     }
332 
333     charFilt.init(storage->getPatch().character.val.i);
334 }
335 
configureLpAndHpFromTone()336 void StringOscillator::configureLpAndHpFromTone()
337 {
338     tone.newValue(limit_range(localcopy[id_stiffness].f, -1.f, 1.f));
339 
340     float clo = 10, cmidhi = 60, cmid = 100, chi = -70;
341     float hpCutoff = chi;
342     float lpCutoff = cmid;
343 
344     if (tone.v > 0)
345     {
346         // OK so cool scale the HP cutoff
347         auto tv = tone.v;
348         hpCutoff = tv * (cmidhi - chi) + chi;
349     }
350     else
351     {
352         auto tv = -tone.v;
353         lpCutoff = tv * (clo - cmid) + cmid;
354     }
355 
356     // Inefficient - copy coefficients later
357     lp.coeff_LP(lp.calc_omega((lpCutoff / 12.0) - 2.f) * OSC_OVERSAMPLING, 0.707);
358     hp.coeff_HP(hp.calc_omega((hpCutoff / 12.0) - 2.f) * OSC_OVERSAMPLING, 0.707);
359 }
360 
process_block(float pitch,float drift,bool stereo,bool FM,float fmdepthV)361 void StringOscillator::process_block(float pitch, float drift, bool stereo, bool FM, float fmdepthV)
362 {
363 #define P(m)                                                                                       \
364     case m:                                                                                        \
365         if (FM)                                                                                    \
366             process_block_internal<true, m>(pitch, drift, stereo, fmdepthV);                       \
367         else                                                                                       \
368             process_block_internal<false, m>(pitch, drift, stereo, fmdepthV);                      \
369         break;
370 
371     auto mode = (exciter_modes)oscdata->p[str_exciter_mode].val.i;
372 
373     switch (mode)
374     {
375         P(burst_noise)
376         P(burst_pink_noise)
377         P(burst_sine)
378         P(burst_tri)
379         P(burst_ramp)
380         P(burst_square)
381         P(burst_sweep)
382 
383         P(constant_noise)
384         P(constant_pink_noise)
385         P(constant_sine)
386         P(constant_tri)
387         P(constant_ramp)
388         P(constant_square)
389         P(constant_sweep)
390 
391         P(constant_audioin)
392     }
393 
394 #undef P
395 }
396 
397 template <bool FM, StringOscillator::exciter_modes mode>
process_block_internal(float pitch,float drift,bool stereo,float fmdepthV)398 void StringOscillator::process_block_internal(float pitch, float drift, bool stereo, float fmdepthV)
399 {
400     auto lfodetune = drift * driftLFO[0].next();
401     auto pitch_t = std::min(148.f, pitch + lfodetune);
402     auto pitchmult_inv = std::max((FIRipol_N >> 1) + 1.0, dsamplerate_os * (1 / 8.175798915) *
403                                                               storage->note_to_pitch_inv(pitch_t));
404     auto d0 = limit_range(localcopy[id_exciterlvl].f, 0.f, 1.f);
405 
406     if (mode >= constant_noise)
407     {
408         examp.newValue(d0 * d0 * d0 * d0);
409     }
410     else
411     {
412         if (d0 < 0.1)
413         {
414             // 5.6234 = powf(0.1, 0.25) * 10 to match it where powf(d0, 0.25) starts below
415             examp.newValue(d0 * 5.6234);
416         }
417         else
418         {
419             examp.newValue(powf(d0, 0.25));
420         }
421     }
422 
423     auto dp1 = pitch_to_dphase(pitch_t);
424 
425     lfodetune = drift * driftLFO[1].next();
426 
427     double dp2;
428     double pitch2_t = 1, pitchmult2_inv = 1;
429     auto p2off = oscdata->p[str_str2_detune].get_extended(localcopy[id_str2detune].f);
430 
431     if (oscdata->p[str_str2_detune].absolute)
432     {
433         pitch2_t = std::min(148.f, pitch);
434         auto frequency = Tunings::MIDI_0_FREQ * storage->note_to_pitch(pitch2_t);
435 
436         auto fac = oscdata->p[str_str2_detune].extend_range ? 12 * 16 : 16;
437         auto detune = localcopy[id_str2detune].f * fac;
438 
439         frequency = std::max(10.0, frequency + detune);
440         pitchmult2_inv = std::max(1.0, dsamplerate_os / frequency);
441         dp2 = frequency * dsamplerate_os_inv;
442     }
443     else
444     {
445         pitch2_t = std::min(148.f, pitch + p2off);
446         pitchmult2_inv = std::max(1.0, dsamplerate_os * (1 / 8.175798915) *
447                                            storage->note_to_pitch_inv(pitch2_t));
448         dp2 = pitch_to_dphase(pitch2_t);
449     }
450 
451     pitchmult_inv = std::min(pitchmult_inv, (delayLine[0].comb_size - 100) * 1.0);
452     pitchmult2_inv = std::min(pitchmult2_inv, (delayLine[0].comb_size - 100) * 1.0);
453 
454     tap[0].newValue(pitchmult_inv);
455     tap[1].newValue(pitchmult2_inv);
456 
457     t2level.newValue(0.5 * limit_range(localcopy[id_strbalance].f, -1.f, 1.f) + 0.5);
458 
459     auto fbp = limit_range(localcopy[id_str1decay].f, 0.f, 1.f);
460 
461     if (fbp < 0.2)
462     {
463         // go from 0.85 to 0.95
464         feedback[0].newValue(0.85f + (0.5f * fbp));
465     }
466     else
467     {
468         // go from 0.95 to 1.0
469         feedback[0].newValue(0.9375f + (0.0625f * fbp));
470     }
471 
472     auto fbp2 = limit_range(localcopy[id_str2decay].f, 0.f, 1.f);
473 
474     if (fbp2 < 0.2)
475     {
476         feedback[1].newValue(0.85f + (0.5f * fbp2));
477     }
478     else
479     {
480         feedback[1].newValue(0.9375f + (0.0625f * fbp2));
481     }
482 
483     // fmdepthV basically goes 0 -> 16 so lets push it 0,1 for now
484     double fv = fmdepthV / 16.0;
485 
486     fmdepth.newValue(fv);
487 
488     configureLpAndHpFromTone();
489 
490     float val[2] = {0.f, 0.f}, fbNoOutVal[2] = {0.f, 0.f}, fbv[2] = {0, 0};
491 
492     if (mode == constant_pink_noise)
493     {
494         fillDustBuffer(pitchmult_inv, pitchmult2_inv);
495     }
496 
497     for (int i = 0; i < BLOCK_SIZE_OS; ++i)
498     {
499         for (int t = 0; t < 2; ++t)
500         {
501             auto v = tap[t].v;
502             float *phs = (t == 0) ? &phase1 : &phase2;
503             float dp = (t == 0) ? dp1 : dp2;
504 
505             if (FM)
506             {
507                 v *= Surge::DSP::fastexp(limit_range(fmdepth.v * master_osc[i] * 3, -6.f, 4.f));
508             }
509 
510             val[t] = delayLine[t].read(v);
511             fbNoOutVal[t] = 0.f;
512 
513             // Add continuous excitation
514             switch (mode)
515             {
516             case constant_noise:
517             {
518                 val[t] += examp.v * (urd(gen) * 2 - 1);
519             }
520             break;
521             case constant_pink_noise:
522             {
523                 auto ds1 = examp.v * dustBuffer[t][i];
524                 val[t] += ds1;
525             }
526             break;
527             case constant_ramp:
528             {
529                 auto rn = 0.707 * (*phs * 2 - 1);
530 
531                 val[t] += examp.v * rn;
532                 *phs += dp;
533                 *phs -= (*phs > 1);
534             }
535             break;
536             case constant_tri:
537             {
538                 auto rn = 0.707 * ((*phs < 0.5) ? (*phs * 4 - 1) : ((1 - *phs) * 4 - 1));
539 
540                 val[t] += examp.v * rn;
541                 *phs += dp;
542                 *phs -= (*phs > 1);
543             }
544             break;
545             case constant_sweep:
546             {
547                 float sv = 1.0;
548 
549                 if (*phs != 0)
550                 {
551                     sv = std::sin(2.0 * M_PI / *phs);
552                 }
553 
554                 val[t] += examp.v * 0.707 * sv;
555                 *phs += dp;
556                 *phs -= (*phs > 1);
557             }
558             break;
559             case constant_sine:
560             {
561                 float sv = std::sin(2.0 * M_PI * *phs);
562 
563                 val[t] += examp.v * 0.707 * sv;
564                 *phs += dp;
565                 *phs -= (*phs > 1);
566             }
567             break;
568             case constant_square:
569             {
570                 auto rn = 0.707 * ((*phs > 0.5) ? 1 : -1);
571 
572                 val[t] += examp.v * rn;
573                 *phs += dp;
574                 *phs -= (*phs > 1);
575             }
576             break;
577             case constant_audioin:
578             {
579                 fbNoOutVal[t] = examp.v * storage->audio_in[t][i];
580             }
581             break;
582             default:
583                 // We should do something else with amplitude here
584                 val[t] *= examp.v;
585                 break;
586             }
587 
588             // precautionary hard clip
589             fbv[t] = limit_range(val[t] + fbNoOutVal[t], -1.f, 1.f);
590         }
591 
592         float lpv[2], hpv[2];
593         lp.process_sample(fbv[0], fbv[1], lpv[0], lpv[1]);
594         hp.process_sample(fbv[0], fbv[1], hpv[0], hpv[1]);
595 
596         for (int t = 0; t < 2; ++t)
597         {
598             auto filtv = (tone.v > 0) ? hpv[t] : lpv[t];
599 
600             if (fabs(filtv) < 1e-16)
601                 filtv = 0;
602             delayLine[t].write(filtv * feedback[t].v);
603         }
604 
605         float out = val[0] + t2level.v * (val[1] - val[0]);
606 
607         // softclip the output
608         out = out * (1.5 - 0.5 * out * out);
609 
610         tap[0].process();
611         tap[1].process();
612         t2level.process();
613         feedback[0].process();
614         feedback[1].process();
615         tone.process();
616         examp.process();
617         fmdepth.process();
618 
619         output[i] = out;
620         outputR[i] = out;
621     }
622 
623     lp.flush_sample_denormal_aggressive();
624     hp.flush_sample_denormal_aggressive();
625 
626     if (charFilt.doFilter)
627     {
628         if (stereo)
629         {
630             charFilt.process_block_stereo(output, outputR, BLOCK_SIZE_OS);
631         }
632         else
633         {
634             charFilt.process_block(output, BLOCK_SIZE_OS);
635         }
636     }
637 }
638 
init_ctrltypes()639 void StringOscillator::init_ctrltypes()
640 {
641     oscdata->p[str_exciter_mode].set_name("Exciter");
642     oscdata->p[str_exciter_mode].set_type(ct_stringosc_excitation_model);
643 
644     oscdata->p[str_exciter_level].set_name("Exciter Level");
645     oscdata->p[str_exciter_level].set_type(ct_percent);
646     oscdata->p[str_exciter_level].val_default.f = 1.f;
647 
648     oscdata->p[str_str1_decay].set_name("String 1 Decay");
649     oscdata->p[str_str1_decay].set_type(ct_percent);
650     oscdata->p[str_str1_decay].val_default.f = 0.95;
651 
652     oscdata->p[str_str2_decay].set_name("String 2 Decay");
653     oscdata->p[str_str2_decay].set_type(ct_percent);
654     oscdata->p[str_str2_decay].val_default.f = 0.95;
655 
656     oscdata->p[str_str2_detune].set_name("String 2 Detune");
657     oscdata->p[str_str2_detune].set_type(ct_oscspread_bipolar);
658 
659     oscdata->p[str_str_balance].set_name("String Balance");
660     oscdata->p[str_str_balance].set_type(ct_percent_bipolar_stringbal);
661 
662     oscdata->p[str_stiffness].set_name("Stiffness");
663     oscdata->p[str_stiffness].set_type(ct_percent_bipolar);
664 }
665 
init_default_values()666 void StringOscillator::init_default_values()
667 {
668     oscdata->p[str_exciter_mode].val.i = 0;
669     oscdata->p[str_exciter_level].val.f = 1.f;
670 
671     oscdata->p[str_str1_decay].val.f = 0.95f;
672     oscdata->p[str_str2_decay].val.f = 0.95f;
673 
674     oscdata->p[str_str2_detune].val.f = 0.1f;
675     oscdata->p[str_str2_detune].extend_range = false;
676     oscdata->p[str_str_balance].val.f = 0.f;
677 
678     oscdata->p[str_stiffness].val.f = 0.f;
679 }
680 
fillDustBuffer(float tap0,float tap1)681 void StringOscillator::fillDustBuffer(float tap0, float tap1)
682 {
683     for (int i = 0; i < BLOCK_SIZE_OS; ++i)
684     {
685         auto v0 = urd(gen) * 2 - 1;
686         auto v1 = urd(gen) * 2 - 1;
687         noiseLp.process_sample_nolag(v0, v1);
688         dustBuffer[0][i] = v0 * 1.7;
689         dustBuffer[1][i] = v1 * 1.7;
690     }
691 }
692