A frequency-domain artificial reverberation effect. FDverb is implemented as a plugin (see plugin/) and as an offline Python implementation (see python/).
📄 Paper: "A Frequency-Domain Artificial Reverberator Plug-In," demo paper presented at the Int. Conf. Digital Audio Effects (DAFx-26), Cambridge, 2026. [PDF] [arXiv]
Developed by Nishanth Kumar, Silvan Krebs, David Wieland, Christoph Studer, and Jonas Roth at the Integrated Information Processing (IIP) Group at ETH Zurich.
Built using the JUCE framework.
- Frequency-domain reverb processing using STFT
- Envelope follower with decay control
- Frequency-dependent decay (tilt)
- Spectral shifting (static and dynamic)
- Brick-wall EQ (low cut / high cut)
- Freeze mode with input gate
- Synthetic early reflections
- Stereo link and width control
The Python implementation has a number of extra features implemented, compared to the plugin implementation:
- Load a preset early-reflections IR (config parameter
early_reflections:er_preset). - Send early-reflections signal to tail reverberator (config parameter
early_reflections:er2tail_gain). - Tune the early-reflections decay rate (config parameter
early_reflections:decay_rate, in dB/ms). The plugin fixes this rate at 0.2 dB/ms, so presets must keep that value to match it.
FDverb is a hybrid pipeline with two parts:
- Early reflections (ER): a synthetic, sparse ER impulse response, implemented as a sparse convolution in the time domain so it adds no extra latency.
- Tail reverberator: a vocoder with a noise carrier. The input is analyzed with an STFT, each frequency bin gets its own envelope follower, and these envelopes weight the spectral components of a noise signal. Conceptually related to spectral magnitude decay (Vickers et al., AES 121st Conv., 2006).
| Parameter | Description |
|---|---|
block_size |
STFT block size. Trade-off between frequency resolution and the lower limit on tail_delay. |
mode |
Envelope (AR-averager) mode — see below. |
color |
Amplitude power γ. Affects dynamics and frequency weighting. |
time |
Nominal T60 decay time. |
tilt |
Increase/decrease decay time for lower/higher frequencies. |
shift |
Static pitch shift (offsets the input bins). |
drift |
Dynamic pitch shift (offsets the AR-averager states). |
link |
Links envelopes between the stereo channels (follows the maximum). |
width |
Correlates, decorrelates, or anti-correlates the noise carrier between the stereo channels. |
low_cut / high_cut |
Brick-wall EQ applied to the noise carrier. |
Modes
| Mode | Behavior |
|---|---|
logarithmic |
Exponential-decay envelope (constant factor). Sounds like a regular reverb. |
arithmetic |
Linear envelope (constant decrement). Sounds like a gated reverb. |
freeze |
Infinite sustain; gate controls whether the input signal is routed into the reverb. |
Tap delays follow a pseudo-random pattern, with delays distributed between pre_delay and tail_delay (density grows ∝ t²) and a fixed amplitude decay of −0.2 dB/ms (tunable in Python only, see above).
| Parameter | Description |
|---|---|
echoes |
Number of ER taps. |
pre_delay |
Delay of the first reflection. Also sets the RNG seed for the tap pattern. |
tail_delay |
Delay of the last reflection and onset of the tail reverberator. Lower limit depends on block_size. |
See our releases for pre-compiled plugin binaries.
Alternatively, follow the instructions below to build from source.
git clone --recurse-submodules git@github.com:IIP-Group/FDverb.git
cd FDverboffline reference implementation
Create virtual environment and install requirements:
cd python
python3.13 -m venv env_fdverb
source env_fdverb/bin/activate
pip install -r requirements.txtParameter presets are found in the presets/ directory.
The paths to the active parameter config and audio input file are set at the beginning of the notebook.
To tweak parameters, edit presets/default.yaml or create a new YAML and adjust the path in the notebook.
Open Jupyter notebook python/FDverb.ipynb and run cells.
Output is saved to python/out/out.wav and plays automatically.
Recommended development requirements are provided in python/requirements-dev.txt.
pip install -r requirements-dev.txt
nbstripout --installUser requirements are maintained in python/requirements.in and compiled using
pip-compile requirements.in- CMake 3.22+
- C++17-compatible compiler
- JUCE framework
cd plugin
cmake --preset macos # or: windows
cmake --build --preset macos-release # or: windows-releaseBuild presets: macos-debug, macos-release, windows-debug, windows-release.
Use Release for listening tests and releases — Debug builds are unoptimized and show
-debug next to the version number in the UI.
Plugins are output to plugin/build/FDverb_artefacts/<Config>/, where <Config> is
Debug or Release, and are copied to the standard user plugin directory after each
build. To disable the copy, remove this line from plugin/CMakeLists.txt:
COPY_PLUGIN_AFTER_BUILD TRUEOn Windows the default location C:\Program Files\Common Files\VST3\ is a protected
system folder, so the copy fails unless Visual Studio runs as administrator.
cmake --preset macos also generates plugin/build/FDverb.xcodeproj. Visual Studio
(File > Open > Folder...) and VS Code (CMake Tools) read the presets directly; select the
configuration from the preset list.
To re-run the processFrame() timing measurements, build with -DFDVERB_MEASURE_TIMING=ON:
cd plugin
cmake --preset macos -DFDVERB_MEASURE_TIMING=ON
cmake --build --preset macos-releaseWhile the plugin runs, measurements are appended to ~/Desktop/fdverb_runtime_measurements/<timestamp>_blocksize_<N>.txt.
Since the AU is declared sandbox-safe (AU_SANDBOX_SAFE), a sandboxed host may redirect that path into its own container, e.g. ~/Library/Containers/<host>/Data/Desktop/.
Run python/scripts/runtime_analysis.ipynb to analyze the results — it reads directly from that directory.
Rebuild with -DFDVERB_MEASURE_TIMING=OFF when done.
FDverb ships with factory presets. Whether they appear automatically or need a one-time install depends on your host.
Nothing to do. The presets are embedded in the plugin and appear in the host's native preset menu automatically.
These hosts don't read the plugin's built-in preset list; they look for .vstpreset files on disk.
Copy the files from presets/vstpreset/ into the VST3 preset folder for your OS:
- macOS:
~/Library/Audio/Presets/IIP/FDverb/ - Windows:
%USERPROFILE%\Documents\VST3 Presets\IIP\FDverb\ - Linux:
~/.vst3/presets/IIP/FDverb/
Then restart the host (or rescan its preset/media library) so it picks them up.
These instructions are for contributors changing the presets that ship with FDverb. If you just want to use the existing presets, see Factory Presets above.
A preset exists in three forms:
- YAML source in presets/ is authoritative.
- JUCE state XML in presets/generated/ is derived from it and embedded in the binary (Logic/Reaper).
.vstpresetfiles in presets/vstpreset/ are exported from the built plugin (Ableton/Cubase/Studio One).
- Create the YAML in
presets/, followingpresets/default.yaml. - Add it to
PRESET_FILESinpython/scripts/yaml_to_preset.py(filename + display name). - Add its
BinaryData::entry tokPresets[]inplugin/src/PluginProcessor.cpp(JUCE strips hyphens from BinaryData identifiers). - Reconfigure CMake (
cmake --preset macos # or windows, see above) so the glob picks up the new XML.
Then run the build steps below from step 6.
- Edit the YAML in
presets/. - Regenerate the XML:
python python/scripts/yaml_to_preset.py(from the repo root). - Re-export the
.vstpresetfile: load FDverb in Reaper, select the preset, and save it as a.vstpresetintopresets/vstpreset/. - Build, and commit the YAML plus the updated
generated/andvstpreset/files.
If you use FDverb in your work, please cite:
@misc{roth2026fdverb,
author = {Roth, Jonas and Kumar, Nishanth and Krebs, Silvan and Wieland, David and Studer, Christoph},
title = {A Frequency-Domain Artificial Reverberator Plug-In},
howpublished = {Demo paper presented at the Int. Conf. Digital Audio Effects (DAFx-26), Cambridge},
year = {2026},
eprint = {2608.27695},
archivePrefix = {arXiv}
}FDverb is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). The JUCE framework is included as a Git submodule, which is used under the terms of the AGPL. The JUCE framework remains subject to its own license, which is included in the JUCE submodule.
