My Projects

RT FFT Convolver

Status: 🚧 Work in progress β€” core engine is functional, offline high-fidelity mode and crossfade IR switching are still planned.

Every guitarist who runs direct into a DAW or amp-sim uses an impulse response (IR) β€” a short WAV file that captures how a real speaker cabinet colours the sound. The problem is latency. Standard FFT convolution is efficient but introduces a full buffer of delay before any output arrives. For a 64-sample buffer at 48 kHz that is 1.3 ms β€” barely audible in isolation, but stack it with driver and interface round-trips and it becomes unplayable.

The solution is partitioned convolution with a zero-latency head: apply the very first samples of the IR directly in the time domain (zero added delay), then switch to FFT-based processing for the rest of the tail where efficiency matters. The result is a convolution engine that sounds like a full FFT convolution but feels like there is none.


rt-fft-convolver is a real-time-safe Rust library for zero-latency partitioned convolution. It is designed as a building block for guitar cabinet simulators, reverb engines, and DAW plugins.

Features

Quick start

[dependencies]
rt-fft-convolver = "0.1"

Mono cabinet simulation:

use rt_fft_convolver::{UniformPartitionEngine, load_ir};

// Off the render thread β€” allocates
let ir = load_ir("cabinet.wav", 48_000)?;
let mut engine = UniformPartitionEngine::new(&ir.channels[0], block_size);

// On the render thread β€” zero allocation
let mut output = vec![0.0f32; block_size];
engine.process(&input, &mut output);

Stereo with a shared mono IR:

use rt_fft_convolver::{StereoConvolver, load_ir};

let ir = load_ir("cabinet.wav", 48_000)?;
let mut conv = StereoConvolver::new_mono_ir(&ir.channels[0], block_size);

conv.process(&in_l, &in_r, &mut out_l, &mut out_r);

True-stereo (4-channel mic capture):

use rt_fft_convolver::{TrueStereoConvolver, load_ir};

// A true-stereo IR WAV has 4 channels: LL, LR, RL, RR
let ir = load_ir("true_stereo_cab.wav", 48_000)?;
let mut conv = TrueStereoConvolver::new(
    &ir.channels[0], // L β†’ L
    &ir.channels[1], // L β†’ R
    &ir.channels[2], // R β†’ L
    &ir.channels[3], // R β†’ R
    block_size,
);

conv.process(&in_l, &in_r, &mut out_l, &mut out_r);

Dry/wet mix with auto-normalization:

use rt_fft_convolver::Mixer;

// Compute IR gain (1 / β€–IRβ€–β‚‚) once, then blend 30% dry / 70% wet
let mut mixer = Mixer::new(&ir_samples, 0.7);
mixer.process(&dry, &wet, &mut output);

Anti-denormal guard (drop at the start of your audio callback):

use rt_fft_convolver::DenormalGuard;

fn audio_callback(buffer: &mut [f32]) {
    let _guard = DenormalGuard::new(); // sets FTZ for this scope
    // … process …
}

Alternatives

rt-fft-convolverfft-convolverzita-convolver
LanguageRustRustC++
Algorithmic latency0 samples1 block1 block (small stage)
Real-time safeβœ…βœ…βœ…
True-stereo (4-ch)βœ…βŒβœ… (up to 64ch)
WAV load + resampleβœ…βŒβŒ
Dry/wet mixerβœ…βŒβŒ
Anti-denormal guardβœ…βŒβ€”
LicenseMITMITGPL-3

fft-convolver is a faithful Rust port of the well-known HiFi-LoFi FFTConvolver C++ library. It uses uniform partitioning with an optional two-stage variant for long IRs. One block of latency is inherent in the algorithm β€” that is the trade-off this library avoids with its direct-form head.

zita-convolver is the reference C++ implementation used in Guitarix and several LV2 plugins. It supports large multi-channel matrices and uses a dual-partition scheme, but it requires linking C++ and carries a GPL licence, which restricts use in commercial plugins.

What’s coming

Repo Β· crates.io Β· lib.rs