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(¶meters_[0], ¶meters_[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 = ¶meters_[i].primary;
505 s->curve = ¶meters_[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 = ¶meters_[i + 1].primary;
513 } else if (i == first_ramp_segment) {
514 s->end = &one_;
515 } else {
516 s->end = ¶meters_[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 = ¶meters_[j].secondary;
525 // break;
526 // }
527 // }
528 // }
529 s->curve = &half_;
530 }
531 } else {
532 s->start = s->end = ¶meters_[i].primary;
533 s->curve = &half_;
534 if (segment_configuration[i].type == TYPE_STEP) {
535 s->portamento = ¶meters_[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 : ¶meters_[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