Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
chorus_family.hpp
Go to the documentation of this file.
1#pragma once
2
106
110#include <pulp/signal/lfo.hpp>
112#include <pulp/signal/units.hpp>
113
114#include <algorithm>
115#include <array>
116#include <cmath>
117#include <cstddef>
118#include <cstdint>
119
120namespace pulp::signal {
121
123template <typename SampleType = float>
125public:
126 enum class Voicing : std::uint8_t { ce2, juno_ensemble, dimension_d, tri_chorus };
127
131 enum class JunoMode : std::uint8_t { mode_I, mode_II, mode_I_plus_II };
132
133 // ── Structural constants ──────────────────────────────────────────────
134
136 static constexpr int kMaxVoices = 3;
137 static constexpr std::size_t kVoiceSlots = static_cast<std::size_t>(kMaxVoices);
138
141 static constexpr int kInterpOrder = 3;
142
147 static constexpr int kGuardSamples = kInterpOrder + 1;
148
154 static constexpr double kMaxDelayMs = 40.0;
155
156 // ── Dimension D constants ─────────────────────────────────────────────
157
161 static constexpr double kTrapK = 1.8;
162
169 static constexpr double kDimCornerHz = 200.0;
170
173 static constexpr double kDimBoostDb = 1.5;
174
175 // ── BBD colour constants ──────────────────────────────────────────────
176
182 static constexpr double kBbdColorCharacter = 1.0;
183
189 static constexpr double kBbdColorGuardMs = 0.5;
190
191 // ── Calibration tables ────────────────────────────────────────────────
192
212
213 static constexpr Calibration calibration(Voicing v) {
214 switch (v) {
215 case Voicing::ce2:
216 // d_center 12 ms [dp, range 5–25], d_depth 6 ms [dp, range
217 // 2–10], rate 1.2 Hz [dp, range 0.05–10], internal blend 0.5
218 // [dp, range 0.3–0.7 — the pedal has no mix knob]. The
219 // enclosing 5–40 ms practical zone and the MN3007's
220 // 5.12–51.2 ms device range are the cited part (ElectroSmash,
221 // "Boss CE-2 Analysis"); the calibration inside it is not
222 // published and is an honest gap.
223 return {12.0, 6.0, 1.2, 0.5, 1, LfoWave::triangle, true, false};
225 // Placeholder row: the Juno's numbers are per-mode and come
226 // from juno_spec(). Only `voices`, `wave` and the routing flags
227 // are read for this voicing.
228 return {3.505, 1.845, 0.513, 0.5, 2, LfoWave::triangle, false, false};
230 // All four numbers [dp] — honest gap. d_center 6 ms [range
231 // 3–12], d_depth 1.5 ms [range 0.3–3] (deliberately shallow:
232 // the unit is engineered not to sound like modulation), rate
233 // 0.6 Hz [range 0.2–1.5], mix 0.5 [range 0.3–0.7]. Roland's
234 // SDD-320 service notes document the topology, not constants.
235 return {6.0, 1.5, 0.6, 0.5, 2, LfoWave::triangle, false, true};
237 // All [dp] — honest gap. The 120°-spaced three-voice L/C/R
238 // topology is documented across the Dytronics Songbird
239 // TSC-1380 lineage (Fractal Audio's Chorus block notes,
240 // Eventide's TriceraChorus documentation); no source publishes
241 // delay or rate figures, by design — the family spans many
242 // implementations. d_center 15 ms [range 8–25], d_depth 4 ms
243 // [range 1–8], rate 0.8 Hz [range 0.3–3], mix 0.5 [0.3–0.7].
244 return {15.0, 4.0, 0.8, 0.5, 3, LfoWave::sine, true, false};
245 }
246 return {12.0, 6.0, 1.2, 0.5, 1, LfoWave::triangle, true, false};
247 }
248
255 double center_ms;
256 double depth_ms;
257 double rate_a_hz;
258 double rate_b_hz;
259 bool dual;
260 };
261
262 static constexpr JunoModeSpec juno_spec(JunoMode m) {
263 constexpr double kLoMs = 1.66; // published
264 constexpr double kHiMs = 5.35; // published
265 constexpr double kRateI = 0.513; // published, Hz
266 constexpr double kRateII = 0.863; // published, Hz
267 constexpr double kBothLoMs = 3.3; // published
268 constexpr double kBothHiMs = 3.7; // published
269 switch (m) {
270 case JunoMode::mode_I:
271 return {0.5 * (kLoMs + kHiMs), 0.5 * (kHiMs - kLoMs), kRateI, 0.0, false};
273 return {0.5 * (kLoMs + kHiMs), 0.5 * (kHiMs - kLoMs), kRateII, 0.0, false};
275 return {0.5 * (kBothLoMs + kBothHiMs), 0.5 * (kBothHiMs - kBothLoMs),
276 kRateI, kRateII, true};
277 }
278 return {0.5 * (kLoMs + kHiMs), 0.5 * (kHiMs - kLoMs), kRateI, 0.0, false};
279 }
280
281 // ── Lifecycle ─────────────────────────────────────────────────────────
282
283 ChorusEnsembleT() { configure_voicing(); }
284
287 void prepare(double sample_rate) {
288 sample_rate_ = (std::isfinite(sample_rate) && sample_rate > 0.0) ? sample_rate : 48000.0;
289
290 const int capacity = static_cast<int>(
291 std::ceil(kMaxDelayMs * 0.001 * sample_rate_)) + kGuardSamples + kInterpOrder + 2;
292 for (auto& line : lines_) line.prepare(capacity);
293 max_read_samples_ = static_cast<double>(capacity - kInterpOrder - 1);
294
295 for (std::size_t k = 0; k < kVoiceSlots; ++k) {
296 lfo_a_[k].prepare(sample_rate_);
297 lfo_b_[k].prepare(sample_rate_);
298 bbd_[k].prepare(sample_rate_);
299 // Distinct clock-jitter streams per voice. Sharing one seed would
300 // make three "independent" BBDs wander in lockstep, which is
301 // exactly the correlation the third voice exists to avoid.
302 bbd_[k].set_seed(chardelay::kPrngSeed ^ (0x9E3779B9u * static_cast<std::uint32_t>(k + 1)));
303 }
304 for (std::size_t c = 0; c < 2; ++c) {
305 shelf_lowpass_[c].prepare(sample_rate_);
306 shelf_lowpass_[c].set_cutoff(kDimCornerHz);
307 cross_highpass_[c].prepare(sample_rate_);
308 cross_highpass_[c].set_cutoff(kDimCornerHz);
309 }
310
311 prepared_ = true;
312 configure_voicing();
313 reset();
314 }
315
316 // ── Configuration ─────────────────────────────────────────────────────
317
322 voicing_ = v;
323 configure_voicing();
324 }
325
326 Voicing voicing() const { return voicing_; }
327
331 juno_mode_ = m;
332 if (voicing_ == Voicing::juno_ensemble) configure_voicing();
333 }
334
335 JunoMode juno_mode() const { return juno_mode_; }
336
340 void set_rate_hz(SampleType hz) {
341 if (!std::isfinite(static_cast<double>(hz))) return;
342 rate_hz_ = std::clamp(static_cast<double>(hz), kRateMinHz, kRateMaxHz);
343 apply_rates();
344 }
345
346 double rate_hz() const { return rate_hz_; }
347
350 void set_depth(SampleType depth01) {
351 if (!std::isfinite(static_cast<double>(depth01))) return;
352 depth_ = std::clamp(static_cast<double>(depth01), 0.0, 1.0);
353 }
354
359 void set_mix(SampleType mix01) {
360 if (!std::isfinite(static_cast<double>(mix01))) return;
361 mix_ = std::clamp(static_cast<double>(mix01), 0.0, 1.0);
362 }
363
367 void set_stereo_width(SampleType width01) {
368 if (!std::isfinite(static_cast<double>(width01))) return;
369 width_ = std::clamp(static_cast<double>(width01), 0.0, 1.0);
370 }
371
398 void set_bbd_color(bool on) {
399 bbd_color_ = on;
400 update_bbd_stage();
401 }
402
403 bool bbd_color() const { return bbd_color_; }
404
405 // ── Audio ─────────────────────────────────────────────────────────────
406
407 void process(SampleType* left, SampleType* right, int n) {
408 if (!prepared_ || left == nullptr || right == nullptr) return;
409
410 const Calibration cal = calibration(voicing_);
411 const bool juno = voicing_ == Voicing::juno_ensemble;
412 const JunoModeSpec juno_cal = juno_spec(juno_mode_);
413 const double center_ms = juno ? juno_cal.center_ms : cal.center_ms;
414 const double depth_ms = depth_ * (juno ? juno_cal.depth_ms : cal.depth_ms);
415 const double ms_to_samples = sample_rate_ * 0.001;
416 const double boost_extra = units::db_to_linear(kDimBoostDb) - 1.0;
417
418 for (int i = 0; i < n; ++i) {
419 const double in_l = static_cast<double>(left[i]);
420 const double in_r = static_cast<double>(right[i]);
421 if (!std::isfinite(in_l) || !std::isfinite(in_r)) {
423 left[i] = right[i] = SampleType{0};
424 continue;
425 }
426 const double src_l = cal.mono_source ? 0.5 * (in_l + in_r) : in_l;
427 const double src_r = cal.mono_source ? src_l : in_r;
428
429 lines_[0].push(static_cast<SampleType>(src_l));
430 lines_[1].push(static_cast<SampleType>(src_r));
431
432 std::array<double, kVoiceSlots> wet{};
433 const auto active = static_cast<std::size_t>(voices_);
434 for (std::size_t k = 0; k < active; ++k) {
435 const double m = modulation(k);
436 const double delay_ms = center_ms + depth_ms * m;
437 delay_ms_[k] = delay_ms;
438
439 double read_samples = delay_ms * ms_to_samples;
440 if (bbd_color_) read_samples -= bbd_delay_samples_;
441 read_samples = std::clamp(read_samples,
442 static_cast<double>(kGuardSamples),
443 max_read_samples_);
444
445 double tap = read_lagrange(lines_[voice_line_[k]], read_samples);
446 if (bbd_color_) tap = bbd_[k].process(tap);
447 wet[k] = tap;
448 }
449
450 double matrix_l = 0.0;
451 double matrix_r = 0.0;
452 switch (voicing_) {
453 case Voicing::ce2:
454 matrix_l = src_l + wet[0];
455 matrix_r = matrix_l;
456 break;
458 matrix_l = in_l + wet[0];
459 matrix_r = in_r + wet[1];
460 break;
462 // Cross-feed is high-passed so only mid and high content
463 // participates in the cancellation; the dry is shelved by
464 // the complementary low-pass so the low end that the
465 // cross-mix would thin out stays solid and centred.
466 const double boost_l = in_l + boost_extra * shelf_lowpass_[0].process_lowpass(in_l);
467 const double boost_r = in_r + boost_extra * shelf_lowpass_[1].process_lowpass(in_r);
468 const double cross_l = cross_highpass_[0].process_highpass(wet[1]);
469 const double cross_r = cross_highpass_[1].process_highpass(wet[0]);
470 matrix_l = boost_l + wet[0] - width_ * cross_l;
471 matrix_r = boost_r + wet[1] - width_ * cross_r;
472 break;
473 }
475 matrix_l = in_l + wet[0] + width_ * 0.5 * wet[1];
476 matrix_r = in_r + wet[2] + width_ * 0.5 * wet[1];
477 break;
478 }
479
480 left[i] = static_cast<SampleType>((1.0 - mix_) * in_l + mix_ * matrix_l);
481 right[i] = static_cast<SampleType>((1.0 - mix_) * in_r + mix_ * matrix_r);
482 }
483 }
484
485 void reset() {
486 for (auto& line : lines_) line.reset();
487 for (std::size_t k = 0; k < kVoiceSlots; ++k) {
488 lfo_a_[k].reset();
489 lfo_b_[k].reset();
490 bbd_[k].reset();
491 delay_ms_[k] = 0.0;
492 }
493 for (std::size_t c = 0; c < 2; ++c) {
494 shelf_lowpass_[c].reset();
495 cross_highpass_[c].reset();
496 }
497 }
498
502 void discard_history() noexcept {
503 for (auto& line : lines_) line.discard_history();
504 for (std::size_t k = 0; k < kVoiceSlots; ++k) {
505 lfo_a_[k].reset();
506 lfo_b_[k].reset();
507 bbd_[k].reset();
508 delay_ms_[k] = 0.0;
509 }
510 for (std::size_t c = 0; c < 2; ++c) {
511 shelf_lowpass_[c].reset();
512 cross_highpass_[c].reset();
513 }
514 }
515
517 int latency_samples() const { return 0; }
518
519 // ── Observability ─────────────────────────────────────────────────────
520 //
521 // These exist so the acceptance suite can measure the modulation directly
522 // rather than only inferring it from audio. The suite still proves them
523 // against the audio path (the delay-range test cross-checks
524 // `current_delay_ms` against a click train tracked through `process`) —
525 // an accessor that agreed with itself would test nothing.
526
528 double current_delay_ms(int voice) const {
529 return (voice >= 0 && voice < kMaxVoices) ? delay_ms_[static_cast<std::size_t>(voice)] : 0.0;
530 }
531
532 int voice_count() const { return voices_; }
533
536 double bbd_bandwidth_hz() const { return bbd_color_ ? bbd_[0].bandwidth_hz() : 0.0; }
537
539 double bbd_stage_delay_ms() const {
540 return bbd_color_ ? bbd_delay_samples_ * 1000.0 / sample_rate_ : 0.0;
541 }
542
556 static constexpr double kTapL1 = 1.25;
557
578 double worst_case_gain() const {
579 switch (voicing_) {
580 case Voicing::ce2:
582 return 1.0 + kTapL1;
584 return shelf_l1() + kTapL1 + width_ * kTapL1 * highpass_l1();
586 return 1.0 + kTapL1 + width_ * 0.5 * kTapL1;
587 }
588 return 1.0 + kTapL1;
589 }
590
592 double shelf_l1() const { return units::db_to_linear(kDimBoostDb); }
593
595 double highpass_l1() const {
596 const double t = std::tan(kPi * kDimCornerHz / sample_rate_);
597 return 2.0 / (1.0 + t);
598 }
599
600private:
601 static constexpr double kPi = 3.14159265358979323846;
602
604 static constexpr double kRateMinHz = 0.05;
605 static constexpr double kRateMaxHz = 10.0;
606
612 static double read_lagrange(const DelayLineT<SampleType>& line, double delay_samples) {
613 const int i = static_cast<int>(std::floor(delay_samples));
614 const double frac = delay_samples - static_cast<double>(i);
615 const double ym1 = static_cast<double>(line.read(i - 1));
616 const double y0 = static_cast<double>(line.read(i));
617 const double y1 = static_cast<double>(line.read(i + 1));
618 const double y2 = static_cast<double>(line.read(i + 2));
619 return Interpolator::lagrange(frac, ym1, y0, y1, y2);
620 }
621
623 double modulation(std::size_t index) {
624 if (juno_dual_) {
625 // Both LFOs engage simultaneously — the real unit's two mode
626 // switches are not exclusive. The averaging-and-clamp law is a
627 // [design parameter]: the analog mixer's summing headroom is not
628 // published. The clamp is provably inactive for two bipolar
629 // triangles (|0.5(a + b)| ≤ 1) and is kept as the belt-and-braces
630 // the spec states, not as an active shaper.
631 const double a = lfo_a_[index].next();
632 const double b = lfo_b_[index].next();
633 return std::clamp(0.5 * (a + b), -1.0, 1.0);
634 }
635 const double a = lfo_a_[index].next();
636 if (!trapezoid_) return a;
637 // Dwells at the modulation extremes instead of reversing sharply,
638 // which is what lets the Dimension D's excursion be shallow enough to
639 // read as width rather than as pitch modulation.
640 return std::clamp(kTrapK * a, -1.0, 1.0);
641 }
642
643 void configure_voicing() {
644 const Calibration cal = calibration(voicing_);
645 const bool juno = voicing_ == Voicing::juno_ensemble;
646 const JunoModeSpec juno_cal = juno_spec(juno_mode_);
647
648 voices_ = cal.voices;
649 trapezoid_ = cal.trapezoid;
650 juno_dual_ = juno && juno_cal.dual;
651 rate_hz_ = juno ? juno_cal.rate_a_hz : cal.rate_hz;
652
653 // Voice → delay line. Mono-source voicings read one line; the
654 // inverted-phase pairs read their own channel.
655 for (std::size_t k = 0; k < kVoiceSlots; ++k)
656 voice_line_[k] = (cal.mono_source || k == 0) ? 0 : 1;
657
658 for (std::size_t k = 0; k < kVoiceSlots; ++k) {
659 // Voice k of N sits at k/N cycles — the toolkit's N-voice spacing,
660 // which for N = 2 is the exact inversion the Juno and Dimension D
661 // are built on and for N = 3 is the TriChorus's 120°.
662 const double offset = static_cast<double>(k) / static_cast<double>(voices_);
663 lfo_a_[k].set_wave(cal.wave);
664 lfo_a_[k].set_phase_offset(offset);
665 lfo_b_[k].set_wave(cal.wave);
666 lfo_b_[k].set_phase_offset(offset);
667 lfo_a_[k].reset();
668 lfo_b_[k].reset();
669 }
670 apply_rates();
671 update_bbd_stage();
672 }
673
674 void apply_rates() {
675 const bool juno = voicing_ == Voicing::juno_ensemble;
676 const JunoModeSpec juno_cal = juno_spec(juno_mode_);
677 const double rate_a = juno ? juno_cal.rate_a_hz : rate_hz_;
678 const double rate_b = juno ? juno_cal.rate_b_hz : rate_hz_;
679 for (std::size_t k = 0; k < kVoiceSlots; ++k) {
680 lfo_a_[k].set_rate_hz(rate_a);
681 lfo_b_[k].set_rate_hz(rate_b);
682 }
683 }
684
685 void update_bbd_stage() {
686 if (!prepared_) return;
687 const Calibration cal = calibration(voicing_);
688 const bool juno = voicing_ == Voicing::juno_ensemble;
689 const JunoModeSpec juno_cal = juno_spec(juno_mode_);
690 const double center_ms = juno ? juno_cal.center_ms : cal.center_ms;
691 const double depth_ms = juno ? juno_cal.depth_ms : cal.depth_ms;
692
693 const double stage_ms = std::max(center_ms - depth_ms - kBbdColorGuardMs, 0.05);
694 bbd_delay_samples_ = stage_ms * sample_rate_ * 0.001;
695 for (std::size_t k = 0; k < kVoiceSlots; ++k)
696 bbd_[k].update(kBbdColorCharacter, stage_ms * 0.001);
697 }
698
699 std::array<DelayLineT<SampleType>, 2> lines_{};
700 std::array<EffectLfoT<double>, kVoiceSlots> lfo_a_{};
701 std::array<EffectLfoT<double>, kVoiceSlots> lfo_b_{};
702 std::array<chardelay::BbdChannel, kVoiceSlots> bbd_{};
703 std::array<TptFilterT<double>, 2> shelf_lowpass_{};
704 std::array<TptFilterT<double>, 2> cross_highpass_{};
705
706 std::array<double, kVoiceSlots> delay_ms_{};
707 std::array<std::size_t, kVoiceSlots> voice_line_{};
708
709 double sample_rate_ = 48000.0;
710 double max_read_samples_ = 0.0;
711 double bbd_delay_samples_ = 0.0;
712 double rate_hz_ = 1.2;
713 double depth_ = 0.5;
714 double mix_ = 0.5;
715 double width_ = 1.0;
716
717 Voicing voicing_ = Voicing::ce2;
718 JunoMode juno_mode_ = JunoMode::mode_I;
719 int voices_ = 1;
720 bool trapezoid_ = false;
721 bool juno_dual_ = false;
722 bool bbd_color_ = false;
723 bool prepared_ = false;
724};
725
728
729} // namespace pulp::signal
One chorus engine, four voicings. Stereo in place.
Definition chorus_family.hpp:124
static constexpr int kGuardSamples
Definition chorus_family.hpp:147
double worst_case_gain() const
Peak output gain this configuration can produce for |input| ≤ 1 at mix = 1, as an L1 (worst-case-over...
Definition chorus_family.hpp:578
int voice_count() const
Definition chorus_family.hpp:532
static constexpr double kDimBoostDb
Definition chorus_family.hpp:173
static constexpr double kMaxDelayMs
Definition chorus_family.hpp:154
void set_stereo_width(SampleType width01)
0 .
Definition chorus_family.hpp:367
double highpass_l1() const
L1 norm of the first-order cross-feed high-pass at the prepared rate.
Definition chorus_family.hpp:595
static constexpr JunoModeSpec juno_spec(JunoMode m)
Definition chorus_family.hpp:262
void set_juno_mode(JunoMode m)
Ignored unless the voicing is juno_ensemble.
Definition chorus_family.hpp:330
double bbd_bandwidth_hz() const
Bandwidth the composed BBD stage is running at, Hz.
Definition chorus_family.hpp:536
double current_delay_ms(int voice) const
Instantaneous delay applied to voice k on the most recent sample, ms.
Definition chorus_family.hpp:528
void set_bbd_color(bool on)
Routes every voice's tap through chardelay::BbdChannel — the clock-domain bandwidth law and compander...
Definition chorus_family.hpp:398
void set_voicing(Voicing v)
Switches the calibration table and rewinds every LFO phase.
Definition chorus_family.hpp:321
static constexpr double kBbdColorCharacter
Definition chorus_family.hpp:182
static constexpr Calibration calibration(Voicing v)
Definition chorus_family.hpp:213
void discard_history() noexcept
Constant-time audio fault recovery.
Definition chorus_family.hpp:502
void set_mix(SampleType mix01)
Dry/wet, 0 .
Definition chorus_family.hpp:359
void prepare(double sample_rate)
Sizes both delay lines for kMaxDelayMs plus the interpolation stencil, prepares the composed primitiv...
Definition chorus_family.hpp:287
static constexpr double kBbdColorGuardMs
Definition chorus_family.hpp:189
void set_rate_hz(SampleType hz)
LFO rate in Hz, 0.05 .
Definition chorus_family.hpp:340
static constexpr double kDimCornerHz
Definition chorus_family.hpp:169
Voicing voicing() const
Definition chorus_family.hpp:326
static constexpr double kTapL1
Definition chorus_family.hpp:556
JunoMode
The Juno's three front-panel positions.
Definition chorus_family.hpp:131
@ mode_I_plus_II
Definition chorus_family.hpp:131
@ mode_I
Definition chorus_family.hpp:131
@ mode_II
Definition chorus_family.hpp:131
JunoMode juno_mode() const
Definition chorus_family.hpp:335
static constexpr int kMaxVoices
Definition chorus_family.hpp:136
ChorusEnsembleT()
Definition chorus_family.hpp:283
void reset()
Definition chorus_family.hpp:485
double shelf_l1() const
L1 norm of the dry low-shelf: its DC gain.
Definition chorus_family.hpp:592
bool bbd_color() const
Definition chorus_family.hpp:403
void process(SampleType *left, SampleType *right, int n)
Definition chorus_family.hpp:407
double bbd_stage_delay_ms() const
Delay the BBD colour stage carries when enabled, ms. Zero when off.
Definition chorus_family.hpp:539
static constexpr std::size_t kVoiceSlots
Definition chorus_family.hpp:137
double rate_hz() const
Definition chorus_family.hpp:346
static constexpr int kInterpOrder
Definition chorus_family.hpp:141
int latency_samples() const
0 for every voicing. See this file's latency note.
Definition chorus_family.hpp:517
Voicing
Definition chorus_family.hpp:126
@ juno_ensemble
Definition chorus_family.hpp:126
@ tri_chorus
Definition chorus_family.hpp:126
@ dimension_d
Definition chorus_family.hpp:126
@ ce2
Definition chorus_family.hpp:126
void set_depth(SampleType depth01)
Depth macro, 0 .
Definition chorus_family.hpp:350
static constexpr double kTrapK
Definition chorus_family.hpp:161
Definition delay_line.hpp:13
High-quality sample interpolation for delay lines and resampling.
The house low-frequency oscillator: seven waveforms plus a continuous shape morph,...
constexpr std::uint32_t kPrngSeed
PRNG seed.
Definition tables.hpp:92
T db_to_linear(T db)
Amplitude dB → linear gain. 0 dB → 1, −6.0206 dB → 0.5.
Definition units.hpp:71
Definition additive_bank.hpp:218
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
ChorusEnsembleT< float > ChorusEnsemble
Definition chorus_family.hpp:726
@ c
Definition spectrum_trace.hpp:35
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
LfoWave
The effect-wave vocabulary, shared by these functions and by EffectLfoT (lfo.hpp),...
Definition lfo_sampling.hpp:53
@ sine
Definition lfo_sampling.hpp:54
@ triangle
Definition lfo_sampling.hpp:55
ChorusEnsembleT< double > ChorusEnsemble64
Definition chorus_family.hpp:727
@ k
Definition input_events.hpp:40
One voicing's shipped calibration.
Definition chorus_family.hpp:197
bool trapezoid
True when the triangle is trapezoid-shaped before it modulates.
Definition chorus_family.hpp:210
int voices
Definition chorus_family.hpp:202
LfoWave wave
Definition chorus_family.hpp:203
double mix_default
Definition chorus_family.hpp:201
double rate_hz
Definition chorus_family.hpp:200
double depth_ms
Definition chorus_family.hpp:199
bool mono_source
True when the taps read a mono sum of the input rather than their own channel — the CE-2 because the ...
Definition chorus_family.hpp:208
double center_ms
Definition chorus_family.hpp:198
The Juno's per-mode calibration.
Definition chorus_family.hpp:254
double depth_ms
Definition chorus_family.hpp:256
double rate_b_hz
Second LFO; used only when dual.
Definition chorus_family.hpp:258
bool dual
Definition chorus_family.hpp:259
double center_ms
Definition chorus_family.hpp:255
double rate_a_hz
Definition chorus_family.hpp:257
static SampleType lagrange(SampleType frac, SampleType ym1, SampleType y0, SampleType y1, SampleType y2)
4-point Lagrange interpolation.
Definition interpolator.hpp:60
First-order topology-preserving transform (TPT) filter.
The real-unit vocabulary shared by every DSP block in the catalog.