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

The memoryless saturation stage. More...

#include <saturator.hpp>

Public Types

using Shape = SaturatorShape
using AliasPolicy = SaturatorAliasPolicy

Public Member Functions

 SaturatorT ()
void prepare (double sample_rate)
 Sizes the oversampler and the dry-path alignment delay. May allocate.
void set_shape (Shape shape)
Shape shape () const
void set_drive_db (double db)
double drive_db () const
void set_bias (double normalized)
 Bias as a normalised [-1, +1].
double bias () const
 The bias actually in force after any shape-specific clamp — exposed so a caller can show the effective value rather than the requested one.
void set_tone_pre_hz (double hz)
 Pre-emphasis corner in Hz. 0 disables the pre/de pair.
void set_tone_tracking (bool tracking)
 When true (the default) the de-emphasis corner follows the pre-emphasis corner, so the pair cancels exactly.
void set_tone_de_hz (double hz)
 De-emphasis corner, used only when tracking is off.
void set_pre_boost_db (double db)
void set_alias_policy (AliasPolicy policy)
 Select the alias policy.
AliasPolicy alias_policy () const
void set_mix (double wet01)
void set_output_trim_db (double db)
int latency_samples () const noexcept
 The integer delay the host should compensate, matched on the dry path.
double group_delay_samples () const noexcept
 The wet path's exact delay on the linear part of the curve, in samples: 0.5 for adaa (its two-tap average), 1 for adaa2, the oversampler's exact figure for oversample_2x, 0 for off.
void reset ()
 Never allocates; a zero-initialised instance is already in this state.
SampleType process (SampleType input)
 One sample through the full chain: pre-emphasis, alias-safe shaping, de-emphasis, latency-aligned dry/wet, trim.
double worst_case_gain () const
 The supremum of |shaped(x) / x| over every input, at the current shape and bias — the bound Forge's registry cites (series law 8), and a tested invariant rather than an estimate.
double shaped (double x) const
 The normalised shaper itself, exposed so a caller (or a test) can evaluate the curve without running it through the alias policy or the tone pair.

Static Public Attributes

static constexpr double kDriveDbMin = -12.0
 Drive range in dB.
static constexpr double kDriveDbMax = 36.0
static constexpr double kDriveDbDefault = 0.0
static constexpr double kBiasMax = 1.0
 Bias magnitude ceiling. [design parameter] default 1.0, fixed.
static constexpr double kCubicBiasClamp = 0.98
 The cubic's own clip boundary is at |u| = 1, where f'(b) = 1 − b² reaches zero — and the bias normaliser divides by it.
static constexpr double kTonePreHzDefault = 3000.0
 Pre-emphasis corner.
static constexpr double kTonePreHzMax = 8000.0
static constexpr double kTonePreHzFloor = 20.0
 Lowest corner the shelf will actually be placed at.
static constexpr double kPreBoostDbDefault = 9.0
 Shelf gain magnitude: boost before the shaper, cut after.
static constexpr double kPreBoostDbMax = 18.0
static constexpr double kShelfQ = 0.70710678118654752
 Shelf Q.
static constexpr double kAdaaEpsilon = 1e-6
 ADAA's near-degenerate-denominator guard.
static constexpr double kOutputTrimDbMax = 24.0
 Output trim range. [design parameter] default 0 dB, range ±24 dB.

Detailed Description

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

The memoryless saturation stage.

Member Typedef Documentation

◆ AliasPolicy

template<typename SampleType = float>
using pulp::signal::SaturatorT< SampleType >::AliasPolicy = SaturatorAliasPolicy

◆ Shape

template<typename SampleType = float>
using pulp::signal::SaturatorT< SampleType >::Shape = SaturatorShape

Constructor & Destructor Documentation

◆ SaturatorT()

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

Member Function Documentation

◆ alias_policy()

template<typename SampleType = float>
AliasPolicy pulp::signal::SaturatorT< SampleType >::alias_policy ( ) const
inline

◆ bias()

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::bias ( ) const
inline

The bias actually in force after any shape-specific clamp — exposed so a caller can show the effective value rather than the requested one.

◆ drive_db()

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::drive_db ( ) const
inline

◆ group_delay_samples()

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::group_delay_samples ( ) const
inlinenoexcept

The wet path's exact delay on the linear part of the curve, in samples: 0.5 for adaa (its two-tap average), 1 for adaa2, the oversampler's exact figure for oversample_2x, 0 for off.

◆ latency_samples()

template<typename SampleType = float>
int pulp::signal::SaturatorT< SampleType >::latency_samples ( ) const
inlinenoexcept

The integer delay the host should compensate, matched on the dry path.

One sample for adaa2, whose three-point stencil is centred one sample back; the composed oversampler's own reported latency for oversample_2x; zero for off, and zero for adaa, whose half sample is below what an integer delay can express (group_delay_samples()).

◆ prepare()

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

Sizes the oversampler and the dry-path alignment delay. May allocate.

◆ process()

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

One sample through the full chain: pre-emphasis, alias-safe shaping, de-emphasis, latency-aligned dry/wet, trim.

◆ reset()

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

Never allocates; a zero-initialised instance is already in this state.

◆ set_alias_policy()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_alias_policy ( AliasPolicy policy)
inline

Select the alias policy.

Switching re-seeds both ADAA paths from the two most recent inputs, so the first sample after a switch uses the true input history rather than whatever the path saw when it last ran.

◆ set_bias()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_bias ( double normalized)
inline

Bias as a normalised [-1, +1].

Clamped tighter for cubic_soft, whose slope reaches zero at |b| = 1.

◆ set_drive_db()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_drive_db ( double db)
inline

◆ set_mix()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_mix ( double wet01)
inline

◆ set_output_trim_db()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_output_trim_db ( double db)
inline

◆ set_pre_boost_db()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_pre_boost_db ( double db)
inline

◆ set_shape()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_shape ( Shape shape)
inline

◆ set_tone_de_hz()

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

De-emphasis corner, used only when tracking is off.

◆ set_tone_pre_hz()

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

Pre-emphasis corner in Hz. 0 disables the pre/de pair.

◆ set_tone_tracking()

template<typename SampleType = float>
void pulp::signal::SaturatorT< SampleType >::set_tone_tracking ( bool tracking)
inline

When true (the default) the de-emphasis corner follows the pre-emphasis corner, so the pair cancels exactly.

Set false to shape the asymmetry's low end differently from its top end.

◆ shape()

template<typename SampleType = float>
Shape pulp::signal::SaturatorT< SampleType >::shape ( ) const
inline

◆ shaped()

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::shaped ( double x) const
inline

The normalised shaper itself, exposed so a caller (or a test) can evaluate the curve without running it through the alias policy or the tone pair.

Unity slope at the origin; exactly 0 at 0 for every bias.

◆ worst_case_gain()

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::worst_case_gain ( ) const
inline

The supremum of |shaped(x) / x| over every input, at the current shape and bias — the bound Forge's registry cites (series law 8), and a tested invariant rather than an estimate.

It is f'(0) / f'(b) = 1 / f'(b): the shaper's steepest slope (always at the origin, for all four members) divided by the slope at the operating point that the bias construction normalises by. Exactly 1.0 unbiased. Independent of drive, because the drive law divides by the same d it multiplies the argument by.

Member Data Documentation

◆ kAdaaEpsilon

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kAdaaEpsilon = 1e-6
staticconstexpr

ADAA's near-degenerate-denominator guard.

When two consecutive samples are this close, the difference quotient loses precision and the direct evaluation at their midpoint is used instead.

Honest gap: no citable literature pins this value. Bilbao et al. establish the method and the need for a fallback branch, not a threshold. Any value far below a typical sample-to-sample delta and far above float rounding noise works. [design parameter] default 1e-6, range 1e-9 .. 1e-3.

◆ kBiasMax

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kBiasMax = 1.0
staticconstexpr

Bias magnitude ceiling. [design parameter] default 1.0, fixed.

◆ kCubicBiasClamp

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kCubicBiasClamp = 0.98
staticconstexpr

The cubic's own clip boundary is at |u| = 1, where f'(b) = 1 − b² reaches zero — and the bias normaliser divides by it.

Clamping short of the boundary keeps the divisor away from zero without special-casing. [design parameter] default 0.98, range 0.5 .. 0.999.

◆ kDriveDbDefault

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kDriveDbDefault = 0.0
staticconstexpr

◆ kDriveDbMax

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kDriveDbMax = 36.0
staticconstexpr

◆ kDriveDbMin

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kDriveDbMin = -12.0
staticconstexpr

Drive range in dB.

The floor is below 0 dB on purpose: proving unity gain at a point below unity is more convincing than proving it at unity, where "correct" and "coincidentally close" look the same. [design parameter] default 0 dB, range −12 .. +36 dB.

◆ kOutputTrimDbMax

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kOutputTrimDbMax = 24.0
staticconstexpr

Output trim range. [design parameter] default 0 dB, range ±24 dB.

◆ kPreBoostDbDefault

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kPreBoostDbDefault = 9.0
staticconstexpr

Shelf gain magnitude: boost before the shaper, cut after.

[design parameter] default +9 dB, range 0 .. +18 dB.

◆ kPreBoostDbMax

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kPreBoostDbMax = 18.0
staticconstexpr

◆ kShelfQ

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kShelfQ = 0.70710678118654752
staticconstexpr

Shelf Q.

Butterworth-flat, the neutral choice for a pair whose whole job is to cancel. [design parameter] default 0.7071, range 0.3 .. 2.0.

◆ kTonePreHzDefault

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kTonePreHzDefault = 3000.0
staticconstexpr

Pre-emphasis corner.

0 disables the pair entirely. [design parameter] default 3000 Hz, range 0 (off) .. 8000 Hz, log.

◆ kTonePreHzFloor

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kTonePreHzFloor = 20.0
staticconstexpr

Lowest corner the shelf will actually be placed at.

Below this a "high shelf" is a broadband gain, which is not what the control means.

◆ kTonePreHzMax

template<typename SampleType = float>
double pulp::signal::SaturatorT< SampleType >::kTonePreHzMax = 8000.0
staticconstexpr

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