«Basic Feedback Delay Network SynthDef» by michaeldzjap

on 18 Jul'19 18:40 in feedbackdelayreverbresonatorfeedback delay networkfdn

Example of a basic feedback delay network or FDN of order 8. Requires the MathLib quark. Use the scale argument to increase / decrease the delay time and the coef argument to control the decay time. Smaller scale values produce resonating sounds, larger scale values more reverb tail like sounds. Be careful with small scale values in combination with small coef values (hence the tanh).

For a theoretical reference see: https://ccrma.stanford.edu/~jos/cfdn/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Construct a circulant feedback matrix using the given eigenvalues
(
// 1 - The eigenvalues of the feedback coefficient matrix
d = [
	-1,
        Polar(1, -3pi / 4),
        Polar(1, -pi / 2),
        Polar(1, -pi / 6),
        1,
        Polar(1, pi / 6),
        Polar(1, pi / 2),
        Polar(1, 3pi / 4)
];

// 2 - Compute the feedback matrix from the given eigenvalues
n = d.size;
a = (Matrix.newIDFT(n) * Matrix.withFlatArray(n, 1, d)).real.flat / sqrt(n);
)

(
s.waitForBoot({
        var primePowerDelays = { arg delays;
                (delays collect: { |delay, i|
                        var prime = i.nthPrime;

		        prime ** ((log(delay) / log(prime)) + 0.5).floor;
	        }).asInteger / s.sampleRate;
        };

        var delayLengths = { arg n, dmin, dmax;
	        var nm1 = n - 1;
	        var d = dmin * ((dmax / dmin) ** ((0..nm1) / nm1));
		
	        (d * s.sampleRate).round(1.0).asInteger;
        };

	SynthDef(\sine, { arg out, freq = 440, amp = 0.5, trigFreq = 1;
		Out.ar(out, Decay.ar(Impulse.ar(trigFreq), 0.2, SinOsc.ar(freq, 0, amp)))
	}).add;

	SynthDef(\fdn, { arg in, out, scale = 1.0, coef = 0.5;
		var a, x, w, fb, delT;

		fb = LocalIn.ar(n);

		a = \a.kr(0 ! n);
		delT = \delT.kr(primePowerDelays.(delayLengths.(n, 0.03, 0.06)));
		x = In.ar(in);
		w = a.size collect: { arg i;
			DelayN.ar(a.rotate(i).inject(x, { |input, coef|
				coef * fb[i] + input
			}), 1, (delT[i] * scale - ControlDur.ir).fold(0.0, 1.0))
		};

		LocalOut.ar(LeakDC.ar(OnePole.ar(w, coef)));

		Out.ar(out, w.sum.tanh ! 2)
	}).add;

	{ s.scope(2) }.defer
});
)

(
s.makeBundle(nil, {
        x = Synth(\sine, [\out, 10, \trigFreq, 0.25, \amp, 0.1], 1, \addToHead);
        y = Synth(\fdn, [\in, 10, \out, 0, \a, a, \scale, 1, \coef, 0.5], 1, \addToTail);
});
)
raw 1854 chars (focus & ctrl+a+c to copy)
reception
comments
semiquaver user 20 Sep'19 18:48

very cool!

there's a grainy/clicky sound with louder inputs that I'd love to figure out how to avoid though... wonder where to fiddle...