Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::dynamics Namespace Reference

Functions

double retain_finite (double candidate, double current) noexcept
 Control setters retain their last valid value when automation supplies a non-finite sample.
double amplitude_db (double amplitude, double epsilon)
 An amplitude → dB, floored by an ADDEND rather than a max().
double power_db (double mean_square, double epsilon)
 A mean square → dB, floored by an addend.
double one_pole_retain (double tau_seconds, double sample_rate)
 α = exp(−1/(τ·fs)) — the RETAIN coefficient (see the file doc block).
double knee_term_db (double over_db, double knee_db, double slope)
 The knee branch's quadratic term: the dB the characteristic bends away from unity inside the knee, (slope − 1)·(over + W/2)² / (2W).
double soft_knee_output_db (double input_db, double threshold_db, double knee_db, double ratio)
 The characteristic in the OUTPUT-LEVEL domain: input dB → output dB.
double soft_knee_reduction_db (double over_db, double knee_db, double slope)
 The same characteristic in the GAIN-REDUCTION domain: dB over threshold → reduction in dB, SIGNED and ≤ 0 for a compressing slope.

Variables

constexpr double kLevelEpsilon = 1e-12
 Level-conversion floor, guarding log10(0).

Function Documentation

◆ amplitude_db()

double pulp::signal::dynamics::amplitude_db ( double amplitude,
double epsilon )
inline

An amplitude → dB, floored by an ADDEND rather than a max().

20·log10, because the argument is an amplitude. The addend form is chosen over max() here because a detector reading a peak wants a continuous function of its input near silence — a max() puts a corner in the curve at the floor, which a smoother downstream then has to ride over.

◆ knee_term_db()

double pulp::signal::dynamics::knee_term_db ( double over_db,
double knee_db,
double slope )
inline

The knee branch's quadratic term: the dB the characteristic bends away from unity inside the knee, (slope − 1)·(over + W/2)² / (2W).

This is the shared kernel — it is bit-identical in both domain forms below and in all four lineages, which is what makes it the thing worth owning here. slope is 1/R; pass 0 for a limiter's infinite ratio and a negative value for an over-unity ("infinity+") curve. Caller guarantees W > 0.

◆ one_pole_retain()

double pulp::signal::dynamics::one_pole_retain ( double tau_seconds,
double sample_rate )
inline

α = exp(−1/(τ·fs)) — the RETAIN coefficient (see the file doc block).

τ in seconds. Returns 0 (instant) for a non-positive τ or sample rate rather than dividing by zero.

◆ power_db()

double pulp::signal::dynamics::power_db ( double mean_square,
double epsilon )
inline

A mean square → dB, floored by an addend.

10·log10, NOT 20, because the integrator already holds a squared quantity. Getting this wrong doubles every level the detector reports, which reads as a compressor with twice the ratio it was set to and no obvious symptom otherwise — so the two conversions are named separately rather than left to a factor at each call site.

◆ retain_finite()

double pulp::signal::dynamics::retain_finite ( double candidate,
double current )
inlinenoexcept

Control setters retain their last valid value when automation supplies a non-finite sample.

std::clamp alone does not reject NaN because every comparison with NaN is false.

◆ soft_knee_output_db()

double pulp::signal::dynamics::soft_knee_output_db ( double input_db,
double threshold_db,
double knee_db,
double ratio )
inline

The characteristic in the OUTPUT-LEVEL domain: input dB → output dB.

y(x) = x 2(x−T) < −W
= x + (1/R − 1)(x − T + W/2)² / (2W) 2|x−T| ≤ W
= T + (x−T)/R otherwise

ratio may be negative (an "infinity+" curve that keeps pushing output down as input rises); the equation is continuous through that and the caller owns any floor.

Preconditions, which every module enforced with its own clamp before this was shared code and which are therefore not re-checked here: knee_db >= 0 and ratio != 0. There is deliberately no guard — a compressor whose ratio reached zero has a bug upstream, and swallowing it here would hide that while costing a branch per sample. A module whose top-of-range ratio means "limit" should resolve the slope itself and use soft_knee_reduction_db, which takes slope = 0 for an infinite ratio without any division.

◆ soft_knee_reduction_db()

double pulp::signal::dynamics::soft_knee_reduction_db ( double over_db,
double knee_db,
double slope )
inline

The same characteristic in the GAIN-REDUCTION domain: dB over threshold → reduction in dB, SIGNED and ≤ 0 for a compressing slope.

Takes slope = 1/R already resolved rather than R, so a caller that maps its top-of-range ratio onto a true limiter passes 0 without this function needing to know what that module's limit threshold is.

Variable Documentation

◆ kLevelEpsilon

double pulp::signal::dynamics::kLevelEpsilon = 1e-12
inlineconstexpr

Level-conversion floor, guarding log10(0).

Any value far below the quietest representable signal works: this sits ~26 orders above the float32 denormal floor and ~7 orders below −120 dBFS. [design parameter] default 1e-12, range 1e-15 .. 1e-9.