Two-stage Gardner-style non-uniform partitioned convolution. More...
#include <pulp/signal/convolver.hpp>#include <pulp/signal/convolver_messages.hpp>#include <algorithm>#include <array>#include <cassert>#include <complex>#include <cstddef>#include <cstdint>#include <string_view>#include <type_traits>#include <vector>#include <TargetConditionals.h>#include <sys/sysctl.h>Go to the source code of this file.
Classes | |
| class | pulp::signal::NonUniformPartitionedConvolverT< SampleType > |
| Two-stage non-uniform partitioned convolver. More... | |
Namespaces | |
| namespace | pulp |
| namespace | pulp::signal |
Macros | |
| #define | PULP_NON_UNIFORM_MEASURED_TABLE 0 |
Typedefs | |
| using | pulp::signal::NonUniformPartitionedConvolver = NonUniformPartitionedConvolverT<float> |
| using | pulp::signal::NonUniformPartitionedConvolver64 = NonUniformPartitionedConvolverT<double> |
Two-stage Gardner-style non-uniform partitioned convolution.
NonUniformPartitionedConvolver splits an impulse response into: • a small-block "head" stage processing the first head_samples of the IR at the user-provided audio block size B (zero-latency overlap-save partitioned convolution), and • a large-block "tail" stage processing IR samples [head_samples, ir_length) at a larger block size K · B (K ≥ 2), which fires only every K audio blocks, amortizing the larger FFT cost across many small blocks.
Why: a single uniform partitioned convolver at block size B pays the per-block FFT cost on every block. A long IR (1 s @ 48 kHz = 48 000 samples) needs num_partitions = ceil(ir_len / B) complex multiplies per block in the frequency-domain accumulate; the FFTs themselves stay O(B log B) per block. Switching the tail to a larger block size collapses those tail-partition spectra into fewer (and larger) FFT bins and runs the convolution loop on a schedule of one out of every K blocks.
Latency: zero — head stage produces the current block immediately via overlap-save. The tail stage's contribution to a given input sample arrives at the output head_samples samples later, which is exactly where tail IR taps would have contributed in a direct convolution.
Acceptance pinned in test/test_convolver_non_uniform.cpp: • impulse round-trip matches the IR within float epsilon, • non-uniform output matches uniform PartitionedConvolver output to within float epsilon over a sine sweep, • short noise burst through a 4 096-tap IR matches the direct-convolution reference within float epsilon.
IR loading: unlike the uniform convolver, this class does not provide a background swapper. load_ir() rebuilds both stages inline and must be called off the audio thread.
| #define PULP_NON_UNIFORM_MEASURED_TABLE 0 |