|
| | ChorusEnsembleT () |
| void | prepare (double sample_rate) |
| | Sizes both delay lines for kMaxDelayMs plus the interpolation stencil, prepares the composed primitives, and resets.
|
| void | set_voicing (Voicing v) |
| | Switches the calibration table and rewinds every LFO phase.
|
| Voicing | voicing () const |
| void | set_juno_mode (JunoMode m) |
| | Ignored unless the voicing is juno_ensemble.
|
| JunoMode | juno_mode () const |
| void | set_rate_hz (SampleType hz) |
| | LFO rate in Hz, 0.05 .
|
| double | rate_hz () const |
| void | set_depth (SampleType depth01) |
| | Depth macro, 0 .
|
| void | set_mix (SampleType mix01) |
| | Dry/wet, 0 .
|
| void | set_stereo_width (SampleType width01) |
| | 0 .
|
| void | set_bbd_color (bool on) |
| | Routes every voice's tap through chardelay::BbdChannel — the clock-domain bandwidth law and compander the multi-character-delay module owns.
|
| bool | bbd_color () const |
| void | process (SampleType *left, SampleType *right, int n) |
| void | reset () |
| void | discard_history () noexcept |
| | Constant-time audio fault recovery.
|
| int | latency_samples () const |
| | 0 for every voicing. See this file's latency note.
|
| double | current_delay_ms (int voice) const |
| | Instantaneous delay applied to voice k on the most recent sample, ms.
|
| int | voice_count () const |
| double | bbd_bandwidth_hz () const |
| | Bandwidth the composed BBD stage is running at, Hz.
|
| double | bbd_stage_delay_ms () const |
| | Delay the BBD colour stage carries when enabled, ms. Zero when off.
|
| double | worst_case_gain () const |
| | Peak output gain this configuration can produce for |input| ≤ 1 at mix = 1, as an L1 (worst-case-over-all-inputs) bound.
|
| double | shelf_l1 () const |
| | L1 norm of the dry low-shelf: its DC gain.
|
| double | highpass_l1 () const |
| | L1 norm of the first-order cross-feed high-pass at the prepared rate.
|
|
| static constexpr int | kMaxVoices = 3 |
| | Most voices any voicing uses (TriChorus). Sizes the per-voice arrays.
|
| static constexpr std::size_t | kVoiceSlots = static_cast<std::size_t>(kMaxVoices) |
| static constexpr int | kInterpOrder = 3 |
| | Lagrange interpolation order.
|
| static constexpr int | kGuardSamples = kInterpOrder + 1 |
| | Samples of clearance the minimum instantaneous delay must keep from the write pointer so the kInterpOrder + 1-point stencil never reads ahead of it.
|
| static constexpr double | kMaxDelayMs = 40.0 |
| | Storage ceiling, milliseconds.
|
| static constexpr double | kTrapK = 1.8 |
| | Trapezoid shaping gain: trap = clamp(k · triangle, ±1).
|
| static constexpr double | kDimCornerHz = 200.0 |
| | Corner of both the cross-feed high-pass and the complementary dry low-shelf.
|
| static constexpr double | kDimBoostDb = 1.5 |
| | Dry low-shelf gain below kDimCornerHz.
|
| static constexpr double | kBbdColorCharacter = 1.0 |
| | Position on chardelay::kBbdAxis used for the optional colour stage.
|
| static constexpr double | kBbdColorGuardMs = 0.5 |
| | Milliseconds of the wet path left on the Lagrange line at the deepest modulation point when the BBD stage carries the rest.
|
| static constexpr double | kTapL1 = 1.25 |
| | L1 norm of one modulated tap — the gain a fractional delay read can actually reach, as opposed to the unity a delay line suggests.
|
template<typename SampleType = float>
class pulp::signal::ChorusEnsembleT< SampleType >
One chorus engine, four voicings. Stereo in place.
template<typename SampleType = float>
Routes every voice's tap through chardelay::BbdChannel — the clock-domain bandwidth law and compander the multi-character-delay module owns.
Substitution, stated deliberately. The spec asks for a CharacterDelayT configured to Character::bbd; this holds BbdChannel instead. BbdChannel is that character's device model — the composition is verbatim — while CharacterDelayT is the whole 2 s feedback delay engine wrapped around it, with reverse, tape and diffusion buffers costing megabytes per instance, three instances here, and no API to act as a pure colouring stage (its wet path is its own delay line, which would double every tap's delay).
The split. The BBD is a clocked delay, so it cannot colour without delaying. It is given the fixed sub-delay d_center − d_depth − kBbdColorGuardMs and the Lagrange line carries the remainder including all of the modulation, so the total wet delay stays exactly on the calibration table and every delay, phase and latency property measured with the colour off holds with it on. Driving the BBD's clock from the instantaneous delay instead would be the more literal reading, but it buys nothing measurable: the bandwidth law clamp(stages / t / 3, 300 Hz, 10 kHz) sits on its 10 kHz ceiling at every point of every voicing's sweep (the slowest case is the CE-2 at its 18 ms extreme: 1024 / 0.018 / 3 = 19.0 kHz, still nearly twice the ceiling), so instantaneous and centre evaluation are provably equal here, and a control-rate clock would only add a staircase to the pitch.
template<typename SampleType = float>
Peak output gain this configuration can produce for |input| ≤ 1 at mix = 1, as an L1 (worst-case-over-all-inputs) bound.
This module has no feedback path — every voicing is dry plus N feedforward taps — so the bound is a closed-form sum, and Forge's worst_case_gain cites it rather than estimating (series law 8).
Two terms are larger than they look, which is why this is computed and not written down as 1 + N:
- each tap carries kTapL1 = 1.25, not 1;
- the Dimension D's cross-feed high-pass carries 2 / (1 + tan(π f_c / f_s)) — just under 2, not the unity its passband gain suggests. Passband gain is a steady-state sinusoidal figure; a peak bound needs the impulse response's L1 norm, and for a first-order high-pass those differ by a factor of almost two. Its companion low-shelf is better behaved: a non-negative impulse response makes that one's L1 norm exactly its DC gain.
The sample-rate dependence is real and comes from that high-pass term.
template<typename SampleType = float>
Corner of both the cross-feed high-pass and the complementary dry low-shelf.
One constant, because the shelf exists precisely to restore what the high-passed cross-feed cancels — a mismatched pair would leave a hole or a bump at the crossover. [design parameter] default 200 Hz, range 100 .. 400 Hz. Honest gap: the SDD-320's actual corner is not published.
template<typename SampleType = float>
L1 norm of one modulated tap — the gain a fractional delay read can actually reach, as opposed to the unity a delay line suggests.
A delay line's own L1 norm is 1, but the tap is a delay line read through the 4-point Lagrange kernel, and that kernel's coefficients are not all non-negative. At a half-sample offset they are (−1/16, 9/16, 9/16, −1/16), whose absolute sum is 20/16 = 1.25 — the maximum over the fractional interval, and exactly attainable by an input whose signs match. Any bound that treats a modulated tap as unity gain is 25 % low; the acceptance suite recomputes this number directly from the shipped kernel rather than trusting the algebra. [derived constant, not a design parameter: it is a property of kInterpOrder = 3, and moving to linear interpolation would make it 1.]