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 …
}

Plugins β€” two IR loaders

The engine ships with two production-oriented IR-loader plugins built on top of it. Both compile to CLAP and VST3 through nih-plug (LV2 via a CLAPβ†’LV2 bridge), and share a framework-agnostic core crate rt-ir-plugin-core that owns the pieces you don’t want to rewrite twice:

The DSP is fully unit-testable without the plugin runtime: the nih feature is opt-in, so cargo test / clippy stay fast and offline. An optional gui feature layers a nih-plug-egui editor on top (waveform preview, pad states, MIDI-activity indicators).

rt-ir-cab β€” guitar / bass cabinet simulator

Drop-in cabinet block for direct-recorded guitar and bass. Stereoβ†’stereo by default; monoβ†’stereo for the guitarist-into-DAW case. Parameters: current slot, crossfade time, input/output trim (Β±24 dB), dry/wet mix, low-cut (20–500 Hz) and high-cut (2–20 kHz) shelves, IR normalisation toggle, per-slot enable, bypass. Presets follow the classic cab tonestack curves.

rt-ir-reverb β€” convolution reverb

True-stereo capable (4-channel IR matrix) convolution reverb. Stereo in β†’ stereo out. Parameters: slot selection, crossfade time (up to 500 ms β€” reverb tails need it), pre-delay (0–500 ms), dry / wet faders (βˆ’60 to +6 dB with a βˆ’βˆž low end), stereo width (0–200 %), wet-only low-cut / high-cut, IR reverse, IR length fraction (1–100 % β€” trim the tail without reloading), bypass. Presets pair with a bundled room-IR pack.

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