|
Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
|
The two LFO engines that modulate every partial. More...
#include <tabulasonora/lfo_engine.hpp>
Classes | |
| struct | Limits |
| Depth clamp and rounding constant for a destination. More... | |
Public Member Functions | |
| LfoEngine (const TableSet &tables, EngineNoise *noise=nullptr) | |
| Creates the engine over a loaded table set, which must outlive it. | |
| EngineNoise & | noise () const noexcept |
| The generator the random shapes draw from. | |
| int | waveform (int phase, int waveform_index) const noexcept |
| Evaluates a waveform at a 16-bit phase. | |
| std::pair< LfoConfig, LfoConfig > | configure (int tone_number, const PartialParameters &partial, const PartModifiers &modifiers={}) const |
| Reads both LFO configurations for one partial: the tone-common LFO1 and the per-partial LFO2. | |
| LfoRunner | create_runner (const LfoConfig &config) const |
| Creates a runner that steps one LFO a control tick at a time. | |
| std::pair< LfoRunner, LfoRunner > | create_runners (int tone_number, const PartialParameters &partial, const PartModifiers &modifiers={}) const |
| Creates runners for both of a partial's LFOs. | |
| std::vector< double > | run (const LfoConfig &config, int tick_count, LfoDestination destination) const |
| Runs one LFO for a number of control ticks. | |
| std::vector< double > | modulation (int tone_number, const PartialParameters &partial, int tick_count, LfoDestination destination) const |
| The combined LFO1 and LFO2 modulation for a partial, per control tick. | |
| std::vector< double > | pitch_modulation_with_wheel (int tone_number, const PartialParameters &partial, int tick_count, std::span< const double > mod_depth_per_tick) const |
| Combined pitch modulation with a per-tick mod-wheel depth folded into LFO1. | |
Static Public Member Functions | |
| static constexpr bool | is_random (int waveform) noexcept |
| Whether a waveform is one of the three random shapes, which the runner drives. | |
| static constexpr Limits | destination_limits (LfoDestination destination) noexcept |
| static int | mod_wheel_depth (int controller, int depth=0x0A, int offset=0) noexcept |
| The mod wheel's contribution to LFO1 pitch depth, in milli-semitones. | |
Static Public Attributes | |
| static constexpr double | waveform_scale = 32640.0 |
| Scale that maps a raw waveform value to [-1, 1]. | |
| static constexpr int | slew_step = 0x50 |
| How far a slewed random shape moves toward its target in one control tick. | |
The two LFO engines that modulate every partial.
A partial is modulated by both. LFO1 is tone-common, with its parameters in the tone header and its per-partial depths in the partial block; LFO2 is per-partial throughout. The asymmetry that matters is in how their rate and delay fields are read: LFO1's are indices into lookup tables, while LFO2's are used raw as per-tick increments. Verified live — LFO1 rate 43 gives increment 2817, LFO2 rate 917 gives 917.
Pitch depth is in milli-semitones, not cents. The pitch accumulator clamps at 0x1f018, which is 127 x 1000, and that is what fixes the unit.
Waveform selectors 1, 2 and 3 are the random shapes. They are not functions of the phase the way every other shape is — they redraw when the phase wraps and hold or walk toward that draw in between — so they live in ts::LfoRunner rather than in waveform below, which asks only where in the cycle the LFO is and cannot express them.
|
explicit |
Creates the engine over a loaded table set, which must outlive it.
noise is the engine's shared generator, which the random shapes draw from; when null a private one is used. Sharing it is not a detail — the module has exactly one generator, and the LFO shapes, the pitch start jitter and the random pan all draw from it, so which voice draws when is part of what the sequence is.
|
inlinestaticnodiscardconstexprnoexcept |
Whether a waveform is one of the three random shapes, which the runner drives.
|
inlinestaticnodiscardconstexprnoexcept |
|
inlinenodiscardnoexcept |
The generator the random shapes draw from.
|
nodiscardnoexcept |
Evaluates a waveform at a 16-bit phase.
The three random shapes are not evaluable this way and return zero here; ts::LfoRunner drives them, because what they depend on is the phase having wrapped rather than the phase.
|
nodiscard |
Reads both LFO configurations for one partial: the tone-common LFO1 and the per-partial LFO2.
modifiers applies the part's vibrato rate, depth and delay. They reach LFO1 alone — LFO2 has no table indices for them to bias.
Creates a runner that steps one LFO a control tick at a time.
|
nodiscard |
Creates runners for both of a partial's LFOs.
|
nodiscard |
Runs one LFO for a number of control ticks.
|
nodiscard |
The combined LFO1 and LFO2 modulation for a partial, per control tick.
The first tick is always zero: the LFO object is created after that tick's control update, so nothing has been applied yet. Aligning to that is what makes the comparison against the engine's own trace line up.
|
nodiscard |
Combined pitch modulation with a per-tick mod-wheel depth folded into LFO1.
The wheel's contribution is added after the fade-in, then the total is clamped to +-6000 — six semitones, the GS full-scale figure. Only LFO1 takes it; LFO2 is unaffected.
|
staticnodiscardnoexcept |
The mod wheel's contribution to LFO1 pitch depth, in milli-semitones.
Summed with the tone's own pitch depth after the cents table, and the total is then clamped to +-6000.
|
staticconstexpr |
Scale that maps a raw waveform value to [-1, 1].
|
staticconstexpr |
How far a slewed random shape moves toward its target in one control tick.