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

Zero-latency convolution with one impulse response for the lifetime of a preparation, running whichever engine is cheaper for that IR length and block size. More...

#include <fixed_ir_convolver.hpp>

Public Member Functions

void load_ir (const SampleType *ir, std::size_t ir_length, std::size_t block_size)
 Load an IR on the engine choose_backend() selects.
void load_ir (const SampleType *ir, std::size_t ir_length, std::size_t block_size, ConvolutionBackend engine)
 Load an IR on a named engine, for callers with their own measurements for the target.
void process (const SampleType *input, SampleType *output, std::size_t num_samples)
 Process one block.
void reset ()
 Clear the history so the next block starts from silence.
bool is_loaded () const noexcept
std::size_t block_size () const noexcept
 The load_ir() request rounded up to a power of two: the exact frame count the FFT engine requires, and the largest the direct engine accepts.
std::size_t latency () const noexcept
std::uint64_t block_size_violations () const noexcept
 Calls to process() with a frame count the engine cannot take (any other than block_size() for the FFT engine, more than block_size() for the direct engine) since the last load_ir() or reset().
ConvolutionBackend backend () const noexcept

Static Public Member Functions

static constexpr ConvolutionBackend choose_backend (std::size_t ir_length, std::size_t block_size) noexcept
 The engine policy: a pure function of IR length and block size, so the choice is deterministic and checkable without running audio.
static constexpr std::size_t direct_fir_limit (std::size_t block_size) noexcept
 The longest IR run on the direct engine for a block size.

Detailed Description

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

Zero-latency convolution with one impulse response for the lifetime of a preparation, running whichever engine is cheaper for that IR length and block size.

load_ir() chooses the engine once, from the pure choose_backend() policy; the choice never changes on the audio thread. Both engines are zero latency and allocation-free in process() and reset(). The direct engine accepts any frame count from 1 to block_size() per call, so a host with a non-power-of-two or varying callback works unchanged. The FFT engine accepts exactly block_size() frames. A count an engine cannot take emits silence, counts a violation, and the next valid block starts from fresh history.

Pick this over PartitionedConvolverT when the IR is fixed and the block size is known; it has no live IR swap or crossfade. For long IRs at small callbacks, ZeroLatencyConvolverT (direct head plus FFT tail) and NonUniformPartitionedConvolverT partition the IR non-uniformly instead.

conv.load_ir(ir.data(), ir.size(), block_size); // prepare(): allocates
conv.process(input, output, conv.block_size()); // process(): RT-safe
std::size_t block_size() const noexcept
The load_ir() request rounded up to a power of two: the exact frame count the FFT engine requires,...
Definition fixed_ir_convolver.hpp:186
void process(const SampleType *input, SampleType *output, std::size_t num_samples)
Process one block.
Definition fixed_ir_convolver.hpp:145
void load_ir(const SampleType *ir, std::size_t ir_length, std::size_t block_size)
Load an IR on the engine choose_backend() selects.
Definition fixed_ir_convolver.hpp:66
FixedIrConvolverT< float > FixedIrConvolver
Definition fixed_ir_convolver.hpp:211

Member Function Documentation

◆ backend()

template<typename SampleType = float>
ConvolutionBackend pulp::signal::FixedIrConvolverT< SampleType >::backend ( ) const
inlinenodiscardnoexcept

◆ block_size()

template<typename SampleType = float>
std::size_t pulp::signal::FixedIrConvolverT< SampleType >::block_size ( ) const
inlinenodiscardnoexcept

The load_ir() request rounded up to a power of two: the exact frame count the FFT engine requires, and the largest the direct engine accepts.

Zero when no IR is loaded.

◆ block_size_violations()

template<typename SampleType = float>
std::uint64_t pulp::signal::FixedIrConvolverT< SampleType >::block_size_violations ( ) const
inlinenodiscardnoexcept

Calls to process() with a frame count the engine cannot take (any other than block_size() for the FFT engine, more than block_size() for the direct engine) since the last load_ir() or reset().

Nonzero means a caller bug.

◆ choose_backend()

template<typename SampleType = float>
constexpr ConvolutionBackend pulp::signal::FixedIrConvolverT< SampleType >::choose_backend ( std::size_t ir_length,
std::size_t block_size )
inlinestaticconstexprnoexcept

The engine policy: a pure function of IR length and block size, so the choice is deterministic and checkable without running audio.

◆ direct_fir_limit()

template<typename SampleType = float>
constexpr std::size_t pulp::signal::FixedIrConvolverT< SampleType >::direct_fir_limit ( std::size_t block_size)
inlinestaticconstexprnoexcept

The longest IR run on the direct engine for a block size.

The table is measured in single precision on Apple Silicon Macs with the Accelerate backend (M1 Max, M5 Max and M5 Ultra), single and multi-instance, for IRs of 8 to 4096 taps (receipt: docs/validation/convolver-crossover/; a test recomputes it from those files). Each limit is the lowest of the three chips' crossovers. At 8-frame callbacks and below the direct engine beat the uniform FFT at every measured length, so the limit there is the end of the measured range; longer IRs keep the FFT engine until they are measured. From 16 frames up the real-input FFT wins early: about 576 taps at 16 frames, 128 at 32 and 64, and 64 from 128 frames up.

Everywhere else (other architectures and operating systems, other SIMD backends, double precision) the limit is 0 and the FFT engine runs every IR until that target is measured.

◆ is_loaded()

template<typename SampleType = float>
bool pulp::signal::FixedIrConvolverT< SampleType >::is_loaded ( ) const
inlinenodiscardnoexcept

◆ latency()

template<typename SampleType = float>
std::size_t pulp::signal::FixedIrConvolverT< SampleType >::latency ( ) const
inlinenodiscardnoexcept

◆ load_ir() [1/2]

template<typename SampleType = float>
void pulp::signal::FixedIrConvolverT< SampleType >::load_ir ( const SampleType * ir,
std::size_t ir_length,
std::size_t block_size )
inline

Load an IR on the engine choose_backend() selects.

Prepare-time: allocates and, for the FFT engine, transforms the IR. A null or empty IR unloads.

◆ load_ir() [2/2]

template<typename SampleType = float>
void pulp::signal::FixedIrConvolverT< SampleType >::load_ir ( const SampleType * ir,
std::size_t ir_length,
std::size_t block_size,
ConvolutionBackend engine )
inline

Load an IR on a named engine, for callers with their own measurements for the target.

ConvolutionBackend::none unloads.

◆ process()

template<typename SampleType = float>
void pulp::signal::FixedIrConvolverT< SampleType >::process ( const SampleType * input,
SampleType * output,
std::size_t num_samples )
inline

Process one block.

input and output may be the same buffer; any other overlap is unsupported, because the direct engine writes earlier outputs before it reads later inputs on blocks longer than its history slice.

◆ reset()

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

Clear the history so the next block starts from silence.

Also clears the block-size violation count.


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