1 // Copyright 2017 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Multi-stage envelope
28 
29 #include "stages/segment_generator.h"
30 
31 #include "stmlib/dsp/dsp.h"
32 #include "stmlib/dsp/parameter_interpolator.h"
33 #include "stmlib/dsp/units.h"
34 
35 #include <cassert>
36 #include <cmath>
37 #include <algorithm>
38 
39 #include "stages/resources.h"
40 
41 namespace stages {
42 
43 using namespace stmlib;
44 using namespace std;
45 using namespace segment;
46 
47 // Duration of the "tooth" in the output when a trigger is received while the
48 // output is high.
49 const int kRetrigDelaySamples = 32;
50 
51 // S&H delay (for all those sequencers whose CV and GATE outputs are out of
52 // sync).
53 const size_t kSampleAndHoldDelay = kSampleRate * 2 / 1000;  // 2 milliseconds
54 
Init()55 void SegmentGenerator::Init() {
56   process_fn_ = &SegmentGenerator::ProcessMultiSegment;
57 
58   phase_ = 0.0f;
59 
60   zero_ = 0.0f;
61   half_ = 0.5f;
62   one_ = 1.0f;
63 
64   start_ = 0.0f;
65   value_ = 0.0f;
66   lp_ = 0.0f;
67 
68   monitored_segment_ = 0;
69   active_segment_ = 0;
70   retrig_delay_ = 0;
71   primary_ = 0;
72 
73   Segment s;
74   s.start = &zero_;
75   s.end = &zero_;
76   s.time = &zero_;
77   s.curve = &half_;
78   s.portamento = &zero_;
79   s.phase = NULL;
80   s.if_rising = 0;
81   s.if_falling = 0;
82   s.if_complete = 0;
83   fill(&segments_[0], &segments_[kMaxNumSegments + 1], s);
84 
85   Parameters p;
86   p.primary = 0.0f;
87   p.secondary = 0.0f;
88   fill(&parameters_[0], &parameters_[kMaxNumSegments], p);
89 
90   ramp_extractor_.Init(
91       kSampleRate,
92       1000.0f / kSampleRate);
93   ramp_division_quantizer_.Init();
94   delay_line_.Init();
95   gate_delay_.Init();
96 
97   num_segments_ = 0;
98 }
99 
WarpPhase(float t,float curve) const100 inline float SegmentGenerator::WarpPhase(float t, float curve) const {
101   curve -= 0.5f;
102   const bool flip = curve < 0.0f;
103   if (flip) {
104     t = 1.0f - t;
105   }
106   const float a = 128.0f * curve * curve;
107   t = (1.0f + a) * t / (1.0f + a * t);
108   if (flip) {
109     t = 1.0f - t;
110   }
111   return t;
112 }
113 
RateToFrequency(float rate) const114 inline float SegmentGenerator::RateToFrequency(float rate) const {
115   int32_t i = static_cast<int32_t>(rate * 2048.0f);
116   CONSTRAIN(i, 0, LUT_ENV_FREQUENCY_SIZE);
117   return lut_env_frequency[i];
118 }
119 
PortamentoRateToLPCoefficient(float rate) const120 inline float SegmentGenerator::PortamentoRateToLPCoefficient(float rate) const {
121   int32_t i = static_cast<int32_t>(rate * 512.0f);
122   return lut_portamento_coefficient[i];
123 }
124 
ProcessMultiSegment(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)125 void SegmentGenerator::ProcessMultiSegment(
126     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
127   float phase = phase_;
128   float start = start_;
129   float lp = lp_;
130   float value = value_;
131 
132   while (size--) {
133     const Segment& segment = segments_[active_segment_];
134 
135     if (segment.time) {
136       phase += RateToFrequency(*segment.time);
137     }
138 
139     bool complete = phase >= 1.0f;
140     if (complete) {
141       phase = 1.0f;
142     }
143     value = Crossfade(
144         start,
145         *segment.end,
146         WarpPhase(segment.phase ? *segment.phase : phase, *segment.curve));
147 
148     ONE_POLE(lp, value, PortamentoRateToLPCoefficient(*segment.portamento));
149 
150     // Decide what to do next.
151     int go_to_segment = -1;
152     if (*gate_flags & GATE_FLAG_RISING) {
153       go_to_segment = segment.if_rising;
154     } else if (*gate_flags & GATE_FLAG_FALLING) {
155       go_to_segment = segment.if_falling;
156     } else if (complete) {
157       go_to_segment = segment.if_complete;
158     }
159 
160     if (go_to_segment != -1) {
161       phase = 0.0f;
162       const Segment& destination = segments_[go_to_segment];
163       start = destination.start
164           ? *destination.start
165           : (go_to_segment == active_segment_ ? start : value);
166       active_segment_ = go_to_segment;
167     }
168 
169     out->value = lp;
170     out->phase = phase;
171     out->segment = active_segment_;
172     ++gate_flags;
173     ++out;
174   }
175   phase_ = phase;
176   start_ = start;
177   lp_ = lp;
178   value_ = value;
179 }
180 
ProcessDecayEnvelope(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)181 void SegmentGenerator::ProcessDecayEnvelope(
182     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
183   const float frequency = RateToFrequency(parameters_[0].primary);
184   while (size--) {
185     if (*gate_flags & GATE_FLAG_RISING) {
186       phase_ = 0.0f;
187       active_segment_ = 0;
188     }
189 
190     phase_ += frequency;
191     if (phase_ >= 1.0f) {
192       phase_ = 1.0f;
193       active_segment_ = 1;
194     }
195     lp_ = value_ = 1.0f - WarpPhase(phase_, parameters_[0].secondary);
196     out->value = lp_;
197     out->phase = phase_;
198     out->segment = active_segment_;
199     ++gate_flags;
200     ++out;
201   }
202 }
203 
ProcessTimedPulseGenerator(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)204 void SegmentGenerator::ProcessTimedPulseGenerator(
205     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
206   const float frequency = RateToFrequency(parameters_[0].secondary);
207 
208   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
209   while (size--) {
210     if (*gate_flags & GATE_FLAG_RISING) {
211       retrig_delay_ = active_segment_ == 0 ? kRetrigDelaySamples : 0;
212       phase_ = 0.0f;
213       active_segment_ = 0;
214     }
215     if (retrig_delay_) {
216       --retrig_delay_;
217     }
218     phase_ += frequency;
219     if (phase_ >= 1.0f) {
220       phase_ = 1.0f;
221       active_segment_ = 1;
222     }
223 
224     const float p = primary.Next();
225     lp_ = value_ = active_segment_ == 0 && !retrig_delay_ ? p : 0.0f;
226     out->value = lp_;
227     out->phase = phase_;
228     out->segment = active_segment_;
229     ++gate_flags;
230     ++out;
231   }
232 }
233 
ProcessGateGenerator(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)234 void SegmentGenerator::ProcessGateGenerator(
235     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
236   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
237   while (size--) {
238     active_segment_ = *gate_flags & GATE_FLAG_HIGH ? 0 : 1;
239 
240     const float p = primary.Next();
241     lp_ = value_ = active_segment_ == 0 ? p : 0.0f;
242     out->value = lp_;
243     out->phase = 0.5f;
244     out->segment = active_segment_;
245     ++gate_flags;
246     ++out;
247   }
248 }
249 
ProcessSampleAndHold(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)250 void SegmentGenerator::ProcessSampleAndHold(
251     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
252   const float coefficient = PortamentoRateToLPCoefficient(
253       parameters_[0].secondary);
254   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
255 
256   while (size--) {
257     const float p = primary.Next();
258     gate_delay_.Write(*gate_flags);
259     if (gate_delay_.Read(kSampleAndHoldDelay) & GATE_FLAG_RISING) {
260       value_ = p;
261     }
262     active_segment_ = *gate_flags & GATE_FLAG_HIGH ? 0 : 1;
263 
264     ONE_POLE(lp_, value_, coefficient);
265     out->value = lp_;
266     out->phase = 0.5f;
267     out->segment = active_segment_;
268     ++gate_flags;
269     ++out;
270   }
271 }
272 
ProcessClockedSampleAndHold(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)273 void SegmentGenerator::ProcessClockedSampleAndHold(
274     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
275   const float frequency = RateToFrequency(parameters_[0].secondary);
276   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
277   while (size--) {
278     phase_ += frequency;
279     if (phase_ >= 1.0f) {
280       phase_ -= 1.0f;
281 
282       const float reset_time = phase_ / frequency;
283       value_ = primary.subsample(1.0f - reset_time);
284     }
285     primary.Next();
286     active_segment_ = phase_ < 0.5f ? 0 : 1;
287     out->value = value_;
288     out->phase = phase_;
289     out->segment = active_segment_;
290     ++out;
291   }
292 }
293 
294 Ratio divider_ratios[] = {
295   { 0.249999f, 4 },
296   { 0.333333f, 3 },
297   { 0.499999f, 2 },
298   { 0.999999f, 1 },
299   { 1.999999f, 1 },
300   { 2.999999f, 1 },
301   { 3.999999f, 1 },
302 };
303 
ProcessTapLFO(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)304 void SegmentGenerator::ProcessTapLFO(
305     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
306   float ramp[12];
307   Ratio r = ramp_division_quantizer_.Lookup(
308       divider_ratios, parameters_[0].primary * 1.03f, 7);
309   ramp_extractor_.Process(r, gate_flags, ramp, size);
310   for (size_t i = 0; i < size; ++i) {
311     out[i].phase = ramp[i];
312   }
313   ShapeLFO(parameters_[0].secondary, out, size);
314   active_segment_ = out[size - 1].segment;
315 }
316 
ProcessFreeRunningLFO(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)317 void SegmentGenerator::ProcessFreeRunningLFO(
318     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
319   float f = 96.0f * (parameters_[0].primary - 0.5f);
320   CONSTRAIN(f, -128.0f, 127.0f);
321   const float frequency = SemitonesToRatio(f) * 2.0439497f / kSampleRate;
322 
323   active_segment_ = 0;
324   for (size_t i = 0; i < size; ++i) {
325     phase_ += frequency;
326     if (phase_ >= 1.0f) {
327       phase_ -= 1.0f;
328     }
329     out[i].phase = phase_;
330   }
331   ShapeLFO(parameters_[0].secondary, out, size);
332   active_segment_ = out[size - 1].segment;
333 }
334 
ProcessDelay(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)335 void SegmentGenerator::ProcessDelay(
336     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
337   const float max_delay = static_cast<float>(kMaxDelay - 1);
338 
339   float delay_time = SemitonesToRatio(
340       2.0f * (parameters_[0].secondary - 0.5f) * 36.0f) * 0.5f * kSampleRate;
341   float clock_frequency = 1.0f;
342   float delay_frequency = 1.0f / delay_time;
343 
344   if (delay_time >= max_delay) {
345     clock_frequency = max_delay * delay_frequency;
346     delay_time = max_delay;
347   }
348   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
349 
350   active_segment_ = 0;
351   while (size--) {
352     phase_ += clock_frequency;
353     ONE_POLE(lp_, primary.Next(), clock_frequency);
354     if (phase_ >= 1.0f) {
355       phase_ -= 1.0f;
356       delay_line_.Write(lp_);
357     }
358 
359     aux_ += delay_frequency;
360     if (aux_ >= 1.0f) {
361       aux_ -= 1.0f;
362     }
363     active_segment_ = aux_ < 0.5f ? 0 : 1;
364 
365     ONE_POLE(
366         value_,
367         delay_line_.Read(delay_time - phase_),
368         clock_frequency);
369     out->value = value_;
370     out->phase = aux_;
371     out->segment = active_segment_;
372     ++out;
373   }
374 }
375 
ProcessPortamento(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)376 void SegmentGenerator::ProcessPortamento(
377     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
378   const float coefficient = PortamentoRateToLPCoefficient(
379       parameters_[0].secondary);
380   ParameterInterpolator primary(&primary_, parameters_[0].primary, size);
381 
382   active_segment_ = 0;
383   while (size--) {
384     value_ = primary.Next();
385     ONE_POLE(lp_, value_, coefficient);
386     out->value = lp_;
387     out->phase = 0.5f;
388     out->segment = active_segment_;
389     ++out;
390   }
391 }
392 
ProcessZero(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)393 void SegmentGenerator::ProcessZero(
394     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
395 
396   value_ = 0.0f;
397   active_segment_ = 1;
398   while (size--) {
399     out->value = 0.0f;
400     out->phase = 0.5f;
401     out->segment = 1;
402     ++out;
403   }
404 }
405 
ProcessSlave(const GateFlags * gate_flags,SegmentGenerator::Output * out,size_t size)406 void SegmentGenerator::ProcessSlave(
407     const GateFlags* gate_flags, SegmentGenerator::Output* out, size_t size) {
408   while (size--) {
409     active_segment_ = out->segment == monitored_segment_ ? 0 : 1;
410     out->value = active_segment_ ? 0.0f : 1.0f - out->phase;
411     ++out;
412   }
413 }
414 
415 /* static */
ShapeLFO(float shape,SegmentGenerator::Output * in_out,size_t size)416 void SegmentGenerator::ShapeLFO(
417     float shape,
418     SegmentGenerator::Output* in_out,
419     size_t size) {
420   shape -= 0.5f;
421   shape = 2.0f + 9.999999f * shape / (1.0f + 3.0f * fabs(shape));
422 
423   const float slope = min(shape * 0.5f, 0.5f);
424   const float plateau_width = max(shape - 3.0f, 0.0f);
425   const float sine_amount = max(
426       shape < 2.0f ? shape - 1.0f : 3.0f - shape, 0.0f);
427 
428   const float slope_up = 1.0f / slope;
429   const float slope_down = 1.0f / (1.0f - slope);
430   const float plateau = 0.5f * (1.0f - plateau_width);
431   const float normalization = 1.0f / plateau;
432   const float phase_shift = plateau_width * 0.25f;
433 
434   while (size--) {
435     float phase = in_out->phase + phase_shift;
436     if (phase > 1.0f) {
437       phase -= 1.0f;
438     }
439     float triangle = phase < slope
440         ? slope_up * phase
441         : 1.0f - (phase - slope) * slope_down;
442     triangle -= 0.5f;
443     CONSTRAIN(triangle, -plateau, plateau);
444     triangle = triangle * normalization;
445     float sine = InterpolateWrap(lut_sine, phase + 0.75f, 1024.0f);
446     in_out->value = 0.5f * Crossfade(triangle, sine, sine_amount) + 0.5f;
447     in_out->segment = phase < 0.5f ? 0 : 1;
448     ++in_out;
449   }
450 }
451 
Configure(bool has_trigger,const Configuration * segment_configuration,int num_segments)452 void SegmentGenerator::Configure(
453     bool has_trigger,
454     const Configuration* segment_configuration,
455     int num_segments) {
456   if (num_segments == 1) {
457     ConfigureSingleSegment(has_trigger, segment_configuration[0]);
458     return;
459   }
460   num_segments_ = num_segments;
461 
462   // assert(has_trigger);
463 
464   process_fn_ = &SegmentGenerator::ProcessMultiSegment;
465 
466   // A first pass to collect loop points, and check for STEP segments.
467   int loop_start = -1;
468   int loop_end = -1;
469   bool has_step_segments = false;
470   int last_segment = num_segments - 1;
471   int first_ramp_segment = -1;
472 
473   for (int i = 0; i <= last_segment; ++i) {
474     has_step_segments = has_step_segments || \
475         segment_configuration[i].type == TYPE_STEP;
476     if (segment_configuration[i].loop) {
477       if (loop_start == -1) {
478         loop_start = i;
479       }
480       loop_end = i;
481     }
482     if (segment_configuration[i].type == TYPE_RAMP) {
483       if (first_ramp_segment == -1) {
484         first_ramp_segment = i;
485       }
486     }
487   }
488 
489   // Check if there are step segments inside the loop.
490   bool has_step_segments_inside_loop = false;
491   if (loop_start != -1) {
492     for (int i = loop_start; i <= loop_end; ++i) {
493       if (segment_configuration[i].type == TYPE_STEP) {
494         has_step_segments_inside_loop = true;
495         break;
496       }
497     }
498   }
499 
500   for (int i = 0; i <= last_segment; ++i) {
501     Segment* s = &segments_[i];
502     if (segment_configuration[i].type == TYPE_RAMP) {
503       s->start = (num_segments == 1) ? &one_ : NULL;
504       s->time = &parameters_[i].primary;
505       s->curve = &parameters_[i].secondary;
506       s->portamento = &zero_;
507       s->phase = NULL;
508 
509       if (i == last_segment) {
510         s->end = &zero_;
511       } else if (segment_configuration[i + 1].type != TYPE_RAMP) {
512         s->end = &parameters_[i + 1].primary;
513       } else if (i == first_ramp_segment) {
514         s->end = &one_;
515       } else {
516         s->end = &parameters_[i].secondary;
517         // The whole "reuse the curve from other segment" thing
518         // is a bit too complicated...
519         //
520         // for (int j = i + 1; j <= last_segment; ++j) {
521         //   if (segment_configuration[j].type == TYPE_RAMP) {
522         //     if (j == last_segment ||
523         //         segment_configuration[j + 1].type != TYPE_RAMP) {
524         //       s->curve = &parameters_[j].secondary;
525         //       break;
526         //     }
527         //   }
528         // }
529         s->curve = &half_;
530       }
531     } else {
532       s->start = s->end = &parameters_[i].primary;
533       s->curve = &half_;
534       if (segment_configuration[i].type == TYPE_STEP) {
535         s->portamento = &parameters_[i].secondary;
536         s->time = NULL;
537         // Sample if there is a loop of length 1 on this segment. Otherwise
538         // track.
539         s->phase = i == loop_start && i == loop_end ? &zero_ : &one_;
540       } else {
541         s->portamento = &zero_;
542         // Hold if there's a loop of length 1 of this segment. Otherwise, use
543         // the programmed time.
544         s->time = i == loop_start && i == loop_end
545             ? NULL : &parameters_[i].secondary;
546         s->phase = &one_;  // Track the changes on the slider.
547       }
548     }
549 
550     s->if_complete = i == loop_end ? loop_start : i + 1;
551     s->if_falling = loop_end == -1 || loop_end == last_segment || has_step_segments ? -1 : loop_end + 1;
552     s->if_rising = 0;
553 
554     if (has_step_segments) {
555       if (!has_step_segments_inside_loop && i >= loop_start && i <= loop_end) {
556         s->if_rising = (loop_end + 1) % num_segments;
557       } else {
558         // Just go to the next stage.
559         // s->if_rising = (i == loop_end) ? loop_start : (i + 1) % num_segments;
560 
561         // Find the next STEP segment.
562         bool follow_loop = loop_end != -1;
563         int next_step = i;
564         while (segment_configuration[next_step].type != TYPE_STEP) {
565           ++next_step;
566           if (follow_loop && next_step == loop_end + 1) {
567             next_step = loop_start;
568             follow_loop = false;
569           }
570           if (next_step >= num_segments) {
571             next_step = num_segments - 1;
572             break;
573           }
574         }
575         s->if_rising = next_step == loop_end
576             ? loop_start
577             : (next_step + 1) % num_segments;
578       }
579     }
580   }
581 
582   Segment* sentinel = &segments_[num_segments];
583   sentinel->end = sentinel->start = segments_[num_segments - 1].end;
584   sentinel->time = &zero_;
585   sentinel->curve = &half_;
586   sentinel->portamento = &zero_;
587   sentinel->if_rising = 0;
588   sentinel->if_falling = -1;
589   sentinel->if_complete = loop_end == last_segment ? 0 : -1;
590 
591   // After changing the state of the module, we go to the sentinel.
592   active_segment_ = num_segments;
593 }
594 
595 /* static */
596 SegmentGenerator::ProcessFn SegmentGenerator::process_fn_table_[12] = {
597   // RAMP
598   &SegmentGenerator::ProcessZero,
599   &SegmentGenerator::ProcessFreeRunningLFO,
600   &SegmentGenerator::ProcessDecayEnvelope,
601   &SegmentGenerator::ProcessTapLFO,
602 
603   // STEP
604   &SegmentGenerator::ProcessPortamento,
605   &SegmentGenerator::ProcessPortamento,
606   &SegmentGenerator::ProcessSampleAndHold,
607   &SegmentGenerator::ProcessSampleAndHold,
608 
609   // HOLD
610   &SegmentGenerator::ProcessDelay,
611   &SegmentGenerator::ProcessDelay,
612   // &SegmentGenerator::ProcessClockedSampleAndHold,
613   &SegmentGenerator::ProcessTimedPulseGenerator,
614   &SegmentGenerator::ProcessGateGenerator
615 };
616 
617 }  // namespace stages