Real-Time Room Correction in FFmpeg Using afir
This article explains how to apply real-time acoustic room correction
to a live audio stream using FFmpeg's afir (Audio Finite
Impulse Response) filter. By convolving an incoming live audio feed with
a pre-measured Room Impulse Response (RIR) file, you can neutralize room
resonances, flatten frequency response, and correct phase anomalies on
the fly. You will learn the required prerequisites, the syntax for the
afir filter graph, and a complete command configured for
low-latency streaming.
Prerequisites
To perform real-time room correction, you need:
- A Room Impulse Response (RIR) file: A standard stereo or mono WAV file generated using acoustic measurement software such as Room EQ Wizard (REW). The sample rate of the IR file must match the sample rate of your audio stream to avoid processing artifacts or pitch shifts.
- FFmpeg: A modern build with libavfilter enabled.
- A low-latency audio subsystem: ALSA or PulseAudio/PipeWire on Linux, CoreAudio on macOS, or DirectShow/WASAPI on Windows.
How the afir Filter Works
The afir filter applies an impulse response to an audio
signal via convolution. It requires two input streams:
- Stream 0: The live audio stream that needs correction.
- Stream 1: The correction impulse response file.
By default, the filter convolves corresponding channels (e.g., Left with Left IR, Right with Right IR).
Basic Command Structure
Below is an example using Linux's PulseAudio input and output
devices. It reads audio from the default input monitor (or capture
device), convolves it with room_ir.wav, and outputs the
corrected stream to the default audio output:
ffmpeg -fflags nobuffer -flags low_delay \
-f pulse -i default \
-i room_ir.wav \
-filter_complex "[0:a][1:a]afir=gtype=gn:irnorm=1[out]" \
-map "[out]" \
-f pulse defaultCommand Breakdown and Key Parameters
-fflags nobufferand-flags low_delay: Reduces internal buffering in FFmpeg to keep real-time latency as low as possible.-f pulse -i default: Captures the real-time audio stream from your system's default input or virtual sink monitor.-i room_ir.wav: Loads the impulse response measurement.-filter_complex "[0:a][1:a]afir=...[out]":gtype=gn: Applies auto-gain normalization to prevent the convolved signal from clipping.irnorm=1: Normalizes the IR gain based on its energy level.dry=0:wet=1: Ensures 100% of the output is the corrected signal (default behavior).
-map "[out]": Routes the filtered audio output directly to the output device.-f pulse default: Sends the corrected audio to your output device or DAC.
Platform-Specific Input/Output Adjustments
To adapt the command to different operating systems, change the input
(-f ... -i ...) and output formats:
Windows (WASAPI / DirectShow)
ffmpeg -fflags nobuffer -flags low_delay ^
-f dshow -i audio="Microphone (Realtek Audio)" ^
-i room_ir.wav ^
-filter_complex "[0:a][1:a]afir=gtype=gn:irnorm=1[out]" ^
-map "[out]" ^
-f wasapi defaultmacOS (AVFoundation / CoreAudio)
ffmpeg -fflags nobuffer -flags low_delay \
-f avfoundation -i ":0" \
-i room_ir.wav \
-filter_complex "[0:a][1:a]afir=gtype=gn:irnorm=1[out]" \
-map "[out]" \
-f coreaudio defaultOptimizing Latency and Performance
Real-time convolution is computationally heavy. To prevent buffer underruns, crackling, or high latency:
Truncate the Impulse Response: Keep the length of
room_ir.wavreasonably short (typically 100ms to 500ms). While longer IR files capture low-frequency room modes better, they introduce higher computational overhead.Match Sample Rates Explicitly: Force both the input stream and the filter to run at the exact sample rate of the IR file using the
aresamplefilter or the-arflag:ffmpeg -ar 48000 -f pulse -i default -i room_ir_48k.wav -filter_complex "[0:a]aresample=48000[a0];[a0][1:a]afir=gtype=gn[out]" -map "[out]" -f pulse defaultPartitioned Convolution: The
afirfilter handles partitioning automatically, but minimizing background processes will ensure uninterrupted audio processing.