Feedback Network
Tier: Algorithms | ComponentType: 32 | Params: 6
8-line feedback delay network with Hadamard mixing matrix, prime-length delays, one-pole LP damping, and LFO modulation for algorithmic reverb.
Overview
FeedbackNetwork implements a Feedback Delay Network (FDN) -- a standard building block for algorithmic reverberation. Eight delay lines of mutually prime lengths are interconnected through an orthogonal Hadamard mixing matrix. On each sample, all delay outputs are read, mixed through the matrix, filtered, scaled by feedback, and written back. This creates a dense, colorless reverberation that decays naturally over time.
The Size parameter scales all delay lengths simultaneously, controlling the perceived room size. Feedback controls the decay time -- values near 1.0 produce long, sustained reverb tails, while values above 1.0 allow controlled buildup (kept stable by tanh soft clipping). Damping applies a one-pole lowpass filter inside each delay's feedback path, causing high frequencies to decay faster than low frequencies -- mimicking air absorption in real rooms.
Mod Rate and Mod Depth add sinusoidal modulation to each delay's read position (up to \(\pm 5\) samples), creating subtle pitch-shifting that decorrelates the delay lines and reduces metallic coloration. The eight LFO phases are spread evenly across one cycle for maximum decorrelation.
The Hadamard(8) matrix divided by \(\sqrt{8}\) is used as the mixing matrix. This is orthogonal and energy-preserving, ensuring that the network neither amplifies nor attenuates signal energy through the mixing stage alone.
File Locations
| Path | |
|---|---|
| Header | Sources/FolioDSP/include/FolioDSP/Algorithms/FeedbackNetwork.h |
| Implementation | Sources/FolioDSP/src/Algorithms/FeedbackNetwork.cpp |
| Tests | Tests/FolioDSPTests/FeedbackNetworkTests.swift |
| Bridge | Sources/FolioDSPBridge/src/FolioDSPBridge.mm (FeedbackNetworkBridge) |
Parameters
| Index | Name | Description | Min | Max | Default Min | Default Max | Default | Unit |
|---|---|---|---|---|---|---|---|---|
| 0 | Size | Delay length multiplier | 0.05 | 5.0 | 0.1 | 3.0 | 1.0 | |
| 1 | Feedback | Feedback amount (>1.0 = runaway) | 0.0 | 1.1 | 0.0 | 1.05 | 0.85 | |
| 2 | Damping | One-pole LP coefficient per delay | 0.0 | 0.99 | 0.0 | 0.95 | 0.4 | |
| 3 | Mod Rate | LFO modulation rate | 0.0 | 5.0 | 0.0 | 2.0 | 0.5 | Hz |
| 4 | Mod Depth | LFO modulation depth (\(\pm\)5 samples max) | 0.0 | 1.0 | 0.0 | 1.0 | 0.2 | |
| 5 | Mix | Dry/wet blend | 0.0 | 100.0 | 0.0 | 100.0 | 50.0 | % |
Processing Algorithm
The process() function executes these steps for each input sample:
1. Read from Delay Lines
Each of the 8 delay lines is read with LFO-modulated tap position:
where \(D_i\) are the base prime delay lengths and the LFO phases \(\phi_i\) are initialized spread evenly: \(\phi_i = i / 8\).
Base delay lengths (in samples, all prime): 1087, 1283, 1447, 1663, 1823, 2011, 2179, 2381.
2. Hadamard Mixing
The 8 delay readings are mixed through the Hadamard(8) matrix, normalized by \(1/\sqrt{8}\):
The Hadamard matrix \(H_8\) is orthogonal: \(H \cdot H^T = 8I\), so dividing by \(\sqrt{8}\) makes it energy-preserving.
3. Damping, Feedback, and Write
For each delay line, the mixed signal passes through a one-pole lowpass filter, is scaled by feedback, summed with input, soft-clipped, and written back:
The one-pole lowpass with coefficient \(d_{\text{damp}}\) causes high frequencies to decay faster. At \(d_{\text{damp}} = 0\), the filter is bypassed (full bandwidth). At \(d_{\text{damp}} = 0.99\), only very low frequencies survive.
4. Output Summation
The wet output sums all 8 delay readings, normalized by \(1/\sqrt{8}\):
5. Dry/Wet Mix
where \(\text{mix} = \text{mixPct} / 100\).
Core Equations
Approximate decay time (T60):
where \(\bar{D}\) is the average delay length in samples scaled by size.
Snapshot Fields
| Field | Type | Range | Unit | Description |
|---|---|---|---|---|
| Input Level | Float | 0--1 | Smoothed input amplitude | |
| Output Level | Float | 0--1 | Smoothed output amplitude | |
| Decay Time | Float | 0--10 | s | Estimated T60 decay time |
| Damping | Float | 0--1 | Current damping coefficient | |
| Drive | Float | 0--1.1 | Current feedback amount | |
| Delay Levels | Float[8] | 0--1 | Per-delay-line signal levels |
Implementation Notes
- Prime delay lengths are chosen to minimize common factors between lines, reducing the chance of resonant coloration. The specific primes (1087--2381) span roughly 25--54 ms at 44100 Hz, covering a natural room reflection range.
- Hadamard matrix is precomputed as a static
const float[8][8], with each entry already divided by \(\sqrt{8}\). This avoids per-sample division. - CircularBuffer<32768> per delay line provides up to ~743 ms of delay at 44100 Hz. With size multiplier up to 5.0, the maximum effective delay is \(2381 \times 5 = 11905\) samples (~270 ms), well within the buffer capacity.
- Tanh soft clipping in the feedback path prevents runaway when feedback exceeds 1.0, allowing controlled self-oscillation without hard clipping artifacts.
- Level tracking uses exponential smoothing with coefficient 0.01 for both overall and per-delay-line levels.
- T60 calculation in the snapshot uses the clamped feedback value (\(\leq 0.999\)) to avoid division by zero at \(f_b = 1.0\).
- All parameters use
std::atomic<float>for lock-free thread safety. - Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).
Equation Summary
y = Hadamard(8 * delay[t]) * fb