Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::DelayVibratoT< SampleType > Class Template Reference

True pitch vibrato: a fractional delay whose tap position is modulated by a sine, which scales the frequency of everything passing through it equally. More...

#include <vibrato.hpp>

Public Member Functions

 DelayVibratoT ()
void prepare (double sample_rate)
 Sizes the delay line for the longest modulated read any legal parameter combination can ask for, so no set_* ever has to reallocate.
void set_rate_hz (double hz)
double rate_hz () const
void set_depth_cents (double cents)
 Peak pitch excursion in cents.
double depth_cents () const
void set_delay_ms (double ms)
 Silence before the vibrato starts, in ms.
void set_fade_in_ms (double ms)
 Time for the depth to ramp 0 -> 1 after the delay, in ms. Re-arms.
double base_delay_samples () const
 Base delay in samples — the centre the modulation swings around.
double modulation_amplitude_samples () const
 Peak modulation excursion in samples, before the lifecycle scales it.
double depth_envelope () const
 Current lifecycle depth scale in [0, 1].
std::size_t latency_samples () const
 Exactly ceil((D0 + A) * fs): the longest delay the tap can read, which is the conservative reading of a time-varying delay's latency.
void reset ()
void discard_history () noexcept
SampleType process (SampleType input)

Static Public Attributes

static constexpr double kDefaultRateHz = 5.5
 Vibrato rate. [design parameter] default 5.5 Hz, range 0.1 .. 20 Hz.
static constexpr double kMinRateHz = 0.1
static constexpr double kMaxRateHz = 20.0
static constexpr double kDefaultDepthCents = 20.0
 Peak pitch excursion.
static constexpr double kMaxDepthCents = 100.0
static constexpr double kBaseDelayHeadroom = 2.0
 The base delay the modulation rides on, as a multiple of the modulation amplitude, so the read pointer never reaches the write pointer.
static constexpr double kMinBaseDelaySamples = 2.0
 Floor on the base delay in samples.
static constexpr int kInterpolatorMarginSamples = 4
 Guard samples past the longest read, covering the Lagrange window's i + 2 reach.
static constexpr double kMaxLifecycleMs = 5000.0
 Ceiling on both lifecycle times.
static constexpr double kInterpolatorPeakGain = 1.25
 Peak sample gain of the 4-point Lagrange kernel: the L1 norm of its weights, maximised at a half-sample offset where they are (-1, 9, 9, -1)/16.

Detailed Description

template<typename SampleType = float>
class pulp::signal::DelayVibratoT< SampleType >

True pitch vibrato: a fractional delay whose tap position is modulated by a sine, which scales the frequency of everything passing through it equally.

100 % wet by design. A dry blend of a pitch-modulated tap against its own dry signal is a chorus — a different effect with a different doc — and mixing one in here would quietly turn the only true-pitch engine in the module into the thing it is meant to be distinguishable from.

The delay/fade-in lifecycle ("vibrato arrives once the note has settled") is a DahdsrT scaling the modulation depth, not a hand-rolled ramp. reset() re-arms it, which is what makes reset() mean "new note" here.

Constructor & Destructor Documentation

◆ DelayVibratoT()

template<typename SampleType = float>
pulp::signal::DelayVibratoT< SampleType >::DelayVibratoT ( )
inline

Member Function Documentation

◆ base_delay_samples()

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::base_delay_samples ( ) const
inline

Base delay in samples — the centre the modulation swings around.

◆ depth_cents()

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::depth_cents ( ) const
inline

◆ depth_envelope()

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::depth_envelope ( ) const
inline

Current lifecycle depth scale in [0, 1].

1 whenever no lifecycle times are set, so the common case costs nothing and starts at full depth.

◆ discard_history()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::discard_history ( )
inlinenoexcept

◆ latency_samples()

template<typename SampleType = float>
std::size_t pulp::signal::DelayVibratoT< SampleType >::latency_samples ( ) const
inline

Exactly ceil((D0 + A) * fs): the longest delay the tap can read, which is the conservative reading of a time-varying delay's latency.

Never 0 — a modulated tap cannot be free.

◆ modulation_amplitude_samples()

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::modulation_amplitude_samples ( ) const
inline

Peak modulation excursion in samples, before the lifecycle scales it.

◆ prepare()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::prepare ( double sample_rate)
inline

Sizes the delay line for the longest modulated read any legal parameter combination can ask for, so no set_* ever has to reallocate.

That worst case is the slowest rate at the deepest setting — the amplitude in seconds is inversely proportional to rate — which is a few hundred milliseconds of storage, not a few.

◆ process()

template<typename SampleType = float>
SampleType pulp::signal::DelayVibratoT< SampleType >::process ( SampleType input)
inline

◆ rate_hz()

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::rate_hz ( ) const
inline

◆ reset()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::reset ( )
inline

◆ set_delay_ms()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::set_delay_ms ( double ms)
inline

Silence before the vibrato starts, in ms.

Re-arms the lifecycle: the times describe the start of a note, so changing them mid-note has no meaningful continuation.

◆ set_depth_cents()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::set_depth_cents ( double cents)
inline

Peak pitch excursion in cents.

The modulation amplitude in seconds is derived here, once, from A = (2^(cents/1200) - 1) / (2*pi*rate) — the inversion of cents = 1200*log2(1 + 2*pi*rate*A) — and never recomputed per sample.

◆ set_fade_in_ms()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::set_fade_in_ms ( double ms)
inline

Time for the depth to ramp 0 -> 1 after the delay, in ms. Re-arms.

◆ set_rate_hz()

template<typename SampleType = float>
void pulp::signal::DelayVibratoT< SampleType >::set_rate_hz ( double hz)
inline

Member Data Documentation

◆ kBaseDelayHeadroom

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kBaseDelayHeadroom = 2.0
staticconstexpr

The base delay the modulation rides on, as a multiple of the modulation amplitude, so the read pointer never reaches the write pointer.

[design parameter] default 2.0, range 1.5 .. 4.0.

◆ kDefaultDepthCents

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kDefaultDepthCents = 20.0
staticconstexpr

Peak pitch excursion.

Musical vibrato lives far above the few-cent pitch JND; the default sits between the narrow bowed-string end and the wide vocal end of the documented range, and effect vibrato has no citable figure of its own. [design parameter] default 20 cents, range 0 .. 100.

◆ kDefaultRateHz

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kDefaultRateHz = 5.5
staticconstexpr

Vibrato rate. [design parameter] default 5.5 Hz, range 0.1 .. 20 Hz.

◆ kInterpolatorMarginSamples

template<typename SampleType = float>
int pulp::signal::DelayVibratoT< SampleType >::kInterpolatorMarginSamples = 4
staticconstexpr

Guard samples past the longest read, covering the Lagrange window's i + 2 reach.

[design parameter] default 4 samples, range 2 .. 8.

◆ kInterpolatorPeakGain

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kInterpolatorPeakGain = 1.25
staticconstexpr

Peak sample gain of the 4-point Lagrange kernel: the L1 norm of its weights, maximised at a half-sample offset where they are (-1, 9, 9, -1)/16.

Provable, not fitted, and the reason this engine's worst-case gain is not exactly 0 dB despite being a single unit-gain tap. Asserted by the suite against a scan of the shipped interpolator.

◆ kMaxDepthCents

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kMaxDepthCents = 100.0
staticconstexpr

◆ kMaxLifecycleMs

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kMaxLifecycleMs = 5000.0
staticconstexpr

Ceiling on both lifecycle times.

[design parameter] default 5000 ms, range 1000 .. 20000 ms.

◆ kMaxRateHz

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kMaxRateHz = 20.0
staticconstexpr

◆ kMinBaseDelaySamples

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kMinBaseDelaySamples = 2.0
staticconstexpr

Floor on the base delay in samples.

The Lagrange read touches index i - 1, so a delay below one sample would read past the write pointer no matter how small the modulation is. [design parameter] default 2 samples, range 1 .. 8.

◆ kMinRateHz

template<typename SampleType = float>
double pulp::signal::DelayVibratoT< SampleType >::kMinRateHz = 0.1
staticconstexpr

The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/signal/include/pulp/signal/vibrato.hpp