DSPark 1.6.1
Header-only audio DSP framework in pure C++20 — zero dependencies
Loading...
Searching...
No Matches
AlgorithmicReverb.h File Reference

World-class 16-line FDN reverb with Jot absorption and Hadamard mixing. More...

#include "../Core/RingBuffer.h"
#include "../Core/DryWetMixer.h"
#include "../Core/DspMath.h"
#include "../Core/AudioSpec.h"
#include "../Core/AudioBuffer.h"
#include "../Core/DenormalGuard.h"
#include "../Core/Biquad.h"
#include "../Core/StateBlob.h"
#include <algorithm>
#include <array>
#include <atomic>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <vector>
Include dependency graph for AlgorithmicReverb.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  dspark::AlgorithmicReverb< T >
 16-line FDN reverb with Jot absorption and 6 presets. More...
 
struct  dspark::AlgorithmicReverb< T >::SmoothRandomLFO
 Hermite-interpolated random noise generator for organic modulation. More...
 
struct  dspark::AlgorithmicReverb< T >::CachedParams
 
struct  dspark::AlgorithmicReverb< T >::PresetValues
 

Namespaces

namespace  dspark
 Main namespace for the DSPark framework.
 

Detailed Description

World-class 16-line FDN reverb with Jot absorption and Hadamard mixing.

Architecture:

Input (mono sum)
|
v
[Pre-delay: 0-200ms]
|
v
[Input Diffusion: 8 cascaded allpass, 1.0-9.5ms]
|
+--> [Early Reflections: 40 taps with progressive HF absorption, L/R decorrelated]
|
+--> [ER-to-Late gap]
| |
| v
| [Parallel Allpass Diffuser: 16 parallel AP + Hadamard -> 16 delay + Hadamard]
| (2-step, 16^2 = 256 echo paths, each FDN line gets unique dense input)
| |
| v
| [FDN Core: 16 delay lines]
| +- Read with dual smooth-random-LFO modulated delay
| +- Householder 16x16 reflection (I - (2/N)J, lossless) feedback mix
| +- Jot absorption filter (1st-order shelving) per line
| +- Bass shelf (1-pole) per line
| +- 2 feedback allpass per line
| +- DC blocker + soft limiter
| +- Write back + input injection
| |
| v
| [Output: sign-weighted + Dattorro multi-tap]
| |
| v
| [Output Diffusion: 2 allpass/channel, L/R decorrelated]
|
v
[Combine early + late] -> [Tone EQ: Biquad LP + HP (12 dB/oct)] -> DryWetMixer -> Output

Key features:

  • Jot absorption filter (Jot 1991): 1st-order pole-zero shelving IIR per delay line for smooth frequency-dependent decay, the #1 factor for natural sound. DC and Nyquist gains anchor the mid/HF T60 exactly; the transition sits at the high crossover. Separate bass shelf for independent LF control.
  • Householder 16x16 FDN feedback (I - (2/N)J): unitary reflection, eigenvalues {-1 once, +1 x15}, |lambda|=1 so it is lossless and zero-coloring. (The Hadamard 16x16 below is the input diffuser's mix, not the feedback matrix.)
  • Parallel allpass diffuser (Signalsmith-inspired): 16 parallel allpass
    • 2-step Hadamard mixing (all eigenvalues +/-1) -> 256 unique echo paths per input sample. Each FDN line receives a different, densely-mixed version of the input.
  • Feedback allpass: 2 regular allpass per delay line for in-loop density
  • Output diffusion: 2 allpass per channel with decorrelated delays, smears residual temporal patterns
  • Smooth random modulation (Lexicon-style): Hermite-interpolated noise replaces periodic sine LFOs for organic character
  • Multi-tap output (Dattorro-style): 7 taps/channel from different delay line positions for true temporal decorrelation
  • Tone correction EQ: Biquad high/low cut (12 dB/oct) for tonal shaping
  • Early reflections: 40-tap with progressive frequency absorption simulating wall absorption; late taps are naturally darker
  • Soft saturation: fast branchless rational soft-clip (transparent below +/-1), more musical than a hard clamp, prevents pipeline stalls.
  • Allpass interpolation: in modulated FDN reads, preserves HF over hundreds of feedback iterations (linear/cubic causes cumulative dulling)
  • Stereo width: M/S width control on late reverb tail
  • Eco quality mode (setQuality): opt-in reduced engine (8 FDN lines, control-rate modulation, linear allpass interpolation, no extra output taps, single-stage input scatter, 12 early taps) at a fraction of the CPU cost, for embedded and other constrained targets. The default Full quality path is bit-identical to previous releases.

Threading: prepare() belongs to the setup thread (allocates). processBlock(), processSample() and reset() belong to the audio thread. All setters are lock-free atomic publications, safe from any thread; topology changes (type, quality) and coefficient refreshes are drained at the start of the next processBlock()/processSample() on the audio thread. Non-finite setter arguments are ignored.

Four levels of API complexity:

  • Level 1: reverb.setType(Hall);
  • Level 2: reverb.setSize(0.7f); reverb.setDamping(0.3f);
  • Level 3: reverb.setHighDecayMultiplier(0.4f);
  • Level 4: Inherit and override protected members.

References:

  • Jot & Chaigne (1991): FDN with frequency-dependent decay (shelving absorption)
  • Dattorro (1997, JAES): multi-tap output, plate topology
  • Griesinger / Lexicon 480L: random modulation, Spin/Wander
  • Sean Costello / Valhalla DSP: practical FDN design, absorbent allpass
  • Valimaki et al. (2012, IEEE): "50 Years of Artificial Reverberation"
  • Smith (CCRMA): Hadamard matrices, prime power delay selection

Dependencies: RingBuffer.h, DryWetMixer.h, DspMath.h, Biquad.h, AudioSpec.h, AudioBuffer.h, DenormalGuard.h, StateBlob.h.

reverb.prepare(spec);
reverb.setDecay(2.0f);
reverb.setMix(0.3f);
reverb.processBlock(buffer);
// Advanced: tune frequency-dependent decay
reverb.setHighDecayMultiplier(0.4f); // HF decays 2.5x faster
reverb.setBassDecayMultiplier(1.3f); // bass lingers 1.3x longer
16-line FDN reverb with Jot absorption and 6 presets.
void setType(Type type) noexcept
void setMix(T dryWet) noexcept
void processBlock(AudioBufferView< T > buffer) noexcept
Processes an audio block in-place with zero allocations.
void setHighDecayMultiplier(T mult) noexcept
Sets HF decay as a multiplier of mid decay time.
void prepare(const AudioSpec &spec)
Prepares the reverberation engine and allocates required memory.
void setDecay(T seconds) noexcept
void setBassDecayMultiplier(T mult) noexcept
Sets bass decay as a multiplier of mid decay time.

Definition in file AlgorithmicReverb.h.