Ideas:
- Adjust gain curve to be more "exponential" for natural decay
- Add smoothing to crossover frequencies to prevent zipper noise
- Increase filter orders for steeper cutoffs
- Use fractional delays for smoother modulation (?)
import("stdfaust.lib");
// Early Reflections
earlyReflections = par(i, 4, de.delay(ma.SR, delayTime(i)) * gain(i))
with {
delayTime(i) = ba.take(i+1, (13, 17, 19, 23)) * 1.5;
gain(i) = ba.take(i+1, (0.7, 0.6, 0.5, 0.4));
};
FDN = si.bus(2) : (preDelay, preDelay) <: (earlyReflections, earlyReflections, MIMO_Network ~ MATRIX) :> par(i, 2, (+:applyFilters))
with {
// User-controllable parameters
decayMs = hslider("Decay[unit:ms][style:knob]", 1000, 100, 10000, 1);
preDelayMs = hslider("Pre-Delay[unit:ms][style:knob]", 20, 0, 200, 1);
modDepth = hslider("Modulation Depth[unit:%][style:knob]", 0.5, 0, 2, 0.01) : *(0.01);
modRate = hslider("Modulation Rate[unit:Hz][style:knob]", 0.5, 0.1, 2, 0.1);
//
// High crossover scales with decay time - longer reverbs need lower high crossover
highCrossover = min(12000, max(2000, 8000 - (decayMs - 1000) * 0.4));
// Low crossover is related to high crossover but stays within reasonable bounds
lowCrossover = min(500, max(100, highCrossover * 0.06));
// Decay ratios adapt based on decay time
// Longer reverbs typically have more low-end build-up, so we reduce low decay ratio
lowDecayRatio = max(0.4, min(1.2, 1.0 - (decayMs - 1000) * 0.0001));
// High frequencies decay faster in longer reverbs
highDecayRatio = max(0.3, min(1.0, 0.8 - (decayMs - 1000) * 0.0002));
// Pre-delay
maxPreDelay = 200;
preDelay = de.sdelay(ma.SR * maxPreDelay / 1000, 512, preDelayMs * ma.SR / 1000);
// Calculate decay factor based on milliseconds and frequency band
calcDecayFactor(delayLengthSamples, decayMs, ratio) = pow(0.001, delayLengthSamples / (decayMs * ratio * ma.SR / 1000.0));
// Matrix
MATRIX = ro.hadamard(16) : par(i, 16, *(1/4));
// Network
MIMO_Network(fb1, fb2, fb3, fb4, fb5, fb6, fb7, fb8, fb9, fb10, fb11, fb12, fb13, fb14, fb15, fb16, in1, in2) =
par(i, 16, DEL(i))
with {
baseDelays = (3797, 3541, 3323, 3109, 2939, 2801, 2693, 2593, 2503, 2423, 2351, 2287, 2237, 2179, 2131, 2083);
DEL(i) = de.fdelay(5000, modulatedDelay(i), fb(i) + input(i)) : multiband_decay
with {
delay = baseDelays : ba.selectn(16, i);
modulatedDelay(i) = delay + os.osc(modRate + 0.01*i) * delay * modDepth;
fb(i) = ba.selectn(16, i, fb1, fb2, fb3, fb4, fb5, fb6, fb7, fb8, fb9, fb10, fb11, fb12, fb13, fb14, fb15, fb16);
input(i) = select2(i < 2, 0, ba.selectn(2, i, in1, in2));
// Multi-band decay using automatic parameters
multiband_decay = _ <: (
fi.lowpass(2, lowCrossover) * calcDecayFactor(delay, decayMs, lowDecayRatio),
fi.bandpass(2, lowCrossover, highCrossover) * calcDecayFactor(delay, decayMs, 1.0),
fi.highpass(2, highCrossover) * calcDecayFactor(delay, decayMs, highDecayRatio)
) :> _;
};
};
// Apply filters to each channel (oh! I see colours, that's so trippy :P)
applyFilters = fi.lowpass(1, highCrossover * 1.5) : fi.highpass(1, lowCrossover * 0.5);
};
process = FDN;