Tabula Sonora 0.1.0
A native C++20 implementation of the Roland Sound Canvas VA synth voice
Loading...
Searching...
No Matches
ts::LfoRunner Class Reference

One LFO's running state: phase, delay and fade-in accumulators, stepped a control tick at a time. More...

#include <tabulasonora/lfo_engine.hpp>

Public Member Functions

 LfoRunner (const LfoEngine &engine, const LfoConfig &config)
const LfoConfigconfig () const noexcept
 The configuration this runner steps.
bool is_applied () const noexcept
 Whether the last tick ran an update at all, so the LFO has an output to give.
void tick (int rate_offset=0) noexcept
 Advances one control tick.
double value (LfoDestination destination, int matrix_depth=0) const noexcept
 The modulation for one destination, after the last tick.
double pitch_value (double wheel_depth) const noexcept
 The pitch modulation with a mod-wheel depth folded in, in milli-semitones.

Detailed Description

One LFO's running state: phase, delay and fade-in accumulators, stepped a control tick at a time.

All three destinations share one runner. The accumulators do not depend on which depth is being applied, so stepping once and reading three values is the same trajectory as running the LFO three times — and it is what the engine does, since a partial has one LFO object, not one per destination.

tick advances; the value is read afterwards, so the first tick already carries a phase increment.

Constructor & Destructor Documentation

◆ LfoRunner()

ts::LfoRunner::LfoRunner ( const LfoEngine & engine,
const LfoConfig & config )
inline

Member Function Documentation

◆ config()

const LfoConfig & ts::LfoRunner::config ( ) const
inlinenodiscardnoexcept

The configuration this runner steps.

◆ is_applied()

bool ts::LfoRunner::is_applied ( ) const
inlinenodiscardnoexcept

Whether the last tick ran an update at all, so the LFO has an output to give.

This is not "the delay has elapsed" — the delay holds the fade-in at zero but does not stop the LFO being applied, since a matrix depth is summed past the fade. What turns it off is an increment of nothing, which is the one case the module skips outright.

◆ tick()

void ts::LfoRunner::tick ( int rate_offset = 0)
noexcept

Advances one control tick.

rate_offset is the control matrix's LFO rate destination, in the same per-tick increment units as the configured rate — the engine adds it to the rate straight out of the table (or, for LFO2, to the raw rate) and clamps the total to 0x28f6.

A total of zero or less does not merely stop the phase: the engine skips the whole update, so the depths are not applied either and the LFO's last output is held rather than decaying. Deep enough negative rate modulation is therefore an off switch, which is why this shares its early return with a configured rate of zero.

◆ value()

double ts::LfoRunner::value ( LfoDestination destination,
int matrix_depth = 0 ) const
nodiscardnoexcept

The modulation for one destination, after the last tick.

matrix_depth is the control matrix's depth destination for this LFO, in the destination's own units. It is summed after the fade-in — the fade scales the patch's depth, not the controller's — and the total is then clamped to the destination's limit. Those limits are exactly the matrix's own full-scale figures, so a matrix depth alone can reach the rail but never exceed it.

◆ pitch_value()

double ts::LfoRunner::pitch_value ( double wheel_depth) const
nodiscardnoexcept

The pitch modulation with a mod-wheel depth folded in, in milli-semitones.

The offline path's spelling of the same thing: the wheel reaches LFO1 pitch depth through the matrix, so this is value(LfoDestination::pitch, ...) with the wheel's contribution standing in for the whole matrix sum.


The documentation for this class was generated from the following file: