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

See the file doc block for the schedule and its lineage. More...

#include <zero_latency_convolver.hpp>

Public Member Functions

void prepare (double sample_rate, int max_block, int channels)
 Size the engine.
bool load_impulse_response (const SampleType *const *ir_channels, int ir_channel_count, int ir_length, double ir_sample_rate)
 Ingest an impulse response.
void set_ir_gain_db (double db)
void set_predelay_ms (double ms)
void set_true_stereo (bool on)
void set_wet_percent (double percent)
void set_dry_percent (double percent)
void set_width_percent (double percent)
void set_lowcut_hz (double hz)
void set_highcut_hz (double hz)
void set_normalize_mode (IrNormalizeMode mode)
 Load-time policy knobs.
void set_tail_trim_db (double db)
void set_tail_fade_ms (double ms)
void set_resample_taps_per_phase (int taps)
void process (const SampleType *const *in, SampleType *const *out, int n)
 Convolve n <= max_block samples. Allocation-free and lock-free.
void reset ()
 Drop all convolution history. Allocation-free.
int latency_samples () const
 The headline invariant.
double worst_case_gain () const
 ir_gain_linear * ||h||_1, the exact l-infinity operator norm of the wet path: |y[n]| <= ||h||_1 * max|x|, with equality approached by the sign-matched input x[n] = sign(h[N-1-n]).
double l1_norm () const
 ||h||_1 under the current channel routing, without the IR trim.
bool is_loaded () const
int head_length () const
int num_levels () const
int level_block_length (int level) const
int level_ir_start (int level) const
int level_partitions (int level) const
int level_margin (int level) const
 Scheduling margin of level i, in samples: the time between its frame closing and the first output it owns falling due, d - L + 1.
int prepared_ir_length () const
int prepared_ir_channels () const
const SampleType * prepared_ir (int channel) const
long long last_block_cost () const
 Estimated real flops performed by the most recent process() call.
double sample_rate () const
IrNormalizeMode normalize_mode () const
double tail_trim_db () const
double tail_fade_ms () const
double predelay_ms () const
int predelay_samples () const

Static Public Member Functions

static bool valid_resample_geometry (int source_length, double source_rate, double destination_rate, int taps_per_phase) noexcept
 Proves every resampler geometry value is finite and representable before the ingest path casts it to int or allocates source/destination work.

Static Public Attributes

static constexpr int kHeadLenMin = 64
 Head length N0, in taps.
static constexpr int kHeadLenMax = 512
static constexpr double kIrGainDbDefault = 0.0
 IR trim on the convolved path. [dp, default 0 dB, range -24..+24 dB].
static constexpr double kIrGainDbMin = -24.0
static constexpr double kIrGainDbMax = 24.0
static constexpr double kPredelayMsDefault = 0.0
 Pre-IR delay of the wet path.
static constexpr double kPredelayMsMin = 0.0
static constexpr double kPredelayMsMax = 250.0
static constexpr double kWetPercentDefault = 100.0
 Wet / dry mix, in percent. [dp, defaults 100 % / 0 %, range 0..100 %].
static constexpr double kDryPercentDefault = 0.0
static constexpr double kLowcutHzDefault = 20.0
 Send-EQ corners.
static constexpr double kLowcutHzMin = 20.0
static constexpr double kLowcutHzMax = 500.0
static constexpr double kHighcutHzDefault = 20000.0
static constexpr double kHighcutHzMin = 1000.0
static constexpr double kHighcutHzMax = 20000.0
static constexpr double kWidthPercentDefault = 100.0
 Mid/side width of the wet output. [dp, default 100 %, range 0..200 %].
static constexpr double kWidthPercentMin = 0.0
static constexpr double kWidthPercentMax = 200.0
static constexpr double kTailTrimDbDefault = -72.0
 IR truncation floor on the Schroeder backward-energy curve.
static constexpr double kTailTrimDbMin = -90.0
static constexpr double kTailTrimDbMax = -40.0
static constexpr double kTailFadeMsDefault = 5.0
 Raised-cosine fade applied to the last part of the kept IR so the truncation cannot click.
static constexpr double kTailFadeMsMin = 2.0
static constexpr double kTailFadeMsMax = 20.0
static constexpr int kResampTapsPerPhaseDefault = 32
 Resampler kernel width, in taps per polyphase branch.
static constexpr int kResampTapsPerPhaseMin = 16
static constexpr int kResampTapsPerPhaseMax = 64
static constexpr double kResampKaiserBeta = 8.0
 House Kaiser window shape, fixed by the series contract's oversampling / resampling law — not a tunable of this module.
static constexpr double kBlockCostSlackDefault = 1.5
 Peak-to-mean per-block cost slack the distributed schedule is allowed.
static constexpr double kBlockCostSlackMin = 1.2
static constexpr double kBlockCostSlackMax = 2.0
static constexpr double kSilenceEpsilon = 1e-24
 Below this, energies are treated as zero.

Detailed Description

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

See the file doc block for the schedule and its lineage.

Channel policy follows the true-stereo contract: 1 IR channel is applied to both ears, 2 IR channels are dual-mono (no crossfeed), 4 IR channels are the full 2x2 matrix in the order [LL, LR, RL, RR] and are only cross-routed when set_true_stereo(true) is engaged.

Member Function Documentation

◆ head_length()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::head_length ( ) const
inline

◆ is_loaded()

template<typename SampleType = float>
bool pulp::signal::ZeroLatencyConvolverT< SampleType >::is_loaded ( ) const
inline

◆ l1_norm()

template<typename SampleType = float>
double pulp::signal::ZeroLatencyConvolverT< SampleType >::l1_norm ( ) const
inline

||h||_1 under the current channel routing, without the IR trim.

◆ last_block_cost()

template<typename SampleType = float>
long long pulp::signal::ZeroLatencyConvolverT< SampleType >::last_block_cost ( ) const
inline

Estimated real flops performed by the most recent process() call.

Always-on integer accounting; the per-block compute bound test reads it.

◆ latency_samples()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::latency_samples ( ) const
inline

The headline invariant.

Always 0 — the head is a direct FIR over samples that are all present in the current block, and every FFT partition's output is due at least its own block length after its frame closes.

◆ level_block_length()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::level_block_length ( int level) const
inline

◆ level_ir_start()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::level_ir_start ( int level) const
inline

◆ level_margin()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::level_margin ( int level) const
inline

Scheduling margin of level i, in samples: the time between its frame closing and the first output it owns falling due, d - L + 1.

Load balancing requires this to be at least the level's own block length.

◆ level_partitions()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::level_partitions ( int level) const
inline

◆ load_impulse_response()

template<typename SampleType = float>
bool pulp::signal::ZeroLatencyConvolverT< SampleType >::load_impulse_response ( const SampleType *const * ir_channels,
int ir_channel_count,
int ir_length,
double ir_sample_rate )
inline

Ingest an impulse response.

Worker / prepare context — MAY allocate.

Pipeline, in order: channel map, resample to the session rate with broadband energy preserved by measurement, DC removal, Schroeder tail trim plus raised-cosine fade, amplitude normalization, then the partition spectra and the cached L1 norms.

A channel count other than 1, 2, or 4 is a load error: the previous IR is kept and false is returned.

◆ normalize_mode()

template<typename SampleType = float>
IrNormalizeMode pulp::signal::ZeroLatencyConvolverT< SampleType >::normalize_mode ( ) const
inline

◆ num_levels()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::num_levels ( ) const
inline

◆ predelay_ms()

template<typename SampleType = float>
double pulp::signal::ZeroLatencyConvolverT< SampleType >::predelay_ms ( ) const
inline

◆ predelay_samples()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::predelay_samples ( ) const
inline

◆ prepare()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::prepare ( double sample_rate,
int max_block,
int channels )
inline

Size the engine.

May allocate. channels is the audio channel count (1 or 2); the IR channel count is independent and arrives with the IR.

◆ prepared_ir()

template<typename SampleType = float>
const SampleType * pulp::signal::ZeroLatencyConvolverT< SampleType >::prepared_ir ( int channel) const
inline

◆ prepared_ir_channels()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::prepared_ir_channels ( ) const
inline

◆ prepared_ir_length()

template<typename SampleType = float>
int pulp::signal::ZeroLatencyConvolverT< SampleType >::prepared_ir_length ( ) const
inline

◆ process()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::process ( const SampleType *const * in,
SampleType *const * out,
int n )
inline

Convolve n <= max_block samples. Allocation-free and lock-free.

◆ reset()

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

Drop all convolution history. Allocation-free.

◆ sample_rate()

template<typename SampleType = float>
double pulp::signal::ZeroLatencyConvolverT< SampleType >::sample_rate ( ) const
inline

◆ set_dry_percent()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_dry_percent ( double percent)
inline

◆ set_highcut_hz()

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

◆ set_ir_gain_db()

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

◆ set_lowcut_hz()

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

◆ set_normalize_mode()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_normalize_mode ( IrNormalizeMode mode)
inline

Load-time policy knobs.

Changing any of them takes effect on the NEXT load_impulse_response() — by definition they re-read the IR.

◆ set_predelay_ms()

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

◆ set_resample_taps_per_phase()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_resample_taps_per_phase ( int taps)
inline

◆ set_tail_fade_ms()

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

◆ set_tail_trim_db()

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

◆ set_true_stereo()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_true_stereo ( bool on)
inline

◆ set_wet_percent()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_wet_percent ( double percent)
inline

◆ set_width_percent()

template<typename SampleType = float>
void pulp::signal::ZeroLatencyConvolverT< SampleType >::set_width_percent ( double percent)
inline

◆ tail_fade_ms()

template<typename SampleType = float>
double pulp::signal::ZeroLatencyConvolverT< SampleType >::tail_fade_ms ( ) const
inline

◆ tail_trim_db()

template<typename SampleType = float>
double pulp::signal::ZeroLatencyConvolverT< SampleType >::tail_trim_db ( ) const
inline

◆ valid_resample_geometry()

bool pulp::signal::ZeroLatencyConvolverDesign::valid_resample_geometry ( int source_length,
double source_rate,
double destination_rate,
int taps_per_phase )
inlinestaticnoexceptinherited

Proves every resampler geometry value is finite and representable before the ingest path casts it to int or allocates source/destination work.

Public so registration-time wrappers can reject unusable IR metadata before retaining a shared copy.

◆ worst_case_gain()

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

ir_gain_linear * ||h||_1, the exact l-infinity operator norm of the wet path: |y[n]| <= ||h||_1 * max|x|, with equality approached by the sign-matched input x[n] = sign(h[N-1-n]).

For a multi-channel IR this is the worst ear, i.e. the largest sum of ||h||_1 over the cells feeding one output channel under the current routing. Measured at load, never estimated.

This is the WET-path bound the registry cites. The bound on the mixed output additionally includes the dry sum: dry_gain + wet_gain * worst_case_gain().

Member Data Documentation

◆ kBlockCostSlackDefault

double pulp::signal::ZeroLatencyConvolverDesign::kBlockCostSlackDefault = 1.5
staticconstexprinherited

Peak-to-mean per-block cost slack the distributed schedule is allowed.

[dp, default 1.5, range 1.2..2.0] Absorbs the fact that a sliced transform's phases (permuted gather, butterfly stages, conjugate passes) have different per-item costs, so equal budgets do not produce exactly equal flop counts.

◆ kBlockCostSlackMax

double pulp::signal::ZeroLatencyConvolverDesign::kBlockCostSlackMax = 2.0
staticconstexprinherited

◆ kBlockCostSlackMin

double pulp::signal::ZeroLatencyConvolverDesign::kBlockCostSlackMin = 1.2
staticconstexprinherited

◆ kDryPercentDefault

double pulp::signal::ZeroLatencyConvolverDesign::kDryPercentDefault = 0.0
staticconstexprinherited

◆ kHeadLenMax

int pulp::signal::ZeroLatencyConvolverDesign::kHeadLenMax = 512
staticconstexprinherited

◆ kHeadLenMin

int pulp::signal::ZeroLatencyConvolverDesign::kHeadLenMin = 64
staticconstexprinherited

Head length N0, in taps.

[design parameter, default = host block size, range 64..512] Tying N0 to the block size is what lets the head be a plain dot product over samples that are all present in the current block, which is the zero-latency property (see the file doc block).

◆ kHighcutHzDefault

double pulp::signal::ZeroLatencyConvolverDesign::kHighcutHzDefault = 20000.0
staticconstexprinherited

◆ kHighcutHzMax

double pulp::signal::ZeroLatencyConvolverDesign::kHighcutHzMax = 20000.0
staticconstexprinherited

◆ kHighcutHzMin

double pulp::signal::ZeroLatencyConvolverDesign::kHighcutHzMin = 1000.0
staticconstexprinherited

◆ kIrGainDbDefault

double pulp::signal::ZeroLatencyConvolverDesign::kIrGainDbDefault = 0.0
staticconstexprinherited

IR trim on the convolved path. [dp, default 0 dB, range -24..+24 dB].

◆ kIrGainDbMax

double pulp::signal::ZeroLatencyConvolverDesign::kIrGainDbMax = 24.0
staticconstexprinherited

◆ kIrGainDbMin

double pulp::signal::ZeroLatencyConvolverDesign::kIrGainDbMin = -24.0
staticconstexprinherited

◆ kLowcutHzDefault

double pulp::signal::ZeroLatencyConvolverDesign::kLowcutHzDefault = 20.0
staticconstexprinherited

Send-EQ corners.

[dp, defaults 20 Hz / 20 kHz, ranges 20..500 Hz and 1 k..20 kHz] Each endpoint is defined as OFF: at lowcut_hz == 20 the high-pass is bypassed and at highcut_hz == 20000 the low-pass is bypassed, so the default send path is an exact identity. Without that rule a 1-pole filter sits in the path at the default setting and the engine cannot reproduce its own impulse response, which the impulse identity acceptance test requires to floating-point round-off.

◆ kLowcutHzMax

double pulp::signal::ZeroLatencyConvolverDesign::kLowcutHzMax = 500.0
staticconstexprinherited

◆ kLowcutHzMin

double pulp::signal::ZeroLatencyConvolverDesign::kLowcutHzMin = 20.0
staticconstexprinherited

◆ kPredelayMsDefault

double pulp::signal::ZeroLatencyConvolverDesign::kPredelayMsDefault = 0.0
staticconstexprinherited

Pre-IR delay of the wet path.

[dp, default 0 ms, range 0..250 ms] Signal delay, not I/O latency — latency_samples() is 0 regardless.

◆ kPredelayMsMax

double pulp::signal::ZeroLatencyConvolverDesign::kPredelayMsMax = 250.0
staticconstexprinherited

◆ kPredelayMsMin

double pulp::signal::ZeroLatencyConvolverDesign::kPredelayMsMin = 0.0
staticconstexprinherited

◆ kResampKaiserBeta

double pulp::signal::ZeroLatencyConvolverDesign::kResampKaiserBeta = 8.0
staticconstexprinherited

House Kaiser window shape, fixed by the series contract's oversampling / resampling law — not a tunable of this module.

◆ kResampTapsPerPhaseDefault

int pulp::signal::ZeroLatencyConvolverDesign::kResampTapsPerPhaseDefault = 32
staticconstexprinherited

Resampler kernel width, in taps per polyphase branch.

[dp, default 32, range 16..64] More taps tighten the stopband at proportionally higher load-time cost; load-time only, never on the audio thread.

◆ kResampTapsPerPhaseMax

int pulp::signal::ZeroLatencyConvolverDesign::kResampTapsPerPhaseMax = 64
staticconstexprinherited

◆ kResampTapsPerPhaseMin

int pulp::signal::ZeroLatencyConvolverDesign::kResampTapsPerPhaseMin = 16
staticconstexprinherited

◆ kSilenceEpsilon

double pulp::signal::ZeroLatencyConvolverDesign::kSilenceEpsilon = 1e-24
staticconstexprinherited

Below this, energies are treated as zero.

Guards a divide and a log of an all-silent IR; any value far below the single-precision noise floor works, range 1e-30..1e-18.

◆ kTailFadeMsDefault

double pulp::signal::ZeroLatencyConvolverDesign::kTailFadeMsDefault = 5.0
staticconstexprinherited

Raised-cosine fade applied to the last part of the kept IR so the truncation cannot click.

[dp, default 5 ms, range 2..20 ms]

◆ kTailFadeMsMax

double pulp::signal::ZeroLatencyConvolverDesign::kTailFadeMsMax = 20.0
staticconstexprinherited

◆ kTailFadeMsMin

double pulp::signal::ZeroLatencyConvolverDesign::kTailFadeMsMin = 2.0
staticconstexprinherited

◆ kTailTrimDbDefault

double pulp::signal::ZeroLatencyConvolverDesign::kTailTrimDbDefault = -72.0
staticconstexprinherited

IR truncation floor on the Schroeder backward-energy curve.

[dp, default -72 dB, range -90..-40 dB]

◆ kTailTrimDbMax

double pulp::signal::ZeroLatencyConvolverDesign::kTailTrimDbMax = -40.0
staticconstexprinherited

◆ kTailTrimDbMin

double pulp::signal::ZeroLatencyConvolverDesign::kTailTrimDbMin = -90.0
staticconstexprinherited

◆ kWetPercentDefault

double pulp::signal::ZeroLatencyConvolverDesign::kWetPercentDefault = 100.0
staticconstexprinherited

Wet / dry mix, in percent. [dp, defaults 100 % / 0 %, range 0..100 %].

◆ kWidthPercentDefault

double pulp::signal::ZeroLatencyConvolverDesign::kWidthPercentDefault = 100.0
staticconstexprinherited

Mid/side width of the wet output. [dp, default 100 %, range 0..200 %].

◆ kWidthPercentMax

double pulp::signal::ZeroLatencyConvolverDesign::kWidthPercentMax = 200.0
staticconstexprinherited

◆ kWidthPercentMin

double pulp::signal::ZeroLatencyConvolverDesign::kWidthPercentMin = 0.0
staticconstexprinherited

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