Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
resampler.hpp File Reference

Polyphase-FIR resampler with a Kaiser-window low-pass prototype. More...

#include <pulp/signal/mirrored_history_buffer.hpp>
#include <pulp/signal/windowed_sinc_design.hpp>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <vector>

Go to the source code of this file.

Classes

struct  pulp::signal::ResamplerQuality
 Quality knobs for the Kaiser-window prototype. More...
struct  pulp::signal::ResamplerProcessResult
class  pulp::signal::ResamplerT< SampleType >

Namespaces

namespace  pulp
namespace  pulp::signal

Typedefs

using pulp::signal::Resampler = ResamplerT<float>
using pulp::signal::Resampler64 = ResamplerT<double>

Detailed Description

Polyphase-FIR resampler with a Kaiser-window low-pass prototype.

Resampler implements arbitrary-ratio sample-rate conversion using a polyphase decomposition of a windowed-sinc low-pass filter. The prototype is designed once via the Kaiser-window method (cutoff/transition/stopband knobs), oversampled at L phases, and then sliced into L sub-filters. The streaming process_sample path uses a delay-line + phase accumulator and linearly interpolates between adjacent phases for arbitrary (irrational) ratios — this is what lets a single design support 44.1↔48, 48↔96, 96↔192, and near-irrational ratios like 48↔44099 with no per-ratio re-design.

Design lineage: the polyphase decomposition + Kaiser-window prototype is the canonical textbook approach (Oppenheim & Schafer, "Discrete-Time Signal Processing"; Crochiere & Rabiner, "Multirate Digital Signal Processing"). Pulp's implementation is written from first principles against those references — no libsamplerate / SoX / SRC source code consulted.

The Kaiser-window helpers live in windowed_sinc_design.hpp so the arbitrary-ratio resampler and integer-factor oversampler share one design implementation.

Streaming contract:

  • prepare(input_rate, output_rate, channels, max_block_size) allocates the delay line and polyphase tables. After prepare, process_sample() / process_block() are allocation-free in the audio thread.
  • set_ratio(input_rate, output_rate) may be called mid-stream; the phase accumulator is preserved so there's no click beyond the documented transition window (one filter span).
  • reset() zeroes the delay line + phase. Use at transport re-start, not at every block.

Acceptance-test friendly invariants (verified in test/test_resampler.cpp):

  • DC unity gain across ratios.
  • Pure sine in [0, output_nyquist) round-trips with low THD+N.
  • Image / alias energy at the rejected sideband is below the stopband attenuation set at design time.
  • Allocation-free process_block() after prepare().
  • Streaming state survives buffer-size changes without click.