Sunteți pe pagina 1din 76

Saxophone

Romain Michon
February 7, 2012
name Saxophone
description Nonlinear WaveGuide Saxophone, This class implements a hybrid digital waveguide instrument that can generate a variety of wind-like sounds. It has also been referred to as the blowed string model. The waveguide section is essentially that of a string, with one rigid and one lossy termination. The non-linear function is a reed table. The string can be blown at any point between the terminations, though just as with strings, it is impossible to excite the system at either end. If the excitation is placed at the string mid-point, the sound is that of a clarinet. At points closer to the bridge, the sound is closer to that of a saxophone. See Scavone (2002) for more details.
author Romain Michon
copyright Romain Michon (rmichon@ccrma.stanford.edu)
version 1.0
licence STK-4.3
reference https://ccrma.stanford.edu/ jos/pasp/Woodwinds.html
music.lib/name Music Library
music.lib/author GRAME
music.lib/copyright GRAME
music.lib/version 1.0
music.lib/license LGPL
math.lib/name Math Library
math.lib/author GRAME
math.lib/copyright GRAME
math.lib/version 1.0
math.lib/license LGPL
instrument.lib/name Faust-STK Tools Library
instrument.lib/author Romain Michon (rmichon@ccrma.stanford.edu)
instrument.lib/copyright Romain Michon
instrument.lib/version 1.0
instrument.lib/licence STK-4.3
lter.lib/name Faust Filter Library
lter.lib/author Julius O. Smith (jos at ccrma.stanford.edu)
lter.lib/copyright Julius O. Smith III
lter.lib/version 1.29
lter.lib/license STK-4.3
lter.lib/reference https://ccrma.stanford.edu/ jos/lters/
eect.lib/name Faust Audio Eect Library
eect.lib/author Julius O. Smith (jos at ccrma.stanford.edu)
eect.lib/copyright Julius O. Smith III
eect.lib/version 1.33
eect.lib/license STK-4.3
eect.lib/reference https://ccrma.stanford.edu/realsimple/fauststrings/
1
This document provides a mathematical description of the Faust program text
stored in the saxophony.dsp le. See the notice in Section 3 (page 15) for details.
1 Mathematical denition of process
The saxophony program evaluates the signal transformer denoted by process,
which is mathematically dened as follows:
1. Output signals y
i
for i [1, 2] such that
y
1
(t) = p
47
(t) r
16
(t) s
50
(t) + 0.37 (r
2
(t) + r
3
(t))
y
2
(t) = u
s14
(t) s
50
(t) r
67
(tp
84
(t)) + 0.37 (r
2
(t) r
3
(t))
2. Input signal (none)
3. User-interface input signals u
ni
for i [1, 17], u
b1
and u
s1
such that
BasicParameters/
freq (Hz) u
n2
(t) [ 20, 20000 ] (default value = 440)
gate u
b1
(t) 0, 1 (default value = 0)
gain u
n3
(t) [ 0, 1 ] (default value = 1)
EnvelopesandVibrato/EnvelopeParameters/
EnvelopeRelease (s) u
s4
(t) [ 0, 2 ] (default value = 0.01)
EnvelopeAttack (s) u
s12
(t) [ 0, 2 ] (default value = 0.05)
EnvelopesandVibrato/VibratoParameters/
VibratoFreq (Hz) u
s8
(t) [ 1, 15 ] (default value = 6)
VibratoGain u
s9
(t) [ 0, 1 ] (default value = 0.1)
PhysicalandNonlinearity/NonlinearFilterParameters/
ModulationFrequency (Hz) u
s3
(t) [ 20, 1000 ] (default value = 220)
ModulationType u
n1
(t) [ 0, 4 ] (default value = 0)
NonlinearityAttack (s) u
s5
(t) [ 0, 2 ] (default value = 0.1)
Nonlinearity u
s6
(t) [ 0, 1 ] (default value = 0)
PhysicalandNonlinearity/PhysicalParameters/
BlowPosition u
s7
(t) [ 0, 1 ] (default value = 0.5)
NoiseGain u
s10
(t) [ 0, 1 ] (default value = 0.05)
Pressure u
s11
(t) [ 0, 1 ] (default value = 1)
ReedStiness u
s13
(t) [ 0, 1 ] (default value = 0.3)
Reverb/
2
roomSize u
s1
(t) [ 0.01, 2 ] (default value = 0.72)
reverbGain u
s2
(t) [ 0, 1 ] (default value = 0.137)
Spat/
pan angle u
s14
(t) [ 0, 1 ] (default value = 0.6)
spatial width u
s15
(t) [ 0, 1 ] (default value = 0.5)
4. Intermediate signals p
i
for i [1, 111], s
i
for i [1, 50], r
i
for i [1, 76]
and v
1
such that
p
1
(t) = e
k
4
us1
(t)
p
2
(t) = p
1
(t)
2
p
3
(t) = 1 p
2
(t)
p
4
(t) = 1 k
6
p
2
(t)
p
5
(t) =

_
max
_
0,
p
4
(t)
2
p
3
(t)
2
1
_
p
6
(t) =
p
4
(t)
p
3
(t)
p
7
(t) = (p
6
(t) p
5
(t))
p
8
(t) =
_
e
k
11
us1
(t)
p
1
(t)
1
_
p
9
(t) = p
1
(t) ((1 + p
5
(t)) p
6
(t))
p
10
(t) = 0.001 u
s2
(t)
p
11
(t) = 0.001 u
s3
(t)
p
12
(t) = (u
n1
(t) ,= 4)
p
13
(t) = u
n2
(t) (u
n1
(t) 4)
p
14
(t) = (u
b1
(t) > 0)
p
15
(t) = (u
b1
(t) 0)
p
16
(t) =
_
1
1
100000
1
(us4
(t)0)+k
1
us4
(t)
_
p
17
(t) =
1
(u
s5
(t) 0) + k
1
u
s5
(t)
p
18
(t) = 0.001 u
s6
(t)
p
19
(t) =
_
k
1
u
n2
(t)
3
_
3
p
20
(t) = p
19
(t) (1 u
s7
(t))
p
21
(t) = int (p
20
(t))
p
22
(t) = int (1 int (p
21
(t) 4095))
p
23
(t) = (1 p
21
(t))
p
24
(t) = (p
23
(t) p
20
(t))
p
25
(t) = int (1 int (int (p
23
(t)) 4095))
p
26
(t) = (p
20
(t) p
21
(t))
p
27
(t) = (u
n1
(t) 3)
p
28
(t) = (u
n1
(t) 2)
p
29
(t) = (u
n1
(t) 0)
p
30
(t) =

2
(u
n1
(t) 1)
p
31
(t) = (u
n1
(t) < 3)
p
32
(t) = k
14
u
s8
(t)
p
33
(t) = 4.6566128752458 10
10
u
s10
(t)
p
34
(t) = u
s4
(t) u
s11
(t)
p
35
(t) =
_
1
1
100000
1
(p
34
(t)0)+k
1
p
34
(t)
_
p
36
(t) = u
s12
(t) u
s11
(t)
p
37
(t) =
1
(p
36
(t) 0) + k
1
p
36
(t)
p
38
(t) = (0.55 + 0.3 u
s11
(t))
p
39
(t) = p
19
(t) u
s7
(t)
p
40
(t) = 1 + p
39
(t)
p
41
(t) = int (p
40
(t))
p
42
(t) = int (p
41
(t) 4095)
p
43
(t) = (p
41
(t) p
39
(t))
p
44
(t) = int (int (1 p
41
(t)) 4095)
p
45
(t) = (p
40
(t) p
41
(t))
p
46
(t) = (0.1 + 0.4 u
s13
(t))
p
47
(t) = u
n3
(t) (1 u
s14
(t))
p
48
(t) = e
k
19
us1
(t)
p
49
(t) = p
48
(t)
2
4
p
50
(t) = 1 p
49
(t)
p
51
(t) = 1 k
6
p
49
(t)
p
52
(t) =

_
max
_
0,
p
51
(t)
2
p
50
(t)
2
1
_
p
53
(t) =
p
51
(t)
p
50
(t)
p
54
(t) = (p
53
(t) p
52
(t))
p
55
(t) =
_
e
k
20
us1
(t)
p
48
(t)
1
_
p
56
(t) = p
48
(t) ((1 + p
52
(t)) p
53
(t))
p
57
(t) = e
k
26
us1
(t)
p
58
(t) = p
57
(t)
2
p
59
(t) = 1 p
58
(t)
p
60
(t) = 1 k
6
p
58
(t)
p
61
(t) =

_
max
_
0,
p
60
(t)
2
p
59
(t)
2
1
_
p
62
(t) =
p
60
(t)
p
59
(t)
p
63
(t) = (p
62
(t) p
61
(t))
p
64
(t) =
_
e
k
27
us1
(t)
p
57
(t)
1
_
p
65
(t) = p
57
(t) ((1 + p
61
(t)) p
62
(t))
p
66
(t) = e
k
33
us1
(t)
p
67
(t) = p
66
(t)
2
p
68
(t) = 1 p
67
(t)
p
69
(t) = 1 k
6
p
67
(t)
p
70
(t) =

_
max
_
0,
p
69
(t)
2
p
68
(t)
2
1
_
p
71
(t) =
p
69
(t)
p
68
(t)
5
p
72
(t) = (p
71
(t) p
70
(t))
p
73
(t) =
_
e
k
34
us1
(t)
p
66
(t)
1
_
p
74
(t) = p
66
(t) ((1 + p
70
(t)) p
71
(t))
p
75
(t) = e
k
40
us1
(t)
p
76
(t) = p
75
(t)
2
p
77
(t) = 1 p
76
(t)
p
78
(t) = 1 k
6
p
76
(t)
p
79
(t) =

_
max
_
0,
p
78
(t)
2
p
77
(t)
2
1
_
p
80
(t) =
p
78
(t)
p
77
(t)
p
81
(t) = (p
80
(t) p
79
(t))
p
82
(t) =
_
e
k
41
us1
(t)
p
75
(t)
1
_
p
83
(t) = p
75
(t) ((1 + p
79
(t)) p
80
(t))
p
84
(t) = int
_
int
_
k
44

u
s15
(t)
u
n2
(t)
_
4095
_
p
85
(t) = e
k
48
us1
(t)
p
86
(t) = p
85
(t)
2
p
87
(t) = 1 p
86
(t)
p
88
(t) = 1 k
6
p
86
(t)
p
89
(t) =

_
max
_
0,
p
88
(t)
2
p
87
(t)
2
1
_
p
90
(t) =
p
88
(t)
p
87
(t)
p
91
(t) = (p
90
(t) p
89
(t))
p
92
(t) =
_
e
k
49
us1
(t)
p
85
(t)
1
_
p
93
(t) = p
85
(t) ((1 + p
89
(t)) p
90
(t))
6
p
94
(t) = e
k
55
us1
(t)
p
95
(t) = p
94
(t)
2
p
96
(t) = 1 p
95
(t)
p
97
(t) = 1 k
6
p
95
(t)
p
98
(t) =

_
max
_
0,
p
97
(t)
2
p
96
(t)
2
1
_
p
99
(t) =
p
97
(t)
p
96
(t)
p
100
(t) = (p
99
(t) p
98
(t))
p
101
(t) =
_
e
k
56
us1
(t)
p
94
(t)
1
_
p
102
(t) = p
94
(t) ((1 + p
98
(t)) p
99
(t))
p
103
(t) = e
k
62
us1
(t)
p
104
(t) = p
103
(t)
2
p
105
(t) = 1 p
104
(t)
p
106
(t) = 1 k
6
p
104
(t)
p
107
(t) =

_
max
_
0,
p
106
(t)
2
p
105
(t)
2
1
_
p
108
(t) =
p
106
(t)
p
105
(t)
p
109
(t) = (p
108
(t) p
107
(t))
p
110
(t) =
_
e
k
63
us1
(t)
p
103
(t)
1
_
p
111
(t) = p
103
(t) ((1 + p
107
(t)) p
108
(t))
7
s
1
(t) = k
14
(p
13
(t) + p
12
(t) r
19
(t)) + r
18
(t1)
s
2
(t) = p
15
(t) (r
21
(t1) > 0)
s
3
(t) = r
22
(t) r
21
(t)
s
4
(t) = s
3
(t) v
1
[int (65536 r
18
(t))]
s
5
(t) = sin (s
4
(t))
s
6
(t) = (p
26
(t) r
15
(tp
25
(t)) + p
24
(t) r
15
(tp
22
(t)))
s
7
(t) = (0 s
5
(t))
s
8
(t) = cos (s
4
(t))
s
9
(t) = (s
6
(t) s
8
(t) + s
7
(t) r
24
(t1))
s
10
(t) = (s
8
(t) s
9
(t) + s
7
(t) r
25
(t1))
s
11
(t) = (s
8
(t) s
10
(t) + s
7
(t) r
26
(t1))
s
12
(t) = (s
8
(t) s
11
(t) + s
7
(t) r
27
(t1))
s
13
(t) = (s
8
(t) s
12
(t) + s
7
(t) r
28
(t1))
s
14
(t) = s
3
(t)
_
p
30
(t) (s
6
(t) + s
6
(t1)) + p
29
(t) s
6
(t) + p
28
(t) s
6
(t)
2
_
s
15
(t) = sin (s
14
(t))
s
16
(t) = (0 s
15
(t))
s
17
(t) = cos (s
14
(t))
s
18
(t) = (s
6
(t) s
17
(t) + s
16
(t) r
30
(t1))
s
19
(t) = (s
17
(t) s
18
(t) + s
16
(t) r
31
(t1))
s
20
(t) = (s
17
(t) s
19
(t) + s
16
(t) r
32
(t1))
s
21
(t) = (s
17
(t) s
20
(t) + s
16
(t) r
33
(t1))
s
22
(t) = (s
17
(t) s
21
(t) + s
16
(t) r
34
(t1))
s
23
(t) = 0 0.95 (p
31
(t) ((1 r
22
(t)) s
6
(t)
+ r
22
(t) (s
17
(t) r
30
(t1) + s
6
(t) s
15
(t)))
+ p
27
(t) (s
8
(t) r
24
(t1) + s
6
(t) s
5
(t)))
s
24
(t) = (s
23
(t) + s
23
(t1))
s
25
(t) = 0.5 s
24
(t)
s
26
(t) = p
32
(t) + r
38
(t1)
s
27
(t) = p
15
(t) (r
41
(t1) > 0)
s
28
(t) =p
38
(t) r
41
(t) (1+p
33
(t) r
39
(t)) (1+u
s9
(t) v
1
[int (65536 r
38
(t))])
s
29
(t) = 0.5 (p
45
(t) s
24
(tp
44
(t)) + p
43
(t) s
24
(tp
42
(t)))
s
30
(t) = ((s
29
(t) + s
28
(t)) s
25
(t))
8
s
31
(t) = 0.7 + p
46
(t) s
30
(t)
s
32
(t) = s
31
(t) (s
31
(t) 1) + (s
31
(t) > 1)
s
33
(t) = 0.3 r
42
(tk
15
)
s
34
(t) = (s
33
(t) + r
13
(tk
13
)) 0.6 r
9
(t1)
s
35
(t) = (s
33
(t) + r
48
(tk
22
)) 0.6 r
44
(t1)
s
36
(t) = r
45
(t) + r
10
(t)
s
37
(t) = r
54
(tk
29
) (s
33
(t) + 0.6 r
50
(t1))
s
38
(t) = r
60
(tk
36
) (s
33
(t) + 0.6 r
56
(t1))
s
39
(t) = r
57
(t) + r
51
(t) + s
36
(t)
s
40
(t) = 0.3 r
68
(tk
15
)
s
41
(t) = s
40
(t) + r
66
(tk
43
) + 0.6 r
62
(t1)
s
42
(t) = s
40
(t) + r
74
(tk
51
) + 0.6 r
70
(t1)
s
43
(t) = (r
80
(tk
58
) + 0.6 r
76
(t1)) s
40
(t)
s
44
(t) = (r
86
(tk
65
) + 0.6 r
82
(t1)) s
40
(t)
s
45
(t) = r
51
(t) + r
57
(t)
s
46
(t) = r
45
(t) + r
51
(t)
s
47
(t) = r
10
(t) + r
57
(t)
s
48
(t) = r
45
(t) + r
57
(t)
s
49
(t) = r
10
(t) + r
51
(t)
s
50
(t) = (1 r
14
(t))
r
12
(t) = k
10
(r
5
(t1) + r
5
(t2)) + k
9
r
12
(t1)
r
11
(t) = p
9
(t) (r
5
(t1) + p
8
(t) r
12
(t)) + p
7
(t) r
11
(t1)
r
13
(t) = 1 10
20
+ 0.353553390593274 r
11
(t)
r
14
(t) = p
10
(t) + 0.999 r
14
(t1)
r
17
(t) = 1 r
17
(t1)
r
19
(t) = p
11
(t) + 0.999 r
19
(t1)
r
18
(t) = s
1
(t) s
1
(t)|
r
20
(t) = p
14
(t) (r
20
(t1) (r
21
(t1) 1))
r
21
(t) =
_
(s
2
(t) 0)
_
r
21
(t1) 1 10
06
__
(p
17
(t) (r
20
(t1) 0)
p
14
(t) (r
21
(t1) < 1) + r
21
(t1) (1 p
16
(t) s
2
(t)))
r
22
(t) = p
18
(t) + 0.999 r
22
(t1)
9
r
29
(t) = s
8
(t) s
13
(t) + s
7
(t) r
29
(t1)
r
28
(t) = s
8
(t) r
29
(t1) + s
5
(t) s
13
(t)
r
27
(t) = s
8
(t) r
28
(t1) + s
5
(t) s
12
(t)
r
26
(t) = s
8
(t) r
27
(t1) + s
5
(t) s
11
(t)
r
25
(t) = s
8
(t) r
26
(t1) + s
5
(t) s
10
(t)
r
24
(t) = s
8
(t) r
25
(t1) + s
5
(t) s
9
(t)
r
35
(t) = s
17
(t) s
22
(t) + s
16
(t) r
35
(t1)
r
34
(t) = s
17
(t) r
35
(t1) + s
15
(t) s
22
(t)
r
33
(t) = s
17
(t) r
34
(t1) + s
15
(t) s
21
(t)
r
32
(t) = s
17
(t) r
33
(t1) + s
15
(t) s
20
(t)
r
31
(t) = s
17
(t) r
32
(t1) + s
15
(t) s
19
(t)
r
30
(t) = s
17
(t) r
31
(t1) + s
15
(t) s
18
(t)
r
38
(t) = s
26
(t) s
26
(t)|
r
39
(t) = 12345 1103515245 r
39
(t1)
r
40
(t) = p
14
(t) (r
40
(t1) (r
41
(t1) 1))
r
41
(t) =
_
(s
27
(t) 0)
_
r
41
(t1) 1 10
06
__
(p
37
(t) (r
40
(t1) 0)
p
14
(t) (r
41
(t1) < 1) + r
41
(t1) (1 p
35
(t) s
27
(t)))
r
15
(t) = s
28
(t) (s
25
(t) + s
30
(t) (s
32
(t) (s
32
(t) 1) (s
32
(t) < 1)))
r
16
(t) = s
25
(t) s
29
(t)
r
42
(t) = p
47
(t) r
16
(t) r
14
(t)
r
9
(t) = s
34
(tk
16
)
r
10
(t) = 0.6 s
34
(t)
r
47
(t) = k
10
(r
1
(t1) + r
1
(t2)) + k
9
r
47
(t1)
r
46
(t) = p
56
(t) (r
1
(t1) + p
55
(t) r
47
(t)) + p
54
(t) r
46
(t1)
r
48
(t) = 1 10
20
+ 0.353553390593274 r
46
(t)
r
44
(t) = s
35
(tk
23
)
r
45
(t) = 0.6 s
35
(t)
r
53
(t) = k
10
(r
3
(t1) + r
3
(t2)) + k
9
r
53
(t1)
r
52
(t) = p
65
(t) (r
3
(t1) + p
64
(t) r
53
(t)) + p
63
(t) r
52
(t1)
r
54
(t) = 1 10
20
+ 0.353553390593274 r
52
(t)
r
50
(t) = s
37
(tk
30
)
r
51
(t) = 0.6 s
37
(t)
r
59
(t) = k
9
r
59
(t1) + k
10
(r
7
(t1) + r
7
(t2))
10
r
58
(t) = p
74
(t) (r
7
(t1) + p
73
(t) r
59
(t)) + p
72
(t) r
58
(t1)
r
60
(t) = 1 10
20
+ 0.353553390593274 r
58
(t)
r
56
(t) = s
38
(tk
37
)
r
57
(t) = 0.6 s
38
(t)
r
65
(t) = k
10
(r
2
(t1) + r
2
(t2)) + k
9
r
65
(t1)
r
64
(t) = p
83
(t) (r
2
(t1) + p
82
(t) r
65
(t)) + p
81
(t) r
64
(t1)
r
66
(t) = 1 10
20
+ 0.353553390593274 r
64
(t)
r
67
(t) = u
n3
(t) r
16
(t)
r
68
(t) = u
s14
(t) r
14
(t) r
67
(tp
84
(t))
r
62
(t) = s
41
(tk
45
)
r
63
(t) = 0 0.6 s
41
(t)
r
73
(t) = k
10
(r
6
(t1) + r
6
(t2)) + k
9
r
73
(t1)
r
72
(t) = p
93
(t) (r
6
(t1) + p
92
(t) r
73
(t)) + p
91
(t) r
72
(t1)
r
74
(t) = 1 10
20
+ 0.353553390593274 r
72
(t)
r
70
(t) = s
42
(tk
52
)
r
71
(t) = 0 0.6 s
42
(t)
r
79
(t) = k
10
(r
4
(t1) + r
4
(t2)) + k
9
r
79
(t1)
r
78
(t) = p
102
(t) (r
4
(t1) + p
101
(t) r
79
(t)) + p
100
(t) r
78
(t1)
r
80
(t) = 1 10
20
+ 0.353553390593274 r
78
(t)
r
76
(t) = s
43
(tk
59
)
r
77
(t) = 0 0.6 s
43
(t)
r
85
(t) = k
10
(r
8
(t1) + r
8
(t2)) + k
9
r
85
(t1)
r
84
(t) = p
111
(t) (r
8
(t1) + p
110
(t) r
85
(t)) + p
109
(t) r
84
(t1)
r
86
(t) = 1 10
20
+ 0.353553390593274 r
84
(t)
r
82
(t) = s
44
(tk
66
)
r
83
(t) = 0 0.6 s
44
(t)
r
1
(t) = r
44
(t1) +r
9
(t1) +r
50
(t1) +r
56
(t1) +r
62
(t1) +r
70
(t1)
+ r
76
(t1) + r
82
(t1) + r
83
(t) + r
77
(t) + r
71
(t) + r
63
(t) + s
39
(t)
r
2
(t) = 0 ((r
62
(t1) +r
70
(t1) +r
76
(t1) +r
82
(t1) +r
83
(t) +r
77
(t)
+ r
63
(t) + r
71
(t))
(r
44
(t1) + r
9
(t1) + r
50
(t1) + r
56
(t1) + s
39
(t)))
11
r
3
(t) = 0 ((r
50
(t1) +r
56
(t1) +r
76
(t1) +r
82
(t1) +r
83
(t) +r
77
(t)
+ s
45
(t)) (r
44
(t1) + r
9
(t1) + r
62
(t1) + r
70
(t1) + r
71
(t)
+ r
63
(t) + s
36
(t)))
r
4
(t) = 0 ((r
50
(t1) +r
56
(t1) +r
62
(t1) +r
70
(t1) +r
71
(t) +r
63
(t)
+ s
45
(t)) (r
44
(t1) + r
9
(t1) + r
76
(t1) + r
82
(t1) + r
83
(t)
+ r
77
(t) + s
36
(t)))
r
5
(t) = 0
((r
9
(t1)+r
56
(t1)+r
70
(t1)+r
82
(t1)+r
83
(t)+r
71
(t)+s
47
(t))
(r
44
(t1) + r
50
(t1) + r
62
(t1) + r
76
(t1) + r
77
(t) + r
63
(t)
+ s
46
(t)))
r
6
(t) = 0
((r
9
(t1)+r
56
(t1)+r
62
(t1)+r
76
(t1)+r
77
(t)+r
63
(t)+s
47
(t))
(r
44
(t1) + r
50
(t1) + r
70
(t1) + r
82
(t1) + r
83
(t) + r
71
(t)
+ s
46
(t)))
r
7
(t) = 0
((r
9
(t1)+r
50
(t1)+r
70
(t1)+r
76
(t1)+r
77
(t)+r
71
(t)+s
49
(t))
(r
44
(t1) + r
56
(t1) + r
62
(t1) + r
82
(t1) + r
83
(t) + r
63
(t)
+ s
48
(t)))
r
8
(t) = 0
((r
9
(t1)+r
50
(t1)+r
62
(t1)+r
82
(t1)+r
83
(t)+r
63
(t)+s
49
(t))
(r
44
(t1) + r
56
(t1) + r
70
(t1) + r
76
(t1) + r
77
(t) + r
71
(t)
+ s
48
(t)))
v
1
[t] = sin
_
9.58737992428526 10
05
(r
17
(t) 1)
_
, when t [0, 65535]
5. Constants k
i
for i [1, 66] such that
k
1
= min (192000, max (1, f
S
))
k
2
= 0.5 + 0.174713 k
1
|
k
3
=
0 6.90775527898214 k
2
k
1
k
4
= 0.5 k
3
k
5
= k
1
k
6
= cos
_
37699.1118430775
k
5
_
k
7
=
1
tan
_
628.318530717959
k1
_
12
k
8
= 1 + k
7
k
9
=
_
0
1 k
7
k
8
_
k
10
=
1
k
8
k
11
= 0.333333333333333 k
3
k
12
= 0.5 + 0.022904 k
1
|
k
13
= int (int (k
2
k
12
) 8191)
k
14
=
1
k
5
k
15
= int (int (0.02 k
1
) 8191)
k
16
= int (int (k
12
1) 2047)
k
17
= 0.5 + 0.153129 k
1
|
k
18
=
0 6.90775527898214 k
17
k
1
k
19
= 0.5 k
18
k
20
= 0.333333333333333 k
18
k
21
= 0.5 + 0.020346 k
1
|
k
22
= int (int (k
17
k
21
) 8191)
k
23
= int (int (k
21
1) 1023)
k
24
= 0.5 + 0.127837 k
1
|
k
25
=
0 6.90775527898214 k
24
k
1
k
26
= 0.5 k
25
k
27
= 0.333333333333333 k
25
k
28
= 0.5 + 0.031604 k
1
|
k
29
= int (int (k
24
k
28
) 8191)
k
30
= int (int (k
28
1) 2047)
k
31
= 0.5 + 0.125 k
1
|
k
32
=
0 6.90775527898214 k
31
k
1
k
33
= 0.5 k
32
k
34
= 0.333333333333333 k
32
k
35
= 0.5 + 0.013458 k
1
|
k
36
= int (int (k
31
k
35
) 8191)
13
k
37
= int (int (k
35
1) 1023)
k
38
= 0.5 + 0.210389 k
1
|
k
39
=
0 6.90775527898214 k
38
k
1
k
40
= 0.5 k
39
k
41
= 0.333333333333333 k
39
k
42
= 0.5 + 0.024421 k
1
|
k
43
= int (int (k
38
k
42
) 16383)
k
44
= 0.5 k
1
k
45
= int (int (k
42
1) 2047)
k
46
= 0.5 + 0.192303 k
1
|
k
47
=
0 6.90775527898214 k
46
k
1
k
48
= 0.5 k
47
k
49
= 0.333333333333333 k
47
k
50
= 0.5 + 0.029291 k
1
|
k
51
= int (int (k
46
k
50
) 8191)
k
52
= int (int (k
50
1) 2047)
k
53
= 0.5 + 0.256891 k
1
|
k
54
=
0 6.90775527898214 k
53
k
1
k
55
= 0.5 k
54
k
56
= 0.333333333333333 k
54
k
57
= 0.5 + 0.027333 k
1
|
k
58
= int (int (k
53
k
57
) 16383)
k
59
= int (int (k
57
1) 2047)
k
60
= 0.5 + 0.219991 k
1
|
k
61
=
0 6.90775527898214 k
60
k
1
k
62
= 0.5 k
61
k
63
= 0.333333333333333 k
61
k
64
= 0.5 + 0.019123 k
1
|
k
65
= int (int (k
60
k
64
) 16383)
k
66
= int (int (k
64
1) 1023)
14
2 Block diagram of process
The block diagram of process is shown on Figure 1 (page 15).
bodyFilter
breathPressure
instrumentBody
delay1 NLFM
nentry(h:Basic_Parameters/gain, 1, 0, 1, 0.01)
gain
* stereo instrReverb
process
Figure 1: Block diagram of process
3 Notice
This document was generated using Faust version 0.9.46 on February 07,
2012.
The value of a Faust program is the result of applying the signal trans-
former denoted by the expression to which the process identier is bound
to input signals, running at the f
S
sampling frequency.
Faust (Functional Audio Stream) is a functional programming language
designed for synchronous real-time signal processing and synthesis appli-
cations. A Faust program is a set of bindings of identiers to expressions
that denote signal transformers. A signal s in S is a function mapping
1
times t Z to values s(t) R, while a signal transformer is a function
from S
n
to S
m
, where n, m N. See the Faust manual for additional
information (http://faust.grame.fr).
Every mathematical formula derived from a Faust expression is assumed,
in this document, to having been normalized (in an implementation-depen-
dent manner) by the Faust compiler.
A block diagram is a graphical representation of the Faust binding of an
identier I to an expression E; each graph is put in a box labeled by I.
Subexpressions of E are recursively displayed as long as the whole picture
ts in one page.
x R,
int(x) =
_
_
_
x| if x > 0
,x| if x < 0
0 if x = 0
.
1
Faust assumes that s S, t Z, s(t) = 0 when t < 0.
15
This document uses the following integer operations:
operation name semantics
i j integer addition normalize(i + j), in Z
i j integer substraction normalize(i j), in Z
i j integer multiplication normalize(i j), in Z
Integer operations in Faust are inspired by the semantics of operations
on the n-bit twos complement representation of integer numbers; they
are internal composition laws on the subset [ 2
n1
, 2
n1
1 ] of Z, with
n = 32. For any integer binary operation on Z, the operation is
dened as: i j = normalize(i j), with
normalize(i) = i N sign(i)
_
[i[ + N/2 + (sign(i)1)/2
N
_
,
where N = 2
n
and sign(i) = 0 if i = 0 and i/[i[ otherwise. Unary integer
operations are dened likewise.
The saxophony-mdoc/ directory may also include the following subdirec-
tories:
cpp/ for Faust compiled code;
pdf/ which contains this document;
src/ for all Faust sources used (even libraries);
svg/ for block diagrams, encoded using the Scalable Vector Graphics
format (http://www.w3.org/Graphics/SVG/);
tex/ for the L
A
T
E
X source of this document.
4 Faust code listings
This section provides the listings of the Faust code used to generate this docu-
ment, including dependencies.
Listing 1: saxophony.dsp

1 declare name "Saxophone";
2 declare description "Nonlinear WaveGuide Saxophone";
3 declare author "Romain Michon";
4 declare copyright "Romain Michon (rmichon@ccrma.stanford.edu)";
5 declare version "1.0";
6 declare licence "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license);
7 declare description "This class implements a hybrid digital waveguide instrument that can
generate a variety of wind-like sounds. It has also been referred to as the blowed
string model. The waveguide section is essentially that of a string, with one rigid and
one lossy termination. The non-linear function is a reed table. The string can be
blown at any point between the terminations, though just as with strings, it is
impossible to excite the system at either end. If the excitation is placed at the
string mid-point, the sound is that of a clarinet. At points closer to the bridge, the
sound is closer to that of a saxophone. See Scavone (2002) for more details.";
16
8 declare reference "https://ccrma.stanford.edu/~jos/pasp/Woodwinds.html";
9
10 import("music.lib");
11 import("instrument.lib");
12
13 //==================== GUI SPECIFICATION ================
14
15 freq = nentry("h:Basic_Parameters/freq [1][unit:Hz] [tooltip:Tone frequency]"
,440,20,20000,1);
16 gain = nentry("h:Basic_Parameters/gain [1][tooltip:Gain (value between 0 and 1)]"
,1,0,1,0.01);
17 gate = button("h:Basic_Parameters/gate [1][tooltip:noteOn = 1, noteOff = 0]");
18
19 pressure = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Pressure
20 [2][tooltip:Breath pressure (a value between 0 and 1)]",1,0,1,0.01);
21 reedStiffness = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Reed_Stiffness
22 [2][tooltip:A value between 0 and 1]",0.3,0,1,0.01);
23 blowPosition = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Blow_Position
24 [2][tooltip:A value between 0 and 1]",0.5,0,1,0.01);
25 noiseGain = hslider("h:Physical_and_Nonlinearity/v:Physical_Parameters/Noise_Gain"
,0.05,0,1,0.01);
26
27 typeModulation = nentry("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/
Modulation_Type
28 [3][tooltip: 0=theta is modulated by the incoming signal; 1=theta is modulated by the
averaged incoming signal;
29 2=theta is modulated by the squared incoming signal; 3=theta is modulated by a sine wave of
frequency freqMod;
30 4=theta is modulated by a sine wave of frequency freq;]",0,0,4,1);
31 nonLinearity = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/
Nonlinearity
32 [3][tooltip:Nonlinearity factor (value between 0 and 1)]",0,0,1,0.01);
33 frequencyMod = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/
Modulation_Frequency
34 [3][unit:Hz][tooltip:Frequency of the sine wave for the modulation of theta (works if
Modulation Type=3)]",220,20,1000,0.1);
35 nonLinAttack = hslider("h:Physical_and_Nonlinearity/v:Nonlinear_Filter_Parameters/
Nonlinearity_Attack
36 [3][unit:s][Attack duration of the nonlinearity]",0.1,0,2,0.01);
37
38 vibratoFreq = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Freq
39 [4][unit:Hz]",6,1,15,0.1);
40 vibratoGain = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Gain
41 [4][tooltip:A value between 0 and 1]",0.1,0,1,0.01);
42 vibratoBegin = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Begin
43 [4][unit:s][tooltip:Vibrato silence duration before attack]",0.05,0,2,0.01);
44 vibratoAttack = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Attack
45 [4][unit:s][tooltip:Vibrato attack duration]",0.3,0,2,0.01);
46 vibratoRelease = hslider("h:Envelopes_and_Vibrato/v:Vibrato_Parameters/Vibrato_Release
47 [4][unit:s][tooltip:Vibrato release duration]",0.1,0,2,0.01);
48
49 envelopeAttack = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Attack
50 [5][unit:s][tooltip:Envelope attack duration]",0.05,0,2,0.01);
51 envelopeRelease = hslider("h:Envelopes_and_Vibrato/v:Envelope_Parameters/Envelope_Release
52 [5][unit:s][tooltip:Envelope release duration]",0.01,0,2,0.01);
53
54 //==================== SIGNAL PROCESSING ================
55
56 //----------------------- Nonlinear filter ----------------------------
57 //nonlinearities are created by the nonlinear passive allpass ladder filter declared in
filter.lib
58
59 //nonlinear filter order
60 nlfOrder = 6;
61
62 //attack - sustain - release envelope for nonlinearity (declared in instrument.lib)
63 envelopeMod = asr(nonLinAttack,100,envelopeRelease,gate);
64
17
65 //nonLinearModultor is declared in instrument.lib, it adapts allpassnn from filter.lib
66 //for using it with waveguide instruments
67 NLFM = nonLinearModulator((nonLinearity : smooth(0.999)),envelopeMod,freq,
68 typeModulation,(frequencyMod : smooth(0.999)),nlfOrder);
69
70 //----------------------- Synthesis parameters computing and functions declaration
----------------------------
71
72 //stereoizer is declared in instrument.lib and implement a stereo spacialisation in function
of
73 //the frequency period in number of samples
74 stereo = stereoizer(SR/freq);
75
76 //reed table parameters
77 reedTableOffset = 0.7;
78 reedTableSlope = 0.1 + (0.4*reedStiffness);
79
80 //the reed function is declared in instrument.lib
81 reedTable = reed(reedTableOffset,reedTableSlope);
82
83 //Delay lines length in number of samples
84 fdel1 = (1-blowPosition) * (SR/freq - 3);
85 fdel2 = (SR/freq - 3)*blowPosition +1 ;
86
87 //Delay lines
88 delay1 = fdelay(4096,fdel1);
89 delay2 = fdelay(4096,fdel2);
90
91 //Breath pressure is controlled by an attack / sustain / release envelope (asr is declared in
instrument.lib)
92 envelope = (0.55+pressure*0.3)*asr(pressure*envelopeAttack,100,pressure*envelopeRelease,gate
);
93 breath = envelope + envelope*noiseGain*noise;
94
95 //envVibrato is decalred in instrument.lib
96 vibrato = vibratoGain*envVibrato(vibratoBegin,vibratoAttack,100,vibratoRelease,gate)*osc(
vibratoFreq);
97 breathPressure = breath + breath*vibratoGain*osc(vibratoFreq);
98
99 //Body filter is a one zero filter (declared in instrument.lib)
100 bodyFilter = *(gain) : oneZero1(b0,b1)
101 with{
102 gain = -0.95;
103 b0 = 0.5;
104 b1 = 0.5;
105 };
106
107 instrumentBody(delay1FeedBack,breathP) = delay1FeedBack <: -(delay2) <:
108 ((breathP - _ <: breathP - _*reedTable) - delay1FeedBack),_;
109
110 process =
111 (bodyFilter,breathPressure : instrumentBody) ~
112 (delay1 : NLFM) : !,
113 //Scaling Output and stereo
114 *(gain) : stereo : instrReverb;

Listing 2: music.lib

1 /************************************************************************
2 ************************************************************************
3 FAUST library file
4 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
18
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 ************************************************************************
21 ************************************************************************/
22
23 declare name "Music Library";
24 declare author "GRAME";
25 declare copyright "GRAME";
26 declare version "1.0";
27 declare license "LGPL";
28
29 import("math.lib");
30
31 //-----------------------------------------------
32 // DELAY LINE
33 //-----------------------------------------------
34 frac(n) = n-int(n);
35 index(n) = &(n-1) ~ +(1); // n = 2**i
36 //delay(n,d,x) = rwtable(n, 0.0, index(n), x, (index(n)-int(d)) & (n-1));
37 delay(n,d,x) = x@(int(d)&(n-1));
38 fdelay(n,d,x) = delay(n,int(d),x)*(1 - frac(d)) + delay(n,int(d)+1,x)*frac(d);
39
40
41 delay1s(d) = delay(65536,d);
42 delay2s(d) = delay(131072,d);
43 delay5s(d) = delay(262144,d);
44 delay10s(d) = delay(524288,d);
45 delay21s(d) = delay(1048576,d);
46 delay43s(d) = delay(2097152,d);
47
48 fdelay1s(d) = fdelay(65536,d);
49 fdelay2s(d) = fdelay(131072,d);
50 fdelay5s(d) = fdelay(262144,d);
51 fdelay10s(d) = fdelay(524288,d);
52 fdelay21s(d) = fdelay(1048576,d);
53 fdelay43s(d) = fdelay(2097152,d);
54
55 millisec = SR/1000.0;
56
57 time1s = hslider("time", 0, 0, 1000, 0.1)*millisec;
58 time2s = hslider("time", 0, 0, 2000, 0.1)*millisec;
59 time5s = hslider("time", 0, 0, 5000, 0.1)*millisec;
60 time10s = hslider("time", 0, 0, 10000, 0.1)*millisec;
61 time21s = hslider("time", 0, 0, 21000, 0.1)*millisec;
62 time43s = hslider("time", 0, 0, 43000, 0.1)*millisec;
63
64
65 echo1s = vgroup("echo 1000", +~(delay(65536, int(hslider("millisecond", 0, 0, 1000, 0.10)*
millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
66 echo2s = vgroup("echo 2000", +~(delay(131072, int(hslider("millisecond", 0, 0, 2000, 0.25)*
millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
67 echo5s = vgroup("echo 5000", +~(delay(262144, int(hslider("millisecond", 0, 0, 5000, 0.50)*
millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
68 echo10s = vgroup("echo 10000", +~(delay(524288, int(hslider("millisecond", 0, 0, 10000,
1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
69 echo21s = vgroup("echo 21000", +~(delay(1048576, int(hslider("millisecond", 0, 0, 21000,
1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
19
70 echo43s = vgroup("echo 43000", +~(delay(2097152, int(hslider("millisecond", 0, 0, 43000,
1.00)*millisec)-1) * (hslider("feedback", 0, 0, 100, 0.1)/100.0)));
71
72
73 //--------------------------sdelay(N,it,dt)----------------------------
74 // s(mooth)delay : a mono delay that doesnt click and doesnt
75 // transpose when the delay time is changed. It takes 4 input signals
76 // and produces a delayed output signal
77 //
78 // USAGE : ... : sdelay(N,it,dt) : ...
79 //
80 // Where :
81 // <N> = maximal delay in samples (must be a constant power of 2, for example 65536)
82 // <it> = interpolation time (in samples) for example 1024
83 // <dt> = delay time (in samples)
84 // < > = input signal we want to delay
85 //--------------------------------------------------------------------------
86
87 sdelay(N, it, dt) = ctrl(it,dt),_ : ddi(N)
88
89 with {
90
91 //---------------------------ddi(N,i,d0,d1)-------------------------------
92 // DDI (Double Delay with Interpolation) : the input signal is sent to two
93 // delay lines. The outputs of these delay lines are crossfaded with
94 // an interpolation stage. By acting on this interpolation value one
95 // can move smoothly from one delay to another. When <i> is 0 we can
96 // freely change the delay time <d1> of line 1, when it is 1 we can freely change
97 // the delay time <d0> of line 0.
98 //
99 // <N> = maximal delay in samples (must be a power of 2, for example 65536)
100 // <i> = interpolation value between 0 and 1 used to crossfade the outputs of the
101 // two delay lines (0.0: first delay line, 1.0: second delay line)
102 // <d0> = delay time of delay line 0 in samples between 0 and <N>-1
103 // <d1> = delay time of delay line 1 in samples between 0 and <N>-1
104 // < > = the input signal we want to delay
105 //-------------------------------------------------------------------------
106 ddi(N, i, d0, d1) = _ <: delay(N,d0), delay(N,d1) : interpolate(i);
107
108
109 //----------------------------ctrl(it,dt)------------------------------------
110 // Control logic for a Double Delay with Interpolation according to two
111 //
112 // USAGE : ctrl(it,dt)
113 // where :
114 // <it> an interpolation time (in samples, for example 256)
115 // <dt> a delay time (in samples)
116 //
117 // ctrl produces 3 outputs : an interpolation value <i> and two delay
118 // times <d0> and <d1>. These signals are used to control a ddi (Double Delay with
Interpolation).
119 // The principle is to detect changes in the input delay time dt, then to
120 // change the delay time of the delay line currently unused and then by a
121 // smooth crossfade to remove the first delay line and activate the second one.
122 //
123 // The control logic has an internal state controlled by 4 elements
124 // <v> : the interpolation variation (0, 1/it, -1/it)
125 // <i> : the interpolation value (between 0 and 1)
126 // <d0>: the delay time of line 0
127 // <d1>: the delay time of line 1
128 //
129 // Please note that the last stage (!,_,_,_) cut <v> because it is only
130 // used internally.
131 //-------------------------------------------------------------------------
132 ctrl(it, dt) = \(v,ip,d0,d1).( (nv, nip, nd0, nd1)
133 with {
134
135 // interpolation variation
20
136 nv = if (v!=0.0, // if variation we are interpolating
137 if( (ip>0.0) & (ip<1.0), v , 0), // should we continue or not ?
138 if ((ip==0.0) & (dt!=d0), 1.0/it, // if true xfade from dl0 to dl1
139 if ((ip==1.0) & (dt!=d1), -1.0/it, // if true xfade from dl1 to dl0
140 0))); // nothing to change
141 // interpolation value
142 nip = ip+nv : min(1.0) : max(0.0);
143
144 // update delay time of line 0 if needed
145 nd0 = if ((ip >= 1.0) & (d1!=dt), dt, d0);
146
147 // update delay time of line 0 if needed
148 nd1 = if ((ip <= 0.0) & (d0!=dt), dt, d1);
149
150 } ) ~ (_,_,_,_) : (!,_,_,_);
151 };
152
153
154 //-----------------------------------------------
155 // Tempo, beats and pulses
156 //-----------------------------------------------
157
158 tempo(t) = (60*SR)/t; // tempo(t) -> samples
159
160 period(p) = %(int(p))~+(1); // signal en dent de scie de periode p
161 pulse(t) = period(t)==0; // pulse (10000...) de periode p
162 pulsen(n,t) = period(t)<n; // pulse (1110000...) de taille n et de periode p
163 beat(t) = pulse(tempo(t)); // pulse au tempo t
164
165
166 //-----------------------------------------------
167 // conversions between db and linear values
168 //-----------------------------------------------
169
170 db2linear(x) = pow(10, x/20.0);
171 linear2db(x) = 20*log10(x);
172
173
174 //===============================================
175 // Random and Noise generators
176 //===============================================
177
178
179 //-----------------------------------------------
180 // noise : Noise generator
181 //-----------------------------------------------
182
183 random = +(12345) ~ *(1103515245);
184 RANDMAX = 2147483647.0;
185
186 noise = random / RANDMAX;
187
188
189 //-----------------------------------------------
190 // Generates multiple decorrelated random numbers
191 // in parallel. Expects n>0.
192 //-----------------------------------------------
193
194 multirandom(n) = randomize(n) ~_
195 with {
196 randomize (1) = +(12345) : *(1103515245);
197 randomize (n) = randomize(1) <: randomize(n-1),_;
198 };
199
200
201 //-----------------------------------------------
202 // Generates multiple decorrelated noises
203 // in parallel. Expects n>0.
21
204 //-----------------------------------------------
205
206 multinoise(n) = multirandom(n) : par(i,n,/(RANDMAX))
207 with {
208 RANDMAX = 2147483647.0;
209 };
210
211
212 //------------------------------------------------
213
214 noises(N,i) = multinoise(N) : selector(i,N);
215
216
217 //-----------------------------------------------
218 // osc(freq) : Sinusoidal Oscillator
219 //-----------------------------------------------
220
221 tablesize = 1 << 16;
222 samplingfreq = SR;
223
224 time = (+(1)~_ ) - 1; // 0,1,2,3,...
225 sinwaveform = float(time)*(2.0*PI)/float(tablesize) : sin;
226
227 decimal(x) = x - floor(x);
228 phase(freq) = freq/float(samplingfreq) : (+ : decimal) ~ _ : *(float(tablesize));
229 osc(freq) = rdtable(tablesize, sinwaveform, int(phase(freq)) );
230 osci(freq) = s1 + d * (s2 - s1)
231 with {
232 i = int(phase(freq));
233 d = decimal(phase(freq));
234 s1 = rdtable(tablesize+1,sinwaveform,i);
235 s2 = rdtable(tablesize+1,sinwaveform,i+1);};
236
237
238 //-----------------------------------------------
239 // ADSR envelop
240 //-----------------------------------------------
241
242 // a,d,s,r = attack (#samples), decay (sec), sustain (percentage), release (sec)
243 // t = trigger signal
244
245 adsr(a,d,s,r,t) = env ~ (_,_) : (!,_) // the 2 state signals are fed back
246 with {
247 env (p2,y) =
248 (t>0) & (p2|(y>=1)), // p2 = decay-sustain phase
249 (y + p1*u - (p2&(y>s))*v*y - p3*w*y) // y = envelop signal
250 *((p3==0)|(y>=eps)) // cut off tails to prevent denormals
251 with {
252 p1 = (p2==0) & (t>0) & (y<1); // p1 = attack phase
253 p3 = (t<=0) & (y>0); // p3 = release phase
254 // #samples in attack, decay, release, must be >0
255 na = SR*a+(a==0.0); nd = SR*d+(d==0.0); nr = SR*r+(r==0.0);
256 // correct zero sustain level
257 z = s+(s==0.0)*db2linear(-60);
258 // attack, decay and (-60dB) release rates
259 u = 1/na; v = 1-pow(z, 1/nd); w = 1-1/pow(z*db2linear(60), 1/nr);
260 // values below this threshold are considered zero in the release phase
261 eps = db2linear(-120);
262 };
263 };
264
265
266 //-----------------------------------------------
267 // Spatialisation
268 //-----------------------------------------------
269
270 panner(c) = _ <: *(1-c), *(c);
271
22
272 bus2 = _,_;
273 bus3 = _,_,_;
274 bus4 = _,_,_,_;
275 bus5 = _,_,_,_,_;
276 bus6 = _,_,_,_,_,_;
277 bus7 = _,_,_,_,_,_,_;
278 bus8 = _,_,_,_,_,_,_,_;
279
280 gain2(g) = *(g),*(g);
281 gain3(g) = *(g),*(g),*(g);
282 gain4(g) = *(g),*(g),*(g),*(g);
283 gain5(g) = *(g),*(g),*(g),*(g),*(g);
284 gain6(g) = *(g),*(g),*(g),*(g),*(g),*(g);
285 gain7(g) = *(g),*(g),*(g),*(g),*(g),*(g),*(g);
286 gain8(g) = *(g),*(g),*(g),*(g),*(g),*(g),*(g),*(g);
287
288
289 //------------------------------------------------------
290 //
291 // GMEM SPAT
292 // n-outputs spatializer
293 // implementation of L. Pottier
294 //
295 //------------------------------------------------------
296 //
297 // n = number of outputs
298 // r = rotation (between 0 et 1)
299 // d = distance of the source (between 0 et 1)
300 //
301 //------------------------------------------------------
302 spat(n,a,d) = _ <: par(i, n, *( scaler(i, n, a, d) : smooth(0.9999) ))
303 with {
304 scaler(i,n,a,d) = (d/2.0+0.5)
305 * sqrt( max(0.0, 1.0 - abs(fmod(a+0.5+float(n-i)/n, 1.0) - 0.5) * n * d
) );
306 smooth(c) = *(1-c) : +~*(c);
307 };
308
309
310 //--------------- Second Order Generic Transfert Function -------------------------
311 // TF2(b0,b1,b2,a1,a2)
312 //
313 //---------------------------------------------------------------------------------
314
315 TF2(b0,b1,b2,a1,a2) = sub ~ conv2(a1,a2) : conv3(b0,b1,b2)
316 with {
317 conv3(k0,k1,k2,x) = k0*x + k1*x + k2*x;
318 conv2(k0,k1,x) = k0*x + k1*x;
319 sub(x,y) = y-x;
320 };
321
322
323 /*************************** Break Point Functions ***************************
324
325 bpf is an environment (a group of related definitions) tha can be used to
326 create break-point functions. It contains three functions :
327 - start(x,y) to start a break-point function
328 - end(x,y) to end a break-point function
329 - point(x,y) to add intermediate points to a break-point function
330
331 A minimal break-point function must contain at least a start and an end point :
332
333 f = bpf.start(x0,y0) : bpf.end(x1,y1);
334
335 A more involved break-point function can contains any number of intermediate
336 points
337
338 f = bpf.start(x0,y0) : bpf.point(x1,y1) : bpf.point(x2,y2) : bpf.end(x3,y3);
23
339
340 In any case the x_{i} must be in increasing order (for all i, x_{i} < x_{i+1})
341
342 For example the following definition :
343
344 f = bpf.start(x0,y0) : ... : bpf.point(xi,yi) : ... : bpf.end(xn,yn);
345
346 implements a break-point function f such that :
347
348 f(x) = y_{0} when x < x_{0}
349 f(x) = y_{n} when x > x_{n}
350 f(x) = y_{i} + (y_{i+1}-y_{i})*(x-x_{i})/(x_{i+1}-x_{i}) when x_{i} <= x and x < x_{i+1}
351
352 ******************************************************************************/
353
354 bpf = environment
355 {
356 // Start a break-point function
357 start(x0,y0) = \(x).(x0,y0,x,y0);
358
359 // Add a break-point
360 point(x1,y1) = \(x0,y0,x,y).(x1, y1, x , if (x < x0, y, if (x < x1, y0 + (x-x0)*(y1-y0)/(
x1-x0), y1)));
361
362 // End a break-point function
363 end (x1,y1) = \(x0,y0,x,y).(if (x < x0, y, if (x < x1, y0 + (x-x0)*(y1-y0)/(x1-x0), y1)));
364
365 // definition of if
366 if (c,t,e) = select2(c,e,t);
367 };

Listing 3: math.lib

1 /************************************************************************
2 ************************************************************************
3 FAUST library file
4 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 ************************************************************************
21 ************************************************************************/
22
23 declare name "Math Library";
24 declare author "GRAME";
25 declare copyright "GRAME";
26 declare version "1.0";
27 declare license "LGPL";
28
29 //--------------------------------------------------------------------------------
30 // Mathematic library for Faust
31
24
32 // Implementation of the math.h file as Faust foreign functions
33 //
34 // History
35 // ----------
36 // 28/06/2005 [YO] postfixed functions with f to force float version
37 // instead of double
38 // [YO] removed modf because it requires a pointer as argument
39 //---------------------------------------------------------------------------------
40
41 // -- Utilities and constants
42
43 SR = min(192000, max(1, fconstant(int fSamplingFreq, <math.h>)));
44 BS = fvariable(int count, <math.h>);
45
46 PI = 3.1415926535897932385;
47
48 // -- neg and inv functions
49
50 neg(x) = -x;
51 inv(x) = 1/x;
52
53 // -- Trigonometric Functions
54
55 //acos = ffunction(float acosf (float), <math.h>, "");
56 //asin = ffunction(float asinf (float), <math.h>, "");
57 //atan = ffunction(float atanf (float), <math.h>, "");
58 //atan2 = ffunction(float atan2f (float, float), <math.h>, "");
59
60 //sin = ffunction(float sinf (float), <math.h>, "");
61 //cos = ffunction(float cosf (float), <math.h>, "");
62 //tan = ffunction(float tanf (float), <math.h>,"");
63
64 // -- Exponential Functions
65
66 //exp = ffunction(float expf (float), <math.h>,"");
67 //log = ffunction(float logf (float), <math.h>,"");
68 //log10 = ffunction(float log10f (float), <math.h>,"");
69 //pow = ffunction(float powf (float, float), <math.h>,"");
70 //sqrt = ffunction(float sqrtf (float), <math.h>,"");
71 cbrt = ffunction(float cbrtf (float), <math.h>,"");
72 hypot = ffunction(float hypotf (float, float), <math.h>,"");
73 ldexp = ffunction(float ldexpf (float, int), <math.h>,"");
74 scalb = ffunction(float scalbf (float, float), <math.h>,"");
75 log1p = ffunction(float log1pf (float), <math.h>,"");
76 logb = ffunction(float logbf (float), <math.h>,"");
77 ilogb = ffunction(int ilogbf (float), <math.h>,"");
78 expm1 = ffunction(float expm1f (float), <math.h>,"");
79
80 // -- Hyperbolic Functions
81
82 acosh = ffunction(float acoshf (float), <math.h>, "");
83 asinh = ffunction(float asinhf (float), <math.h>, "");
84 atanh = ffunction(float atanhf (float), <math.h>, "");
85
86 sinh = ffunction(float sinhf (float), <math.h>, "");
87 cosh = ffunction(float coshf (float), <math.h>, "");
88 tanh = ffunction(float tanhf (float), <math.h>,"");
89
90 // -- Remainder Functions
91
92 //fmod = ffunction(float fmodf (float, float),<math.h>,"");
93 //remainder = ffunction(float remainderf (float, float),<math.h>,"");
94
95 // -- Nearest Integer Functions
96
97 //floor = ffunction(float floorf (float), <math.h>,"");
98 //ceil = ffunction(float ceilf (float), <math.h>,"");
99 //rint = ffunction(float rintf (float), <math.h>,"");
25
100
101 // -- Special Functions
102
103 erf = ffunction(float erff(float), <math.h>,"");
104 erfc = ffunction(float erfcf(float), <math.h>,"");
105 gamma = ffunction(float gammaf(float), <math.h>,"");
106 J0 = ffunction(float j0f(float), <math.h>,"");
107 J1 = ffunction(float j1f(float), <math.h>,"");
108 Jn = ffunction(float jnf(int, float), <math.h>,"");
109 lgamma = ffunction(float lgammaf(float), <math.h>,"");
110 Y0 = ffunction(float y0f(float), <math.h>,"");
111 Y1 = ffunction(float y1f(float), <math.h>,"");
112 Yn = ffunction(float ynf(int, float), <math.h>,"");
113
114
115 // -- Miscellaneous Functions
116
117 //fabs = ffunction(float fabsf (float), <math.h>,"");
118 //fmax = ffunction(float max (float, float),<math.h>,"");
119 //fmin = ffunction(float min (float, float),<math.h>,"");
120
121 fabs = abs;
122 fmax = max;
123 fmin = min;
124
125 isnan = ffunction(int isnan (float),<math.h>,"");
126 nextafter = ffunction(float nextafter(float, float),<math.h>,"");
127
128 // Pattern matching functions to count and access the elements of a list
129 // USAGE : count ((10,20,30,40)) -> 4
130 // take (3,(10,20,30,40)) -> 30
131 //
132
133 count ((xs, xxs)) = 1 + count(xxs);
134 count (xx) = 1;
135
136 take (1, (xs, xxs)) = xs;
137 take (1, xs) = xs;
138 take (nn, (xs, xxs)) = take (nn-1, xxs);
139
140 // linear interpolation between two signals
141 interpolate(i) = *(1.0-i),*(i) : +;
142
143 // if-then-else implemented with a select2.
144 if(cond,thn,els) = select2(cond,els,thn);
145
146
147 //-----------------------------------------------------------------
148 // countdown(count,trig)
149 // start counting down from count, count-1,...,0 when trig > 0
150 //-----------------------------------------------------------------
151 countdown(count, trig) = \(c).(if(trig>0, count, max(0, c-1))) ~_;
152
153 //-----------------------------------------------------------------
154 // countup(count,trig)
155 // start counting down from 0, 1, ... count-1, count when trig > 0
156 //-----------------------------------------------------------------
157 countup(count, trig) = \(c).(if(trig>0, 0, min(count, c+1))) ~_;
158
159 /******************************************************************
160 * Hadamard matrix function
161 * Implementation contributed by Remy Muller
162 *****************************************************************/
163
164 // bus(n) : n parallel cables
165 bus(2) = _,_; // avoids a lot of "bus(1)" labels in block diagrams
166 bus(n) = par(i, n, _);
167
26
168 // selector(i,n) : select ith cable among n
169 selector(i,n) = par(j, n, S(i, j)) with { S(i,i) = _; S(i,j) = !; };
170
171 // interleave(m,n) : interleave m*n cables : x(0), x(m), x(2m), ..., x(1),x(1+m), x(1+2m)...
172 //interleave(m,n) = bus(m*n) <: par(i, m, par(j, n, selector(i+j*m,m*n)));
173
174 // interleave(row,col) : interleave row*col cables from column order to row order.
175 // input : x(0), x(1), x(2) ..., x(row*col-1)
176 // output: x(0+0*row), x(0+1*row), x(0+2*row), ..., x(1+0*row), x(1+1*row), x(1+2*row), ...
177 interleave(row,col) = bus(row*col) <: par(r, row, par(c, col, selector(r+c*row,row*col)));
178
179 // butterfly(n) : addition then substraction of interleaved signals :
180 butterfly(n) = bus(n) <: interleave(n/2,2), interleave(n/2,2) : par(i, n/2, +), par(i, n/2,
-);
181
182 // hadamard(n) : hadamard matrix function of size n = 2^k
183 hadamard(2) = butterfly(2);
184 hadamard(n) = butterfly(n) : (hadamard(n/2) , hadamard(n/2));

Listing 4: instrument.lib

1 //instrument.lib - Faust function of various types usefull for building physical model
instruments
2
3 declare name "Faust-STK Tools Library";
4 declare author "Romain Michon (rmichon@ccrma.stanford.edu)";
5 declare copyright "Romain Michon";
6 declare version "1.0";
7 declare licence "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license);
8
9 import("math.lib");
10 import("filter.lib");
11 import("effect.lib");
12
13 //========================= ENVELOPE GENERATORS ===============================
14
15 //----------------------- VIBRATO ENVELOPE ----------------------------
16 // 4 phases envelope to control vibrato gain
17 //
18 // USAGE:
19 // _ : *(envVibrato(b,a,s,r,t)) : _
20 // where
21 // b = beginning duration (silence) in seconds
22 // a = attack duration in seconds
23 // s = sustain as a percentage of the amplitude to be modified
24 // r = release duration in seconds
25 // t = trigger signal
26
27 envVibrato(b,a,s,r,t) = env ~ (_,_,_) : (!,!,_) // the 3 state signals are fed back
28 with {
29 env (p2,cnt,y) =
30 (t>0) & (p2|(y>=1)),
31 (cnt + 1)*(t>0), // counter for the first step "b"
32 (y + p1*p3*u*(s/100) - p4*w*y)*((p4==0)|(y>=eps)) // y = envelop signal
33 //*(y>=eps) // cut off tails to prevent denormals
34 with {
35 p1 = (p2==0) & (t>0) & (y<1) & (cnt>(b*SR)); // p1 = attack phase
36 p3 = 1-(cnt<(nb)); // p3 = beginning phase
37 p4 = (t<=0) & (y>0); // p4 = release phase
38 // #samples in attack, release, must be >0
39 nb = SR*b+(b==0.0) ; na = SR*a+(a==0.0); nr = SR*r+(r==0.0);
40 // attack and (-60dB) release rates
41 z = s+(s==0.0)*db2linear(-60);
42 u = 1/na; w = 1-1/pow(z*db2linear(60), 1/nr);
27
43 // values below this threshold are considered zero in the release phase
44 eps = db2linear(-120);
45 };
46 };
47
48 //----------------------- ATTACK - SUSTAIN - RELEASE ----------------------------
49 // Attack - Sustain - Release envelope
50 //
51 // USAGE:
52 // _ : *(asr(a,s,r,t)) : _
53 // where
54 // a = attack duration in seconds
55 // s = sustain as a percentage of the amplitude to be modified
56 // r = release duration in seconds
57 // t = trigger signal
58
59 asr(a,s,r,t) = env ~ (_,_) : (!,_) // the 2 state signals are fed back
60 with {
61 env (p2,y) =
62 (t>0) & (p2|(y>=1)),
63 (y + p1*u*(s/100) - p3*w*y) // y = envelop signal
64 *((p3==0)|(y>=eps)) // cut off tails to prevent denormals
65 with {
66 p1 = (p2==0) & (t>0) & (y<1); // p1 = attack phase
67 p3 = (t<=0) & (y>0); // p3 = release phase
68 // #samples in attack, release, must be >0
69 na = SR*a+(a==0.0); nr = SR*r+(r==0.0);
70 // correct zero sustain level
71 z = s+(s==0.0)*db2linear(-60);
72 // attack and (-60dB) release rates
73 u = 1/na; w = 1-1/pow(z*db2linear(60), 1/nr);
74 // values below this threshold are considered zero in the release phase
75 eps = db2linear(-120);
76 };
77 };
78
79 //----------------------- ASYMPT60 ----------------------------
80 // Envelope generator which asymptotically approaches a target value.
81 //
82 // USAGE:
83 // asympT60(value,trgt,T60,trig) : _
84 // where
85 // value = starting value
86 // trgt = target value
87 // T60 = ramping time
88 // trig = trigger signal
89
90 asympT60(value,trgt,T60,trig) = (_*factor + constant)~_
91 with{
92 cntSample = *(trig) + 1~_ : -(1);
93 attDur = float(2);
94 cndFirst = ((cntSample < attDur) & (trig > 0));
95 target = value*cndFirst + trgt*(cndFirst < 1);
96 factorAtt = exp(-7/attDur);
97 factorT60 = exp(-7/(T60*float(SR)));
98 factor = factorAtt*((cntSample < attDur) & (trig > 0)) +
99 ((cntSample >= attDur) | (trig < 1))*factorT60;
100 constant = (1 - factor)*target;
101 };
102
103 //========================= TABLES ===============================
104
105 //----------------------- CLIPPING FUNCTION ----------------------------
106 // Positive and negative clipping functions.
107 //
108 // USAGE:
109 // _ : saturationPos : _
110 // _ : saturationNeg : _
28
111 // _ : saturationPos : saturationNeg : _
112
113 saturationPos(x) = x <: (_>1),(_<=1 : *(x)) :> +;
114 saturationNeg(x) = x <: (_<-1),(_>=-1 : *(x)) :> *(-1) + _;
115
116 //----------------------- BOW TABLE ----------------------------
117 // Simple bow table.
118 //
119 // USAGE:
120 // index : bow(offset,slope) : _
121 // where
122 // 0 <= index <= 1
123
124 bow(offset,slope) = pow(abs(sample) + 0.75, -4) : saturationPos
125 with{
126 sample(y) = (y + offset)*slope;
127 };
128
129 //----------------------- REED TABLE ----------------------------
130 // Simple reed table to be used with waveguide models of clanrinet, saxophone, etc.
131 //
132 // USAGE:
133 // _ : reed(offset,slope) : _
134 // where
135 // offset = offset between 0 and 1
136 // slope = slope between 0 and 1
137 // REFERENCE:
138 // https://ccrma.stanford.edu/~jos/pasp/View_Single_Reed_Oscillation.html
139
140 reed(offset,slope) = reedTable : saturationPos : saturationNeg
141 with{
142 reedTable = offset + (slope*_);
143 };
144
145 //========================= FILTERS ===============================
146
147 //----------------------- ONE POLE ----------------------------
148
149 onePole(b0,a1,x) = (b0*x - a1*_)~_;
150
151 //----------------------- ONE POLE SWEPT ----------------------------
152
153 onePoleSwep(a1,x) = (1 + a1)*x - a1*x;
154
155 //----------------------- POLE ZERO ----------------------------
156
157 poleZero(b0,b1,a1,x) = (b0*x + b1*x - a1*_)~_;
158
159 //----------------------- ONE ZEROS ----------------------------
160 // Simple One zero and One zero recursive filters
161 //
162 // USAGE:
163 // _ : oneZero0(b0,b1) : _
164 // _ : oneZero1(b0,b1) : _
165 // REFERENCE:
166 // https://ccrma.stanford.edu/~jos/fp2/One_Zero.html
167
168 oneZero0(b0,b1,x) = (*(b1) + x*b0)~_;
169 oneZero1(b0,b1,x) = (x*b1 + x*b0);
170
171 //----------------------- BANDPASS FILTER WITH CONSTANT UNITY PEAK GAIN BASED ON A BIQUAD
----------------------------
172
173 bandPass(resonance,radius) = TF2(b0,b1,b2,a1,a2)
174 with{
175 a2 = radius*radius;
176 a1 = -2*radius*cos(PI*2*resonance/SR);
177 b0 = 0.5-0.5*a2;
29
178 b1 = 0;
179 b2 = -b0;
180 };
181
182 //----------------------- BANDPASS FILTER BASED ON A BIQUAD ----------------------------
183 // Band pass filter using a biquad (TF2 is declared in filter.lib)
184 //
185 // USAGE:
186 // _ : bandPassH(resonance,radius) : _
187 // where
188 // resonance = center frequency
189 // radius = radius
190
191 bandPassH(resonance,radius) = TF2(b0,b1,b2,a1,a2)
192 with{
193 a2 = radius*radius;
194 a1 = -2*radius*cos(PI*2*resonance/SR);
195 b0 = 1;
196 b1 = 0;
197 b2 = 0;
198 };
199
200 //----------------------- FLUE JET NON-LINEAR FUNCTION ----------------------------
201 // Jet Table: flue jet non-linear function, computed by a polynomial calculation
202
203 jetTable(x) = x <: _*(_*_-1) : saturationPos : saturationNeg;
204
205 //----------------------- NON LINEAR MODULATOR ----------------------------
206 // nonLinearModulator adapts the function allpassnn from filter.lib for using it with
waveguide instruments
207 //
208 // USAGE:
209 // _ : nonLinearModulator(nonlinearity,env,freq,typeMod,freqMod,order) : _
210 // where
211 // nonlinearity = nonlinearity coefficient between 0 and 1
212 // env = input to connect any kind of envelope
213 // freq = current tone frequency
214 // typeMod = if 0: theta is modulated by the incoming signal;
215 // if 1: theta is modulated by the averaged incoming signal;
216 // if 2: theta is modulated by the squared incoming signal;
217 // if 3: theta is modulated by a sine wave of frequency freqMod;
218 // if 4: theta is modulated by a sine wave of frequency freq;
219 // freqMod = frequency of the sine wave modulation
220 // order = order of the filter
221
222 nonLinearModulator(nonlinearity,env,freq,typeMod,freqMod,order) =
223 //theta is modulated by a sine wave
224 _ <: nonLinearFilterOsc*(typeMod >= 3),
225 //theta is modulated by the incoming signal
226 (_ <: nonLinearFilterSig*nonlinearity,_*(1 - nonlinearity) :> +)*(typeMod < 3)
227 :> +
228 with{
229 //which frequency to use for the sine wave oscillator?
230 freqOscMod = (typeMod == 4)*freq + (typeMod != 4)*freqMod;
231
232 //the incoming signal is scaled and the envelope is applied
233 tsignorm(x) = nonlinearity*PI*x*env;
234 tsigsquared(x) = nonlinearity*PI*x*x*env; //incoming signal is squared
235 tsigav(x) = nonlinearity*PI*((x + x)/2)*env; //incoming signal is averaged with its
previous sample
236
237 //select which version of the incoming signal of theta to use
238 tsig(x) = tsignorm(x)*(typeMod == 0) + tsigav(x)*(typeMod == 1)
239 + tsigsquared(x)*(typeMod == 2);
240
241 //theta is modulated by a sine wave generator
242 tosc = nonlinearity*PI*osc(freqOscMod)*env;
243
30
244 //incoming signal is sent to the nonlinear passive allpass ladder filter
245 nonLinearFilterSig(x) = x <: allpassnn(order,(par(i,order,tsig(x))));
246 nonLinearFilterOsc = _ <: allpassnn(order,(par(i,order,tosc)));
247 };
248
249 //========================= WAVE TABLES ===============================
250
251 //----------------------- STICK IMPACT ----------------------------
252 // Stick impact table.
253 //
254 // USAGE:
255 // index : readMarmstk1 : _
256
257 readMarmstk1 = ffunction(float readMarmstk1 (int), <instrument.h>,"");
258 marmstk1TableSize = 246;
259
260 //========================= TOOLS ===============================
261
262 //----------------------- STEREOIZER ----------------------------
263 // This function takes a mono input signal and spacialize it in stereo
264 // in function of the period duration of the tone being played.
265 //
266 // USAGE:
267 // _ : stereo(periodDuration) : _,_
268 // where
269 // periodDuration = period duration of the tone being played in number of samples
270 // ACKNOWLEDGMENT
271 // Formulation initiated by Julius O. Smith in https://ccrma.stanford.edu/realsimple/
faust_strings/
272
273 stereoizer(periodDuration) = _ <: _,widthdelay : stereopanner
274 with{
275 W = hslider("v:Spat/spatial width", 0.5, 0, 1, 0.01);
276 A = hslider("v:Spat/pan angle", 0.6, 0, 1, 0.01);
277 widthdelay = delay(4096,W*periodDuration/2);
278 stereopanner = _,_ : *(1.0-A), *(A);
279 };
280
281 //----------------------- INSTRREVERB ----------------------------
282 // GUI for zita_rev1_stereo from effect.lib
283 //
284 // USAGE:
285 // _,_ : instrRerveb
286
287 instrReverb = _,_ <: *(reverbGain),*(reverbGain),*(1 - reverbGain),*(1 - reverbGain) :
288 zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax),_,_ <: _,!,_,!,!,_,!,_ : +,+
289 with{
290 reverbGain = hslider("v:Reverb/reverbGain",0.137,0,1,0.01) : smooth(0.999);
291 roomSize = hslider("v:Reverb/roomSize",0.72,0.01,2,0.01);
292 rdel = 20;
293 f1 = 200;
294 f2 = 6000;
295 t60dc = roomSize*3;
296 t60m = roomSize*2;
297 fsmax = 48000;
298 };

Listing 5: filter.lib

1 // filter.lib - digital filters of various types useful in audio and beyond
2
3 declare name "Faust Filter Library";
4 declare author "Julius O. Smith (jos at ccrma.stanford.edu)";
5 declare copyright "Julius O. Smith III";
31
6 declare version "1.29";
7 declare license "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license)
8 declare reference "https://ccrma.stanford.edu/~jos/filters/";
9
10 import("music.lib"); // delay, frac and, from math.lib, SR and PI
11
12 //---------------------- zero(z) --------------------------
13 // z = location of zero along real axis in z-plane
14 // Difference equation: y(n) = x(n) - z * x(n-1)
15 // Reference: https://ccrma.stanford.edu/~jos/filters/One_Zero.html
16
17 zero(z) = _ <: _,mem : _,*(z) : -;
18
19 //------------------------ pole(p) ---------------------------
20 // p = pole location = feedback coefficient
21 // Could also be called a "leaky integrator".
22 // Difference equation: y(n) = x(n) + p * y(n-1)
23 // Reference: https://ccrma.stanford.edu/~jos/filters/One_Pole.html
24
25 pole(p) = + ~ *(p);
26
27 //---------------------- integrator --------------------------
28 // pole(1) [implemented separately for block-diagram clarity]
29
30 integrator = + ~ _ ;
31
32 //----------------------- tau2pole ---------------------------
33 // tau2pole(tau) returns a real pole giving exponential decay with
34 // tau = time-constant in seconds
35 //
36 tau2pole(tau) = exp(-1.0/(tau*SR));
37
38 //---------------------- smooth(s) --------------------------
39 // Exponential smoothing by a unity-dc-gain one-pole lowpass
40 //
41 // USAGE: smooth(tau2pole(tau)), where
42 // tau = desired smoothing time constant in seconds,
43 // or
44 // smooth(s), where s = smoothness between 0 and 1.
45 // s=0 for no smoothing
46 // s=0.999 is "very smooth"
47 // s>1 is unstable, and s=1 yields the zero signal for all inputs.
48 // The exponential time-constant is approximately
49 // 1/(1-s) samples, when s is close to (but less than) 1.
50 // Reference:
51 // https://ccrma.stanford.edu/~jos/mdft/Convolution_Example_2_ADSR.html
52
53 smooth(s) = *(1.0 - s) : + ~ *(s);
54
55 //------------------- dcblockerat(fb) -----------------------
56 // fb = "break frequency" in Hz, i.e., -3 dB gain frequency.
57 // The amplitude response is substantially flat above fb,
58 // and sloped at about +6 dB/octave below fb.
59 // Derived from the analog transfer function
60 // H(s) = s / (s + 2*PI*fb)
61 // by the low-frequency-matching bilinear transform method
62 // (i.e., the standard frequency-scaling constant 2*SR).
63 // Reference:
64 // https://ccrma.stanford.edu/~jos/pasp/Bilinear_Transformation.html
65
66 dcblockerat(fb) = *(b0) : zero(1) : pole(p)
67 with {
68 wn = PI*fb/SR;
69 b0 = 1.0 / (1 + wn);
70 p = (1 - wn) * b0;
71 };
72
73 //---------------------- dcblocker --------------------------
32
74 // Default dc blocker has -3dB point near 35 Hz (at 44.1 kHz)
75 // and high-frequency gain near 1.0025 (due to no scaling)
76 //
77 dcblocker = zero(1) : pole(0.995);
78
79 //------------ notchw(width,freq), notch(freq) --------------
80 // width = "notch width" in Hz (approximate)
81 // freq = "notch frequency" in Hz
82 // Reference:
83 // https://ccrma.stanford.edu/~jos/pasp/Phasing_2nd_Order_Allpass_Filters.html
84
85 notchw(width,freq) = tf2(b0,b1,b2,a1,a2)
86 with {
87 fb = 0.5*width; // First design a dcblockerat(width/2)
88 wn = PI*fb/SR;
89 b0db = 1.0 / (1 + wn);
90 p = (1 - wn) * b0db; // This is our pole radius.
91 // Now place unit-circle zeros at desired angles:
92 tn = 2*PI*freq/SR;
93 a2 = p * p;
94 a2p1 = 1+a2;
95 a1 = -a2p1*cos(tn);
96 b1 = a1;
97 b0 = 0.5*a2p1;
98 b2 = b0;
99 };
100
101 //========================= Comb Filters ===============================
102
103 //----------------------- ff_comb, ff_fcomb ----------------------------
104 // Feed-Forward Comb Filter
105 //
106 // USAGE:
107 // _ : ff_comb(maxdel,intdel,b0,bM) : _
108 // _ : ff_fcomb(maxdel,del,b0,bM) : _
109 // where
110 // maxdel = maximum delay (a power of 2)
111 // intdel = current (integer) comb-filter delay between 0 and maxdel
112 // del = current (float) comb-filter delay between 0 and maxdel
113 // b0 = gain applied to delay-line input
114 // bM = gain applied to delay-line output and then summed with input
115 //
116 // Note that ff_comb requires integer delays (uses delay() internally)
117 // while ff_fcomb takes floating-point delays (uses fdelay() internally).
118 //
119 // REFERENCE:
120 // https://ccrma.stanford.edu/~jos/pasp/Feedforward_Comb_Filters.html
121
122 ff_comb (maxdel,M,b0,bM) = _ <: *(b0), bM * delay(maxdel,M) : + ;
123 ff_fcomb(maxdel,M,b0,bM) = _ <: *(b0), bM * fdelay(maxdel,M) : + ;
124
125 // Typical special case:
126 ffcombfilter(maxdel,del,g) = ff_comb(maxdel,del,1,g);
127
128 //----------------------- fb_comb, fb_fcomb, rev1 -----------------------
129 // Feed-Back Comb Filter
130 //
131 // USAGE:
132 // _ : fb_comb(maxdel,intdel,b0,aN) : _
133 // _ : fb_fcomb(maxdel,del,b0,aN) : _
134 // _ : rev1(maxdel,del,-aN) : _
135 // where
136 // maxdel = maximum delay (a power of 2)
137 // intdel = current (integer) comb-filter delay between 0 and maxdel
138 // del = current (float) comb-filter delay between 0 and maxdel
139 // b0 = gain applied to delay-line input and forwarded to output
140 // aN = minus the gain applied to delay-line output before
141 // summing with the input and feeding to the delay line
33
142 //
143 // Reference:
144 // https://ccrma.stanford.edu/~jos/pasp/Feedback_Comb_Filters.html
145
146 fb_comb (maxdel,N,b0,aN) = (+ <: delay(maxdel,N),_) ~ *(-aN) : !,*(b0);
147 fb_fcomb(maxdel,N,b0,aN) = (+ <: fdelay(maxdel,N),_) ~ *(-aN) : !,*(b0);
148
149 // The "rev1 section" dates back to the 1960s in computer-music reverberation.
150 // See the jcrev and brassrev in effect.lib for usage examples.
151 rev1(maxdel,N,g) = fb_comb (maxdel,N,1,-g);
152
153 // Typical special case:
154 fbcombfilter(maxdel,intdel,g) = (+ : delay(maxdel,intdel)) ~ *(g);
155 ffbcombfilter(maxdel,del,g) = (+ : fdelay(maxdel,del)) ~ *(g);
156
157 //------------------- allpass_comb, allpass_fcomb, rev2 -----------------
158 // Schroeder Allpass Comb Filter
159 //
160 // USAGE:
161 // _ : allpass_comb (maxdel,intdel,aN) : _
162 // _ : allpass_fcomb(maxdel,del,aN) : _
163 // _ : rev2(maxdel,del,-aN) : _
164 // where
165 // maxdel = maximum delay (a power of 2)
166 // intdel = current (integer) comb-filter delay between 0 and maxdel
167 // del = current (float) comb-filter delay between 0 and maxdel
168 // aN = minus the feedback gain
169 //
170 // Note that allpass_comb(maxlen,len,aN) =
171 // ff_comb(maxlen,len,aN,1) :
172 // fb_comb(maxlen,len-1,1,aN);
173 // which is a direct-form-1 implementation, requiring two delay lines.
174 // The implementation here is direct-form-2 requiring only one delay line.
175 //
176 // REFERENCES:
177 // https://ccrma.stanford.edu/~jos/pasp/Allpass_Two_Combs.html
178 // https://ccrma.stanford.edu/~jos/pasp/Schroeder_Allpass_Sections.html
179 // https://ccrma.stanford.edu/~jos/filters/Four_Direct_Forms.html
180
181 allpass_comb(maxdel,N,aN) = (+ <:
182 delay(maxdel,N-1),*(aN)) ~ *(-aN)
183 : mem,_ : + ;
184
185 // The "rev2 section" dates back to the 1960s in computer-music reverberation:
186 rev2(maxlen,len,g) = allpass_comb(maxlen,len,-g);
187
188 //================ Direct-Form Digital Filter Sections ================
189
190 // Specified by transfer-function polynomials B(z)/A(z) as in matlab
191
192 //---------------------------- iir (tfN) -------------------------------
193 // Nth-order Infinite-Impulse-Response (IIR) digital filter,
194 // implemented in terms of the Transfer-Function (TF) coefficients.
195 // Such filter structures are termed "direct form".
196 //
197 // USAGE:
198 // _ : iir(order,bcoeffs,acoeffs) : _
199 // where
200 // order = filter order (int) = max(#poles,#zeros)
201 // bcoeffs = (b0,b1,...,b_order) = TF numerator coefficients
202 // acoeffs = (a1,...,a_order) = TF denominator coeffs (a0=1)
203 //
204 // REFERENCE:
205 // https://ccrma.stanford.edu/~jos/filters/Four_Direct_Forms.html
206
207 iir(bv,av) = sub ~ fir(av) : fir(bv);
208
209 //----------------------------- sub ---------------------------------
34
210 sub(x,y) = y-x; // move to math.lib?
211
212 //----------------------------- fir ---------------------------------
213 // FIR filter (convolution of FIR filter coefficients with a signal)
214 //
215 // USAGE:
216 // _ : fir(bv) : _
217 // where bv = b0,b1,...,bn is a parallel bank of coefficient signals.
218 // NOTE: bv is processed using pattern-matching at compile time,
219 // so it must have this normal form (parallel signals).
220 // EXAMPLE: Smoothing white noise with a five-point moving average:
221 // bv = .2,.2,.2,.2,.2;
222 // process = noise : fir(bv);
223 // EQUIVALENT (note double parens):
224 // process = noise : fir((.2,.2,.2,.2,.2));
225
226 fir(bv) = conv(bv);
227
228 //--------------------------- conv, convN -------------------------------
229 // Convolution of input signal with given coefficients
230 //
231 // USAGE:
232 // _ : conv((k1,k2,k3,...,kN)) : _; // Argument = one signal bank
233 // _ : convN(N,(k1,k2,k3,...)) : _; // Useful when N < count((k1,...))
234
235 convN(N,kv,x) = sum(i,N,take(i+1,kv) * x@i); // take() defined in math.lib
236
237 conv(kv,x) = sum(i,count(kv),take(i+1,kv) * x@i); // count() from math.lib
238
239 // Named special cases:
240 //----------------------------- tf1, tf2 ---------------------------------
241 // tfN = Nth-order direct-form digital filter
242 tf1(b0,b1,a1) = _ <: *(b0), (mem : *(b1)) :> + ~ *(0-a1);
243 tf2(b0,b1,b2,a1,a2) = iir((b0,b1,b2),(a1,a2)); // cf. TF2 in music.lib)
244
245 //===================== Ladder/Lattice Digital Filters ======================
246 // Ladder and lattice digital filters generally have superior numerical
247 // properties relative to direct-form digital filters. They can be derived
248 // from digital waveguide filters, which gives them a physical interpretation.
249
250 // REFERENCES:
251 // F. Itakura and S. Saito: "Digital Filtering Techniques for Speech Analysis and Synthesis",
252 // 7th Int. Cong. Acoustics, Budapest, 25 C 1, 1971.
253 // J. D. Markel and A. H. Gray: Linear Prediction of Speech, New York: Springer Verlag, 1976.
254 // https://ccrma.stanford.edu/~jos/pasp/Conventional_Ladder_Filters.html
255
256 //------------------------------ block, crossn,crossn1 ----------------------------------
257 // signal block/crossing utilities
258 // (move to math.lib?)
259
260 // block - terminate n signals (goes with bus(n) in math.lib)
261 block(n) = par(i,n,!);
262
263 // crossnn - cross two bus(n)s:
264 crossnn(n) = bus(n),bus(n) <: block(n),bus(n),bus(n),block(n);
265
266 // crossn1 - cross bus(n) and bus(1):
267 crossn1(n) = bus(n),(bus(1)<:bus(n)) <: block(n),bus(n),bus(n),block(n):bus(1),block(n-1),
bus(n);
268
269 //------------------------------- av2sv -----------------------------------
270 // Compute reflection coefficients sv from transfer-function denominator av
271 //
272 // USAGE:
273 // sv = av2sv(av)
274 // where
275 // av = parallel signal bank a1,...,aN
276 // sv = parallel signal bank s1,...,sN
35
277 // where si = ith reflection coefficient, and
278 // ai = coefficient of z^(-i) in the filter
279 // transfer-function denominator A(z).
280 //
281 // REFERENCE:
282 // https://ccrma.stanford.edu/~jos/filters/Step_Down_Procedure.html
283 // (where reflection coefficients are denoted by k rather than s).
284
285 av2sv(av) = par(i,M,s(i+1)) with {
286 M = count(av);
287 s(m) = sr(M-m+1); // m=1..M
288 sr(m) = Ari(m,M-m+1); // s_{M-1-m}
289 Ari(m,i) = take(i+1,Ar(m-1));
290 //step-down recursion for lattice/ladder digital filters:
291 Ar(0) = (1,av); // Ar(m) is order M-m (i.e. "reverse-indexed")
292 Ar(m) = 1,par(i,M-m, (Ari(m,i+1) - sr(m)*Ari(m,M-m-i))/(1-sr(m)*sr(m)));
293 };
294
295 //---------------------------- bvav2nuv --------------------------------
296 // Compute lattice tap coefficients from transfer-function coefficients
297 //
298 // USAGE:
299 // nuv = bvav2nuv(bv,av)
300 // where
301 // av = parallel signal bank a1,...,aN
302 // bv = parallel signal bank b0,b1,...,aN
303 // nuv = parallel signal bank nu1,...,nuN
304 // where nui is the ith tap coefficient,
305 // bi is the coefficient of z^(-i) in the filter numerator,
306 // ai is the coefficient of z^(-i) in the filter denominator
307
308 bvav2nuv(bv,av) = par(m,M+1,nu(m)) with {
309 M = count(av);
310 nu(m) = take(m+1,Pr(M-m)); // m=0..M
311 // lattice/ladder tap parameters:
312 Pr(0) = bv; // Pr(m) is order M-m, r means "reversed"
313 Pr(m) = par(i,M-m+1, (Pri(m,i) - nu(M-m+1)*Ari(m,M-m-i+1)));
314 Pri(m,i) = take(i+1,Pr(m-1));
315 Ari(m,i) = take(i+1,Ar(m-1));
316 //step-down recursion for lattice/ladder digital filters:
317 Ar(0) = (1,av); // Ar(m) is order M-m (recursion index must start at constant)
318 Ar(m) = 1,par(i,M-m, (Ari(m,i+1) - sr(m)*Ari(m,M-m-i))/(1-sr(m)*sr(m)));
319 sr(m) = Ari(m,M-m+1); // s_{M-1-m}
320 };
321
322 //--------------------------- iir_lat2, allpassnt -----------------------
323
324 iir_lat2(bv,av) = allpassnt(M,sv) : sum(i,M+1,*(take(M-i+1,tg)))
325 with {
326 M = count(av);
327 sv = av2sv(av); // sv = vector of sin(theta) reflection coefficients
328 tg = bvav2nuv(bv,av); // tg = vector of tap gains
329 };
330
331 // two-multiply lattice allpass (nested order-1 direct-form-ii allpasses):
332 allpassnt(0,sv) = _;
333 allpassnt(n,sv) =
334 //0: x <: ((+ <: (allpassnt(n-1,sv)),*(s))~(*(-s))) : _,_ :+
335 _ : ((+ <: (allpassnt(n-1,sv),*(s)))~*(-s)) : fsec(n)
336 with {
337 fsec(1) = crossnn(1) : _, (_<:mem,_) : +,_;
338 fsec(n) = crossn1(n) : _, (_<:mem,_),par(i,n-1,_) : +, par(i,n,_);
339 innertaps(n) = par(i,n,_);
340 s = take(n,sv); // reflection coefficient s = sin(theta)
341 };
342
343 //------------------------------- iir_kl, allpassnklt -------------------------
344 iir_kl(bv,av) = allpassnklt(M,sv) : sum(i,M+1,*(tghr(i)))
36
345 with {
346 M = count(av);
347 sv = av2sv(av); // sv = vector of sin(theta) reflection coefficients
348 tg = bvav2nuv(bv,av); // tg = vector of tap gains for 2mul case
349 tgr(i) = take(M+1-i,tg);
350 tghr(n) = tgr(n)/pi(n);
351 pi(0) = 1;
352 pi(n) = pi(n-1)*(1+take(M-n+1,sv)); // all sign parameters +
353 };
354
355 // Kelly-Lochbaum ladder allpass with tap lines:
356 allpassnklt(0,sv) = _;
357 allpassnklt(n,sv) = _ <: *(s),(*(1+s) : (+
358 : allpassnklt(n-1,sv))~(*(-s))) : fsec(n)
359 with {
360 fsec(1) = _, (_<:mem*(1-s),_) : sumandtaps(n);
361 fsec(n) = _, (_<:mem*(1-s),_), par(i,n-1,_) : sumandtaps(n);
362 s = take(n,sv);
363 sumandtaps(n) = +,par(i,n,_);
364 };
365
366
367 //------------------------------- iir_lat1, allpassn1mt -------------------------
368 iir_lat1(bv,av) = allpassn1mt(M,sv) : sum(i,M+1,*(tghr(i+1)))
369 with {
370 M = count(av);
371 sv = av2sv(av); // sv = vector of sin(theta) reflection coefficients
372 tg = bvav2nuv(bv,av); // tg = vector of tap gains
373 tgr(i) = take(M+2-i,tg); // i=1..M+1 (for "takability")
374 tghr(n)=tgr(n)/pi(n);
375 pi(1) = 1;
376 pi(n) = pi(n-1)*(1+take(M-n+2,sv)); // all sign parameters +
377 };
378
379 // one-multiply lattice allpass with tap lines:
380 allpassn1mt(0,sv) = _;
381 allpassn1mt(n,sv)= _ <: _,_ : ((+:*(s) <: _,_),_ : _,+ : crossnn(1)
382 : allpassn1mt(n-1,sv),_)~(*(-1)) : fsec(n)
383 with {
384 //0: fsec(n) = _,_ : +
385 fsec(1) = crossnn(1) : _, (_<:mem,_) : +,_;
386 fsec(n) = crossn1(n) : _, (_<:mem,_),par(i,n-1,_) : +, par(i,n,_);
387 innertaps(n) = par(i,n,_);
388 s = take(n,sv); // reflection coefficient s = sin(theta)
389 };
390
391 //------------------------------- iir_nl, allpassnnlt -------------------------
392 // Normalized ladder filter
393 //
394 // REFERENCES:
395 // J. D. Markel and A. H. Gray, Linear Prediction of Speech, New York: Springer Verlag,
1976.
396 // https://ccrma.stanford.edu/~jos/pasp/Normalized_Scattering_Junctions.html
397
398 iir_nl(bv,av) = allpassnnlt(M,sv) : sum(i,M+1,*(tghr(i)))
399 with {
400 M = count(av);
401 sv = av2sv(av); // sv = vector of sin(theta) reflection coefficients
402 tg = bvav2nuv(bv,av); // tg = vector of tap gains for 2mul case
403 tgr(i) = take(M+1-i,tg);
404 tghr(n) = tgr(n)/pi(n);
405 pi(0) = 1;
406 s(n) = take(M-n+1,sv);
407 c(n) = sqrt(max(0,1-s(n)*s(n))); // compiler crashes on sqrt(-)
408 pi(n) = pi(n-1)*c(n);
409 };
410
411 // Normalized ladder allpass with tap lines:
37
412 allpassnnlt(0,sv) = _;
413 allpassnnlt(n,scl*(sv)) = allpassnnlt(n,par(i,count(sv),scl*(sv(i))));
414 allpassnnlt(n,sv) = _ <: *(s),(*(c) : (+
415 : allpassnnlt(n-1,sv))~(*(-s))) : fsec(n)
416 with {
417 fsec(1) = _, (_<:mem*(c),_) : sumandtaps(n);
418 fsec(n) = _, (_<:mem*(c),_), par(i,n-1,_) : sumandtaps(n);
419 s = take(n,sv);
420 c = sqrt(max(0,1-s*s));
421 sumandtaps(n) = +,par(i,n,_);
422 };
423
424 //========================= Useful special cases ============================
425
426 //-------------------------------- tf2np ------------------------------------
427 // tf2np - biquad based on a stable second-order Normalized Ladder Filter
428 // (more robust to modulation than tf2 and protected against instability)
429 tf2np(b0,b1,b2,a1,a2) = allpassnnlt(M,sv) : sum(i,M+1,*(tghr(i)))
430 with {
431 smax = 0.9999; // maximum reflection-coefficient magnitude allowed
432 s2 = max(-smax, min(smax,a2)); // Project both reflection-coefficients
433 s1 = max(-smax, min(smax,a1/(1+a2))); // into the defined stability-region.
434 sv = (s1,s2); // vector of sin(theta) reflection coefficients
435 M = 2;
436 nu(2) = b2;
437 nu(1) = b1 - b2*a1;
438 nu(0) = (b0-b2*a2) - nu(1)*s1;
439 tg = (nu(0),nu(1),nu(2));
440 tgr(i) = take(M+1-i,tg); // vector of tap gains for 2mul case
441 tghr(n) = tgr(n)/pi(n); // apply pi parameters for NLF case
442 pi(0) = 1;
443 s(n) = take(M-n+1,sv);
444 c(n) = sqrt(1-s(n)*s(n));
445 pi(n) = pi(n-1)*c(n);
446 };
447
448 //----------------------------- wgr ---------------------------------
449 // Second-order transformer-normalized digital waveguide resonator
450 // USAGE:
451 // _ : wgr(f,r) : _
452 // where
453 // f = resonance frequency (Hz)
454 // r = loss factor for exponential decay
455 // (set to 1 to make a numerically stable oscillator)
456 //
457 // REFERENCES:
458 // https://ccrma.stanford.edu/~jos/pasp/Power_Normalized_Waveguide_Filters.html
459 // https://ccrma.stanford.edu/~jos/pasp/Digital_Waveguide_Oscillator.html
460 //
461 wgr(f,r,x) = (*(G),_<:_,((+:*(C))<:_,_),_:+,_,_:+(x),-) ~ cross : _,*(0-gi)
462 with {
463 C = cos(2*PI*f/SR);
464 gi = sqrt(max(0,(1+C)/(1-C))); // compensate amplitude (only needed when
465 G = r*(1-1 + gi)/gi; // frequency changes substantially)
466 cross = _,_ <: !,_,_,!;
467 };
468
469 //----------------------------- nlf2 --------------------------------
470 // Second order normalized digital waveguide resonator
471 // USAGE:
472 // _ : nlf2(f,r) : _
473 // where
474 // f = resonance frequency (Hz)
475 // r = loss factor for exponential decay
476 // (set to 1 to make a sinusoidal oscillator)
477 //
478 // REFERENCE:
479 // https://ccrma.stanford.edu/~jos/pasp/Power_Normalized_Waveguide_Filters.html
38
480 //
481 nlf2(f,r,x) = ((_<:_,_),(_<:_,_) : (*(s),*(c),*(c),*(0-s)) :>
482 (*(r),+(x))) ~ cross
483 with {
484 th = 2*PI*f/SR;
485 c = cos(th);
486 s = sin(th);
487 cross = _,_ <: !,_,_,!;
488 };
489
490 //===================== Ladder/Lattice Allpass Filters ======================
491 // An allpass filter has gain 1 at every frequency, but variable phase.
492 // Ladder/lattice allpass filters are specified by reflection coefficients.
493 // They are defined here as nested allpass filters, hence the names allpassn*.
494 //
495 // REFERENCES
496 // 1. https://ccrma.stanford.edu/~jos/pasp/Conventional_Ladder_Filters.html
497 // https://ccrma.stanford.edu/~jos/pasp/Nested_Allpass_Filters.html
498 // 2. Linear Prediction of Speech, Markel and Gray, Springer Verlag, 1976
499 //
500 // QUICK GUIDE
501 // allpassn - two-multiply lattice - each section is two multiply-adds
502 // allpassnn - normalized form - four multiplies and two adds per section,
503 // but coefficients can be time varying and nonlinear without
504 // "parametric amplification" (modulation of signal energy).
505 // allpassnkl - Kelly-Lochbaum form - four multiplies and two adds per
506 // section, but all signals have an immediate physical
507 // interpretation as traveling pressure waves, etc.
508 // allpassn1m - One-multiply form - one multiply and three adds per section.
509 // Normally the most efficient in special-purpose hardware.
510 //
511 // TYPICAL USAGE
512 // _ : allpassn(N,sv) : _
513 // where
514 // N = allpass order (number of ladder or lattice sections)
515 // sv = (s1,s2,...,sN) = reflection coefficients (between -1 and 1).
516 // For allpassnn only, sv is replaced by tv, where sv(i) = sin(tv(i)),
517 // where tv(i) may range between -PI and PI.
518 //
519 // two-multiply:
520 allpassn(0,sv) = _;
521 allpassn(n,sv) = _ <: ((+ <: (allpassn(n-1,sv)),*(s))~(*(-s))) : _,_ :+
522 with { s = take(n,sv); };
523
524 // power-normalized (reflection coefficients s = sin(t)):
525 allpassnn(0,tv) = _;
526 allpassnn(n,tv) = _ <: *(s), (*(c) : (+
527 : allpassnn(n-1,tv))~(*(-s))) : _, mem*c : +
528 with { c=cos(take(n,tv)); s=sin(take(n,tv)); };
529
530 // power-normalized with sparse delays dv(n)>1:
531 allpassnns(0,tv,dmax,dv) = _;
532 allpassnns(n,tv,dmax,dv) = _ <: *(s), (*(c) : (+ : dl
533 : allpassnns(n-1,tv,dmax,dv))~(*(-s))) : _, mem*c : +
534 with { c=cos(take(n,tv)); s=sin(take(n,tv));
535 dl=delay(dmax,(take(n,dv)-1)); };
536
537 // Kelly-Lochbaum:
538 allpassnkl(0,sv) = _;
539 allpassnkl(n,sv) = _ <: *(s),(*(1+s) : (+
540 : allpassnkl(n-1,sv))~(*(-s))) : _, mem*(1-s) : +
541 with { s = take(n,sv); };
542
543 // one-multiply:
544 allpassn1m(0,sv) = _;
545 allpassn1m(n,sv)= _ <: _,_ : ((+:*(s) <: _,_),_ : _,+ : cross
546 : allpassn1m(n-1,sv),_)~(*(-1)) : _,_ : +
547 with {s = take(n,sv); cross = _,_ <: !,_,_,!; };
39
548
549 //===== Digital Filter Sections Specified as Analog Filter Sections =====
550 //
551 //------------------------- tf2s, tf2snp --------------------------------
552 // Second-order direct-form digital filter,
553 // specified by ANALOG transfer-function polynomials B(s)/A(s),
554 // and a frequency-scaling parameter. Digitization via the
555 // bilinear transform is built in.
556 //
557 // USAGE: tf2s(b2,b1,b0,a1,a0,w1), where
558 //
559 // b2 s^2 + b1 s + b0
560 // H(s) = --------------------
561 // s^2 + a1 s + a0
562 //
563 // and w1 is the desired digital frequency (in radians/second)
564 // corresponding to analog frequency 1 rad/sec (i.e., s = j).
565 //
566 // EXAMPLE: A second-order ANALOG Butterworth lowpass filter,
567 // normalized to have cutoff frequency at 1 rad/sec,
568 // has transfer function
569 //
570 // 1
571 // H(s) = -----------------
572 // s^2 + a1 s + 1
573 //
574 // where a1 = sqrt(2). Therefore, a DIGITAL Butterworth lowpass
575 // cutting off at SR/4 is specified as tf2s(0,0,1,sqrt(2),1,PI*SR/2);
576 //
577 // METHOD: Bilinear transform scaled for exact mapping of w1.
578 // REFERENCE:
579 // https://ccrma.stanford.edu/~jos/pasp/Bilinear_Transformation.html
580 //
581 tf2s(b2,b1,b0,a1,a0,w1) = tf2(b0d,b1d,b2d,a1d,a2d)
582 with {
583 c = 1/tan(w1*0.5/SR); // bilinear-transform scale-factor
584 csq = c*c;
585 d = a0 + a1 * c + csq;
586 b0d = (b0 + b1 * c + b2 * csq)/d;
587 b1d = 2 * (b0 - b2 * csq)/d;
588 b2d = (b0 - b1 * c + b2 * csq)/d;
589 a1d = 2 * (a0 - csq)/d;
590 a2d = (a0 - a1*c + csq)/d;
591 };
592
593 // tf2snp = tf2s but using a protected normalized ladder filter for tf2:
594 tf2snp(b2,b1,b0,a1,a0,w1) = tf2np(b0d,b1d,b2d,a1d,a2d)
595 with {
596 c = 1/tan(w1*0.5/SR); // bilinear-transform scale-factor
597 csq = c*c;
598 d = a0 + a1 * c + csq;
599 b0d = (b0 + b1 * c + b2 * csq)/d;
600 b1d = 2 * (b0 - b2 * csq)/d;
601 b2d = (b0 - b1 * c + b2 * csq)/d;
602 a1d = 2 * (a0 - csq)/d;
603 a2d = (a0 - a1*c + csq)/d;
604 };
605
606 //----------------------------- tf1s --------------------------------
607 // First-order direct-form digital filter,
608 // specified by ANALOG transfer-function polynomials B(s)/A(s),
609 // and a frequency-scaling parameter.
610 //
611 // USAGE: tf1s(b1,b0,a0,w1), where
612 //
613 // b1 s + b0
614 // H(s) = ----------
615 // s + a0
40
616 //
617 // and w1 is the desired digital frequency (in radians/second)
618 // corresponding to analog frequency 1 rad/sec (i.e., s = j).
619 //
620 // EXAMPLE: A first-order ANALOG Butterworth lowpass filter,
621 // normalized to have cutoff frequency at 1 rad/sec,
622 // has transfer function
623 //
624 // 1
625 // H(s) = -------
626 // s + 1
627 //
628 // so b0 = a0 = 1 and b1 = 0. Therefore, a DIGITAL first-order
629 // Butterworth lowpass with gain -3dB at SR/4 is specified as
630 //
631 // tf1s(0,1,1,PI*SR/2); // digital half-band order 1 Butterworth
632 //
633 // METHOD: Bilinear transform scaled for exact mapping of w1.
634 // REFERENCE:
635 // https://ccrma.stanford.edu/~jos/pasp/Bilinear_Transformation.html
636 //
637 tf1s(b1,b0,a0,w1) = tf1(b0d,b1d,a1d)
638 with {
639 c = 1/tan((w1)*0.5/SR); // bilinear-transform scale-factor
640 d = a0 + c;
641 b1d = (b0 - b1*c) / d;
642 b0d = (b0 + b1*c) / d;
643 a1d = (a0 - c) / d;
644 };
645
646 //----------------------------- tf2sb --------------------------------
647 // Bandpass mapping of tf2s: In addition to a frequency-scaling parameter
648 // w1 (set to HALF the desired passband width in rad/sec),
649 // there is a desired center-frequency parameter wc (also in rad/s).
650 // Thus, tf2sb implements a fourth-order digital bandpass filter section
651 // specified by the coefficients of a second-order analog lowpass prototpe
652 // section. Such sections can be combined in series for higher orders.
653 // The order of mappings is (1) frequency scaling (to set lowpass cutoff w1),
654 // (2) bandpass mapping to wc, then (3) the bilinear transform, with the
655 // usual scale parameter 2*SR. Algebra carried out in maxima and pasted here.
656 //
657 tf2sb(b2,b1,b0,a1,a0,w1,wc) =
658 iir((b0d/a0d,b1d/a0d,b2d/a0d,b3d/a0d,b4d/a0d),(a1d/a0d,a2d/a0d,a3d/a0d,a4d/a0d)) with {
659 T = 1.0/float(SR);
660 b0d = (4*b0*w1^2+8*b2*wc^2)*T^2+8*b1*w1*T+16*b2;
661 b1d = 4*b2*wc^4*T^4+4*b1*wc^2*w1*T^3-16*b1*w1*T-64*b2;
662 b2d = 6*b2*wc^4*T^4+(-8*b0*w1^2-16*b2*wc^2)*T^2+96*b2;
663 b3d = 4*b2*wc^4*T^4-4*b1*wc^2*w1*T^3+16*b1*w1*T-64*b2;
664 b4d = (b2*wc^4*T^4-2*b1*wc^2*w1*T^3+(4*b0*w1^2+8*b2*wc^2)*T^2-8*b1*w1*T +16*b2)
665 + b2*wc^4*T^4+2*b1*wc^2*w1*T^3;
666 a0d = wc^4*T^4+2*a1*wc^2*w1*T^3+(4*a0*w1^2+8*wc^2)*T^2+8*a1*w1*T+16;
667 a1d = 4*wc^4*T^4+4*a1*wc^2*w1*T^3-16*a1*w1*T-64;
668 a2d = 6*wc^4*T^4+(-8*a0*w1^2-16*wc^2)*T^2+96;
669 a3d = 4*wc^4*T^4-4*a1*wc^2*w1*T^3+16*a1*w1*T-64;
670 a4d = wc^4*T^4-2*a1*wc^2*w1*T^3+(4*a0*w1^2+8*wc^2)*T^2-8*a1*w1*T+16;
671 };
672
673 //----------------------------- tf1sb --------------------------------
674 // First-to-second-order lowpass-to-bandpass section mapping,
675 // analogous to tf2sb above.
676 //
677 tf1sb(b1,b0,a0,w1,wc) = tf2(b0d/a0d,b1d/a0d,b2d/a0d,a1d/a0d,a2d/a0d) with {
678 T = 1.0/float(SR);
679 a0d = wc^2*T^2+2*a0*w1*T+4;
680 b0d = b1*wc^2*T^2 +2*b0*w1*T+4*b1;
681 b1d = 2*b1*wc^2*T^2-8*b1;
682 b2d = b1*wc^2*T^2-2*b0*w1*T+4*b1;
683 a1d = 2*wc^2*T^2-8;
41
684 a2d = wc^2*T^2-2*a0*w1*T+4;
685 };
686
687 //====================== Simple Resonator Filters ======================
688
689 // resonlp = 2nd-order lowpass with corner resonance:
690 resonlp(fc,Q,gain) = tf2s(b2,b1,b0,a1,a0,wc)
691 with {
692 wc = 2*PI*fc;
693 a1 = 2/Q;
694 a0 = 1;
695 b2 = 0;
696 b1 = 0;
697 b0 = gain;
698 };
699
700 // resonhp = 2nd-order highpass with corner resonance:
701 resonhp(fc,Q,gain,x) = gain*x-resonlp(fc,Q,gain,x);
702
703 // resonbp = 2nd-order bandpass
704 resonbp(fc,Q,gain) = tf2s(b2,b1,b0,a1,a0,wc)
705 with {
706 wc = 2*PI*fc;
707 a1 = 2/Q;
708 a0 = 1;
709 b2 = 0;
710 b1 = gain;
711 b0 = 0;
712 };
713
714 //================ Butterworth Lowpass/Highpass Filters ======================
715 // Nth-order Butterworth lowpass or highpass filters
716 //
717 // USAGE:
718 // _ : lowpass(N,fc) : _
719 // _ : highpass(N,fc) : _
720 // where
721 // N = filter order (number of poles) [nonnegative integer]
722 // fc = desired cut-off frequency (-3dB frequency) in Hz
723 // REFERENCE:
724 // https://ccrma.stanford.edu/~jos/filters/Butterworth_Lowpass_Design.html
725 // butter function in Octave ("[z,p,g] = butter(N,1,s);")
726 // ACKNOWLEDGMENT
727 // Generalized recursive formulation initiated by Yann Orlarey.
728
729 lowpass(N,fc) = lowpass0_highpass1(0,N,fc);
730 highpass(N,fc) = lowpass0_highpass1(1,N,fc);
731 lowpass0_highpass1(s,N,fc) = lphpr(s,N,N,fc)
732 with {
733 lphpr(s,0,N,fc) = _;
734 lphpr(s,1,N,fc) = tf1s(s,1-s,1,2*PI*fc);
735 lphpr(s,O,N,fc) = lphpr(s,(O-2),N,fc) : tf2s(s,0,1-s,a1s,1,w1) with {
736 parity = N % 2;
737 S = (O-parity)/2; // current section number
738 a1s = -2*cos(-PI + (1-parity)*PI/(2*N) + (S-1+parity)*PI/N);
739 w1 = 2*PI*fc;
740 };
741 };
742
743 //========== Special Filter-Bank Delay-Equalizing Allpass Filters ===========
744 //
745 // These special allpass filters are needed by filterbank et al. below.
746 // They are equivalent to (lowpass(N,fc) +|- highpass(N,fc))/2, but with
747 // canceling pole-zero pairs removed (which occurs for odd N).
748
749 //-------------------- lowpass_plus|minus_highpass ------------------
750
751 highpass_plus_lowpass(1,fc) = _;
42
752 highpass_plus_lowpass(3,fc) = tf2s(1,-1,1,1,1,w1) with { w1 = 2*PI*fc; };
753 highpass_minus_lowpass(3,fc) = tf1s(-1,1,1,w1) with { w1 = 2*PI*fc; };
754 highpass_plus_lowpass(5,fc) = tf2s(1,-a11,1,a11,1,w1)
755 with {
756 a11 = 1.618033988749895;
757 w1 = 2*PI*fc;
758 };
759 highpass_minus_lowpass(5,fc) = tf1s(1,-1,1,w1) : tf2s(1,-a12,1,a12,1,w1)
760 with {
761 a12 = 0.618033988749895;
762 w1 = 2*PI*fc;
763 };
764
765 // Catch-all definitions for generality - even order is done:
766
767 highpass_plus_lowpass(N,fc) = switch_odd_even(N%2,N,fc) with {
768 switch_odd_even(0,N,fc) = highpass_plus_lowpass_even(N,fc);
769 switch_odd_even(1,N,fc) = highpass_plus_lowpass_odd(N,fc);
770 };
771
772 highpass_minus_lowpass(N,fc) = switch_odd_even(N%2,N,fc) with {
773 switch_odd_even(0,N,fc) = highpass_minus_lowpass_even(N,fc);
774 switch_odd_even(1,N,fc) = highpass_minus_lowpass_odd(N,fc);
775 };
776
777 highpass_plus_lowpass_even(N,fc) = highpass(N,fc) + lowpass(N,fc);
778 highpass_minus_lowpass_even(N,fc) = highpass(N,fc) - lowpass(N,fc);
779
780 // FIXME: Rewrite the following, as for orders 3 and 5 above,
781 // to eliminate pole-zero cancellations:
782 highpass_plus_lowpass_odd(N,fc) = highpass(N,fc) + lowpass(N,fc);
783 highpass_minus_lowpass_odd(N,fc) = highpass(N,fc) - lowpass(N,fc);
784
785 //===================== Elliptic (Cauer) Lowpass Filters ===================
786 // USAGE:
787 // _ : lowpass3e(fc) : _
788 // _ : lowpass6e(fc) : _
789 // where fc = -3dB frequency in Hz
790 //
791 // REFERENCES:
792 // http://en.wikipedia.org/wiki/Elliptic_filter
793 // functions ncauer and ellip in Octave
794
795 //----------------------------- lowpass3e -----------------------------
796 // Third-order Elliptic (Cauer) lowpass filter
797 // DESIGN: For spectral band-slice level display (see octave_analyzer3e):
798 // [z,p,g] = ncauer(Rp,Rs,3); % analog zeros, poles, and gain, where
799 // Rp = 60 % dB ripple in stopband
800 // Rs = 0.2 % dB ripple in passband
801 //
802 lowpass3e(fc) = tf2s(b21,b11,b01,a11,a01,w1) : tf1s(0,1,a02,w1)
803 with {
804 a11 = 0.802636764161030; // format long; poly(p(1:2)) % in octave
805 a01 = 1.412270893774204;
806 a02 = 0.822445908998816; // poly(p(3)) % in octave
807 b21 = 0.019809144837789; // poly(z)
808 b11 = 0;
809 b01 = 1.161516418982696;
810 w1 = 2*PI*fc;
811 };
812
813 //----------------------------- lowpass6e -----------------------------
814 // Sixth-order Elliptic/Cauer lowpass filter
815 // DESIGN: For spectral band-slice level display (see octave_analyzer6e):
816 // [z,p,g] = ncauer(Rp,Rs,6); % analog zeros, poles, and gain, where
817 // Rp = 80 % dB ripple in stopband
818 // Rs = 0.2 % dB ripple in passband
819 //
43
820 lowpass6e(fc) =
821 tf2s(b21,b11,b01,a11,a01,w1) :
822 tf2s(b22,b12,b02,a12,a02,w1) :
823 tf2s(b23,b13,b03,a13,a03,w1)
824 with {
825 b21 = 0.000099999997055;
826 a21 = 1;
827 b11 = 0;
828 a11 = 0.782413046821645;
829 b01 = 0.000433227200555;
830 a01 = 0.245291508706160;
831 b22 = 1;
832 a22 = 1;
833 b12 = 0;
834 a12 = 0.512478641889141;
835 b02 = 7.621731298870603;
836 a02 = 0.689621364484675;
837 b23 = 1;
838 a23 = 1;
839 b13 = 0;
840 a13 = 0.168404871113589;
841 b03 = 53.536152954556727;
842 a03 = 1.069358407707312;
843 w1 = 2*PI*fc;
844 };
845
846 //===================== Elliptic Highpass Filters =====================
847 // USAGE:
848 // _ : highpass3e(fc) : _
849 // _ : highpass6e(fc) : _
850 // where fc = -3dB frequency in Hz
851
852 //----------------------------- highpass3e -----------------------------
853 // Third-order Elliptic (Cauer) highpass filter
854 // DESIGN: Inversion of lowpass3e wrt unit circle in s plane (s <- 1/s)
855 //
856 highpass3e(fc) = tf2s(b01/a01,b11/a01,b21/a01,a11/a01,1/a01,w1) :
857 tf1s(1/a02,0,1/a02,w1)
858 with {
859 a11 = 0.802636764161030;
860 a01 = 1.412270893774204;
861 a02 = 0.822445908998816;
862 b21 = 0.019809144837789;
863 b11 = 0;
864 b01 = 1.161516418982696;
865 w1 = 2*PI*fc;
866 };
867
868 //----------------------------- highpass6e -----------------------------
869 // Sixth-order Elliptic/Cauer highpass filter
870 // METHOD: Inversion of lowpass3e wrt unit circle in s plane (s <- 1/s)
871 //
872 highpass6e(fc) =
873 tf2s(b01/a01,b11/a01,b21/a01,a11/a01,1/a01,w1) :
874 tf2s(b02/a02,b12/a02,b22/a02,a12/a02,1/a02,w1) :
875 tf2s(b03/a03,b13/a03,b23/a03,a13/a03,1/a03,w1)
876 with {
877 b21 = 0.000099999997055;
878 a21 = 1;
879 b11 = 0;
880 a11 = 0.782413046821645;
881 b01 = 0.000433227200555;
882 a01 = 0.245291508706160;
883 b22 = 1;
884 a22 = 1;
885 b12 = 0;
886 a12 = 0.512478641889141;
887 b02 = 7.621731298870603;
44
888 a02 = 0.689621364484675;
889 b23 = 1;
890 a23 = 1;
891 b13 = 0;
892 a13 = 0.168404871113589;
893 b03 = 53.536152954556727;
894 a03 = 1.069358407707312;
895 w1 = 2*PI*fc;
896 };
897
898 //================== Butterworth Bandpass/Bandstop Filters =====================
899 // Order 2*Nh Butterworth bandpass filter made using the transformation
900 // s <- s + wc^2/s on lowpass(Nh), where wc is the desired bandpass center
901 // frequency. The lowpass(Nh) cutoff w1 is half the desired bandpass width.
902 // A notch-like "bandstop" filter is similarly made from highpass(Nh).
903 //
904 // USAGE:
905 // _ : bandpass(Nh,fl,fu) : _
906 // _ : bandstop(Nh,fl,fu) : _
907 // where
908 // Nh = HALF the desired bandpass/bandstop order (which is therefore even)
909 // fl = lower -3dB frequency in Hz
910 // fu = upper -3dB frequency in Hz
911 // Thus, the passband (stopband) width is fu-fl,
912 // and its center frequency is (fl+fu)/2.
913 //
914 // REFERENCE:
915 // http://cnx.org/content/m16913/latest/
916 //
917 bandpass(Nh,fl,fu) = bandpass0_bandstop1(0,Nh,fl,fu);
918 bandstop(Nh,fl,fu) = bandpass0_bandstop1(1,Nh,fl,fu);
919 bandpass0_bandstop1(s,Nh,fl,fu) = bpbsr(s,Nh,Nh,fl,fu)
920 with {
921 wl = 2*PI*fl; // digital (z-plane) lower passband edge
922 wu = 2*PI*fu; // digital (z-plane) upper passband edge
923
924 c = 2.0*SR; // bilinear transform scaling used in tf2sb, tf1sb
925 wla = c*tan(wl/c); // analog (s-splane) lower cutoff
926 wua = c*tan(wu/c); // analog (s-splane) upper cutoff
927
928 wc = sqrt(wla*wua); // s-plane center frequency
929 w1 = wua - wc^2/wua; // s-plane lowpass prototype cutoff
930
931 bpbsr(s,0,Nh,fl,fu) = _;
932 bpbsr(s,1,Nh,fl,fu) = tf1sb(s,1-s,1,w1,wc);
933 bpbsr(s,O,Nh,fl,fu) = bpbsr(s,O-2,Nh,fl,fu) : tf2sb(s,0,(1-s),a1s,1,w1,wc)
934 with {
935 parity = Nh % 2;
936 S = (O-parity)/2; // current section number
937 a1s = -2*cos(-PI + (1-parity)*PI/(2*Nh) + (S-1+parity)*PI/Nh);
938 };
939 };
940
941 //======================= Elliptic Bandpass Filters ============================
942
943 //----------------------------- bandpass6e -----------------------------
944 // Order 12 elliptic bandpass filter analogous to bandpass(6) above.
945 //
946 bandpass6e(fl,fu) = tf2sb(b21,b11,b01,a11,a01,w1,wc) : tf1sb(0,1,a02,w1,wc)
947 with {
948 a11 = 0.802636764161030; // In octave: format long; poly(p(1:2))
949 a01 = 1.412270893774204;
950 a02 = 0.822445908998816; // poly(p(3))
951 b21 = 0.019809144837789; // poly(z)
952 b11 = 0;
953 b01 = 1.161516418982696;
954
955 wl = 2*PI*fl; // digital (z-plane) lower passband edge
45
956 wu = 2*PI*fu; // digital (z-plane) upper passband edge
957
958 c = 2.0*SR; // bilinear transform scaling used in tf2sb, tf1sb
959 wla = c*tan(wl/c); // analog (s-splane) lower cutoff
960 wua = c*tan(wu/c); // analog (s-splane) upper cutoff
961
962 wc = sqrt(wla*wua); // s-plane center frequency
963 w1 = wua - wc^2/wua; // s-plane lowpass cutoff
964 };
965
966 //----------------------------- bandpass12e -----------------------------
967
968 bandpass12e(fl,fu) =
969 tf2sb(b21,b11,b01,a11,a01,w1,wc) :
970 tf2sb(b22,b12,b02,a12,a02,w1,wc) :
971 tf2sb(b23,b13,b03,a13,a03,w1,wc)
972 with { // octave script output:
973 b21 = 0.000099999997055;
974 a21 = 1;
975 b11 = 0;
976 a11 = 0.782413046821645;
977 b01 = 0.000433227200555;
978 a01 = 0.245291508706160;
979 b22 = 1;
980 a22 = 1;
981 b12 = 0;
982 a12 = 0.512478641889141;
983 b02 = 7.621731298870603;
984 a02 = 0.689621364484675;
985 b23 = 1;
986 a23 = 1;
987 b13 = 0;
988 a13 = 0.168404871113589;
989 b03 = 53.536152954556727;
990 a03 = 1.069358407707312;
991
992 wl = 2*PI*fl; // digital (z-plane) lower passband edge
993 wu = 2*PI*fu; // digital (z-plane) upper passband edge
994
995 c = 2.0*SR; // bilinear transform scaling used in tf2sb, tf1sb
996 wla = c*tan(wl/c); // analog (s-splane) lower cutoff
997 wua = c*tan(wu/c); // analog (s-splane) upper cutoff
998
999 wc = sqrt(wla*wua); // s-plane center frequency
1000 w1 = wua - wc^2/wua; // s-plane lowpass cutoff
1001 };
1002
1003 //================= Parametric Equalizers (Shelf, Peaking) ==================
1004 // REFERENCES
1005 // - http://en.wikipedia.org/wiki/Equalization
1006 // - Digital Audio Signal Processing, Udo Zolzer, Wiley, 1999, p. 124
1007 // - http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
1008 // http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
1009 // - https://ccrma.stanford.edu/~jos/filters/Low_High_Shelving_Filters.html
1010 // - https://ccrma.stanford.edu/~jos/filters/Peaking_Equalizers.html
1011 // - maxmsp.lib in the Faust distribution
1012 // - bandfilter.dsp in the faust2pd distribution
1013
1014 //----------------------------- low_shelf ------------------------------------
1015 // First-order "low shelf" filter (gain boost|cut between dc and some frequency)
1016 // USAGE: lowshelf(L0,fx), where
1017 // L0 = desired boost (dB) between dc and fx
1018 // fx = desired transition frequency (Hz) from boost to unity gain
1019 // The gain at SR/2 is constrained to be 1.
1020 //
1021 low_shelf = low_shelf3; // default
1022 low_shelf1(L0,fx,x) = x + (db2linear(L0)-1)*lowpass(1,fx,x);
1023 low_shelf1_l(G0,fx,x) = x + (G0-1)*lowpass(1,fx,x);
46
1024 low_shelf3(L0,fx,x) = x + (db2linear(L0)-1)*lowpass(3,fx,x);
1025 low_shelf5(L0,fx,x) = x + (db2linear(L0)-1)*lowpass(5,fx,x);
1026
1027 //----------------------------- high_shelf -----------------------------------
1028 // First-order "high shelf" filter (gain boost|cut above some frequency)
1029 //
1030 // USAGE: high_shelf(Lpi,fx), where
1031 // Lpi = desired boost or cut (dB) between fx and SR/2
1032 // fx = desired transition frequency in Hz
1033 // The gain at dc is constrained to be 1
1034 //
1035 high_shelf=high_shelf3; //default
1036 high_shelf1(Lpi,fx,x) = x + (db2linear(Lpi)-1)*highpass(1,fx,x);
1037 high_shelf1_l(Gpi,fx,x) = x + (Gpi-1)*highpass(1,fx,x);
1038 high_shelf3(Lpi,fx,x) = x + (db2linear(Lpi)-1)*highpass(3,fx,x);
1039 high_shelf5(Lpi,fx,x) = x + (db2linear(Lpi)-1)*highpass(5,fx,x);
1040
1041 //-------------------------------- peak_eq -----------------------------------
1042 // Second order "peaking equalizer" section
1043 // (gain boost or cut near some frequency)
1044 // Also called a "parametric equalizer" section
1045 // USAGE: _ : peak_eq(Lfx,fx,B) : _;
1046 // where
1047 // Lfx = level (dB) at fx
1048 // fx = peak frequency (Hz)
1049 // B = bandwidth (B) of peak in Hz
1050 //
1051 peak_eq(Lfx,fx,B) = tf2s(1,b1s,1,a1s,1,wx) with {
1052 T = float(1.0/SR);
1053 Bw = B*T/sin(wx*T); // prewarp s-bandwidth for more accuracy in z-plane
1054 a1 = PI*Bw;
1055 b1 = g*a1;
1056 g = db2linear(abs(Lfx));
1057 b1s = select2(Lfx>0,a1,b1); // When Lfx>0, pole dominates bandwidth
1058 a1s = select2(Lfx>0,b1,a1); // When Lfx<0, zero dominates
1059 wx = 2*PI*fx;
1060 };
1061
1062 //------------------------------- peak_eq_cq ---------------------------------
1063 // Constant-Q second order peaking equalizer section
1064 // USAGE: _ : peak_eq_cq(Lfx,fx,Q) : _;
1065 // where
1066 // Lfx = level (dB) at fx
1067 // fx = boost or cut frequency (Hz)
1068 // Q = "Quality factor" = fx/B where B = bandwidth of peak in Hz
1069 //
1070 peak_eq_cq(Lfx,fx,Q) = peak_eq(Lfx,fx,fx/Q);
1071
1072 //------------------------------- peak_eq_rm ---------------------------------
1073 // Regalia-Mitra second order peaking equalizer section
1074 // USAGE: _ : peak_eq_rm(Lfx,fx,tanPiBT) : _;
1075 // where
1076 // Lfx = level (dB) at fx
1077 // fx = boost or cut frequency (Hz)
1078 // tanPiBT = tan(PI*B/SR), where B = -3dB bandwidth (Hz) when 10^(Lfx/20) = 0
1079 // ~ PI*B/SR for narrow bandwidths B
1080 //
1081 // REFERENCE:
1082 // P.A. Regalia, S.K. Mitra, and P.P. Vaidyanathan,
1083 // "The Digital All-Pass Filter: A Versatile Signal Processing Building Block"
1084 // Proceedings of the IEEE, 76(1):19-37, Jan. 1988. (See pp. 29-30.)
1085 //
1086 peak_eq_rm(Lfx,fx,tanPiBT) = _ <: _,A,_ : +,- : *(0.5),*(K/2.0) : + with {
1087 A = tf2(k2, k1*(1+k2), 1, k1*(1+k2), k2) <: _,_; // allpass
1088 k1 = 0.0 - cos(2.0*PI*fx/SR);
1089 k2 = (1.0 - tanPiBT)/(1.0 + tanPiBT);
1090 K = db2linear(Lfx);
1091 };
47
1092
1093 //-------------------------- parametric_eq_demo ------------------------------
1094 // USAGE: _ : parametric_eq_demo: _ ;
1095 parametric_eq_demo = // input_signal :
1096 low_shelf(LL,FL) :
1097 peak_eq(LP,FP,BP) :
1098 high_shelf(LH,FH)
1099 // Recommended:
1100 // : mth_octave_spectral_level_demo(2) // half-octave spectrum analyzer
1101 with {
1102 eq_group(x) = hgroup("[0] PARAMETRIC EQ SECTIONS
1103 [tooltip: See Fausts filter.lib for info and pointers]",x);
1104
1105 ls_group(x) = eq_group(vgroup("[1] Low Shelf",x));
1106 LL = ls_group(hslider("[0] Low Boost|Cut [unit:dB] [style:knob]
1107 [tooltip: Amount of low-frequency boost or cut in decibels]",
1108 0,-40,40,0.1));
1109 FL = ls_group(hslider("[1] Transition Frequency [unit:Hz] [style:knob]
1110 [tooltip: Transition-frequency from boost (cut) to unity gain]",
1111 200,1,5000,1));
1112
1113 pq_group(x) = eq_group(vgroup("[2] Peaking Equalizer
1114 [tooltip: Parametric Equalizer sections from filter.lib]",x));
1115 LP = pq_group(hslider("[0] Peak Boost|Cut [unit:dB] [style:knob]
1116 [tooltip: Amount of local boost or cut in decibels]",
1117 0,-40,40,0.1));
1118 FP = pq_group(hslider("[1] Peak Frequency [unit:PK] [style:knob]
1119 [tooltip: Peak Frequency in Piano Key (PK) units (A-440= 49 PK)]",
1120 49,1,100,1)) : smooth(0.999) : pianokey2hz
1121 with { pianokey2hz(x) = 440.0*pow(2.0, (x-49.0)/12); };
1122
1123 Q = pq_group(hslider("[2] Peak Q [style:knob]
1124 [tooltip: Quality factor (Q) of the peak = center-frequency/bandwidth]",
1125 40,1,50,0.1));
1126
1127 BP = FP/Q;
1128
1129 hs_group(x) = eq_group(vgroup("[3] High Shelf
1130 [tooltip: A high shelf provides a boost or cut
1131 above some frequency]",x));
1132 LH = hs_group(hslider("[0] High Boost|Cut [unit:dB] [style:knob]
1133 [tooltip: Amount of high-frequency boost or cut in decibels]",
1134 0,-40,40,.1));
1135 FH = hs_group(hslider("[1] Transition Frequency [unit:Hz] [style:knob]
1136 [tooltip: Transition-frequency from boost (cut) to unity gain]",
1137 8000,20,10000,1));
1138 };
1139
1140 //========================= Lagrange Interpolation ========================
1141 // Reference:
1142 // https://ccrma.stanford.edu/~jos/pasp/Lagrange_Interpolation.html
1143 //
1144 //------------------ fdelay1, fdelay2, fdelay3, fdelay4 ---------------
1145 // Delay lines interpolated using Lagrange interpolation
1146 // USAGE: _ : fdelayN(maxdelay, delay, inputsignal) : _
1147 // (exactly like fdelay in music.lib)
1148 // where N=1,2,3, or 4 is the order of the Lagrange interpolation polynomial.
1149 //
1150 // NOTE: requested delay should not be less than (N-1)/2.
1151 //
1152 // NOTE: While the implementations below appear to use multiple delay lines,
1153 // they in fact use only one thanks to optimization by the Faust compiler.
1154
1155 // first-order case (linear interpolation) - equivalent to fdelay in music.lib
1156 // delay d in [0,1]
1157 fdelay1(n,d,x) = delay(n,id,x)*(1 - fd) + delay(n,id+1,x)*fd
1158 with {
1159 id = int(d);
48
1160 fd = frac(d);
1161 };
1162
1163 // second-order (quadratic) case, delay in [0.5,1.5]
1164 // delay d should be at least 0.5
1165 fdelay2(n,d,x) = delay(n,id,x)*(1-fd)*(2-fd)/2
1166 + delay(n,id+1,x)*(2-fd)*fd
1167 + delay(n,id+2,x)*(fd-1)*fd/2
1168 with {
1169 o = 0.49999; // offset to make life easy for interpolator
1170 dmo = d - o; // assumed nonnegative
1171 id = int(dmo);
1172 fd = o + frac(dmo);
1173 };
1174
1175 // third-order (cubic) case, delay in [1,2]
1176 // delay d should be at least 1
1177 fdelay3(n,d,x) = delay(n,id,x) * (0-fdm1*fdm2*fdm3)/6
1178 + delay(n,id+1,x) * fd*fdm2*fdm3/2
1179 + delay(n,id+2,x) * (0-fd*fdm1*fdm3)/2
1180 + delay(n,id+3,x) * fd*fdm1*fdm2/6
1181 with {
1182 id = int(d-1);
1183 fd = 1+frac(d);
1184 fdm1 = fd-1;
1185 fdm2 = fd-2;
1186 fdm3 = fd-3;
1187 };
1188
1189 // fourth-order (quartic) case, delay in [1.5,2.5]
1190 // delay d should be at least 1.5
1191 fdelay4(n,d,x) = delay(n,id,x) * fdm1*fdm2*fdm3*fdm4/24
1192 + delay(n,id+1,x) * (0-fd*fdm2*fdm3*fdm4)/6
1193 + delay(n,id+2,x) * fd*fdm1*fdm3*fdm4/4
1194 + delay(n,id+3,x) * (0-fd*fdm1*fdm2*fdm4)/6
1195 + delay(n,id+4,x) * fd*fdm1*fdm2*fdm3/24
1196 with {
1197 //v1: o = 1;
1198 o = 1.49999;
1199 dmo = d - o; // assumed nonnegative
1200 id = int(dmo);
1201 fd = o + frac(dmo);
1202 fdm1 = fd-1;
1203 fdm2 = fd-2;
1204 fdm3 = fd-3;
1205 fdm4 = fd-4;
1206 };
1207
1208 // fifth-order case, delay in [2,3]
1209 // delay d should be at least 2
1210 fdelay5(n,d,x) =
1211 delay(n,id,x) * -fdm1*fdm2*fdm3*fdm4*fdm5/120
1212 + delay(n,id+1,x) * fd* fdm2*fdm3*fdm4*fdm5/24
1213 + delay(n,id+2,x) * -fd*fdm1* fdm3*fdm4*fdm5/12
1214 + delay(n,id+3,x) * fd*fdm1*fdm2* fdm4*fdm5/12
1215 + delay(n,id+4,x) * -fd*fdm1*fdm2*fdm3* fdm5/24
1216 + delay(n,id+5,x) * fd*fdm1*fdm2*fdm3*fdm4 /120
1217 with {
1218 //v1: o = 1;
1219 o = 1.99999;
1220 dmo = d - o; // assumed nonnegative
1221 id = int(dmo);
1222 fd = o + frac(dmo);
1223 fdm1 = fd-1;
1224 fdm2 = fd-2;
1225 fdm3 = fd-3;
1226 fdm4 = fd-4;
1227 fdm5 = fd-5;
49
1228 };
1229
1230 //====================== Thiran Allpass Interpolation =====================
1231 // Reference:
1232 // https://ccrma.stanford.edu/~jos/pasp/Thiran_Allpass_Interpolators.html
1233 //
1234 //---------------- fdelay1a, fdelay2a, fdelay3a, fdelay4a -------------
1235 // Delay lines interpolated using Thiran allpass interpolation
1236 // USAGE: fdelayNa(maxdelay, delay, inputsignal)
1237 // (exactly like fdelay in music.lib)
1238 // where N=1,2,3, or 4 is the order of the Thiran interpolation filter,
1239 // and the delay argument is at least N - 1/2.
1240 //
1241 // (Move the following and similar notes above to filter-lib-doc.txt?)
1242 //
1243 // NOTE: The interpolated delay should not be less than N - 1/2.
1244 // (The allpass delay ranges from N - 1/2 to N + 1/2.)
1245 // This constraint can be alleviated by altering the code,
1246 // but be aware that allpass filters approach zero delay
1247 // by means of pole-zero cancellations.
1248 // The delay range [N-1/2,N+1/2] is not optimal. What is?
1249 //
1250 // NOTE: Delay arguments too small will produce an UNSTABLE allpass!
1251 //
1252 // NOTE: Because allpass interpolation is recursive, it is not as robust
1253 // as Lagrange interpolation under time-varying conditions.
1254 // (You may hear clicks when changing the delay rapidly.)
1255 //
1256 // first-order allpass interpolation, allpass delay in [0.5,1.5]
1257 // delay d should be at least 0.5
1258 fdelay1a(n,d,x) = delay(n,id,x) : tf1(eta,1,eta)
1259 with {
1260 o = 0.49999; // offset to make life easy for allpass
1261 dmo = d - o; // assumed nonnegative
1262 id = int(dmo);
1263 fd = o + frac(dmo);
1264 eta = (1-fd)/(1+fd); // allpass coefficient
1265 };
1266
1267 // second-order allpass delay in [1.5,2.5]
1268 // delay d should be at least 1.5
1269 fdelay2a(n,d,x) = delay(n,id,x) : tf2(a2,a1,1,a1,a2)
1270 with {
1271 o = 1.49999;
1272 dmo = d - o; // delay range is [order-1/2, order+1/2]
1273 id = int(dmo);
1274 fd = o + frac(dmo);
1275 a1o2 = (2-fd)/(1+fd); // share some terms (the compiler does this anyway)
1276 a1 = 2*a1o2;
1277 a2 = a1o2*(1-fd)/(2+fd);
1278 };
1279
1280 // third-order allpass delay in [2.5,3.5]
1281 // delay d should be at least 2.5
1282 fdelay3a(n,d,x) = delay(n,id,x) : iir((a3,a2,a1,1),(a1,a2,a3))
1283 with {
1284 o = 2.49999;
1285 dmo = d - o;
1286 id = int(dmo);
1287 fd = o + frac(dmo);
1288 a1o3 = (3-fd)/(1+fd);
1289 a2o3 = a1o3*(2-fd)/(2+fd);
1290 a1 = 3*a1o3;
1291 a2 = 3*a2o3;
1292 a3 = a2o3*(1-fd)/(3+fd);
1293 };
1294
1295 // fourth-order allpass delay in [3.5,4.5]
50
1296 // delay d should be at least 3.5
1297 fdelay4a(n,d,x) = delay(n,id,x) : tf4(a4,a3,a2,a1,1,a1,a2,a3,a4)
1298 with {
1299 o = 3.49999;
1300 dmo = d - o;
1301 id = int(dmo);
1302 fd = o + frac(dmo);
1303 a1o4 = (4-fd)/(1+fd);
1304 a2o6 = a1o4*(3-fd)/(2+fd);
1305 a3o4 = a2o6*(2-fd)/(3+fd);
1306 a1 = 4*a1o4;
1307 a2 = 6*a2o6;
1308 a3 = 4*a3o4;
1309 a4 = a3o4*(1-fd)/(4+fd);
1310 };
1311
1312 //================ Mth-Octave Filter-Banks and Spectrum-Analyzers ============
1313 // Mth-octave filter-banks and spectrum-analyzers split the input signal into a
1314 // bank of parallel signals, one for each spectral band. The parameters are
1315 //
1316 // M = number of band-slices per octave (>1)
1317 // N = total number of bands (>2)
1318 // ftop = upper bandlimit of the Mth-octave bands (<SR/2)
1319 //
1320 // In addition to the Mth-octave output signals, there is a highpass signal
1321 // containing frequencies from ftop to SR/2, and a "dc band" lowpass signal
1322 // containing frequencies from 0 (dc) up to the start of the Mth-octave bands.
1323 // Thus, the N output signals are
1324 //
1325 // highpass(ftop), MthOctaveBands(M,N-2,ftop), dcBand(ftop*2^(-M*(N-1)))
1326 //
1327 // A FILTER-BANK is defined here as a signal bandsplitter having the
1328 // property that summing its output signals gives an allpass-filtered
1329 // version of the filter-bank input signal. A more conventional term for
1330 // this is an "allpass-complementary filter bank". If the allpass filter
1331 // is a pure delay (and possible scaling), the filter bank is said to be
1332 // a "perfect-reconstruction filter bank" (see Vaidyanathan-1993 cited
1333 // below for details). A "graphic equalizer", in which band signals
1334 // are scaled by gains and summed, should be based on a filter bank.
1335 //
1336 // A SPECTRUM-ANALYZER is defined here as any band-split whose bands span
1337 // the relevant spectrum, but whose band-signals do not
1338 // necessarily sum to the original signal, either exactly or to within an
1339 // allpass filtering. Spectrum analyzer outputs are normally at least nearly
1340 // "power complementary", i.e., the power spectra of the individual bands
1341 // sum to the original power spectrum (to within some negligible tolerance).
1342 //
1343 // The filter-banks below are implemented as Butterworth spectrum-analyzers
1344 // followed by delay equalizers that make them allpass-complementary.
1345 //
1346 // INCREASING CHANNEL ISOLATION
1347 // Go to higher filter orders - see Regalia et al. or Vaidyanathan (cited
1348 // below) regarding the construction of more aggressive recursive
1349 // filter-banks using elliptic or Chebyshev prototype filters.
1350 //
1351 // REFERENCES
1352 // - "Tree-structured complementary filter banks using all-pass sections",
1353 // Regalia et al., IEEE Trans. Circuits & Systems, CAS-34:1470-1484, Dec. 1987
1354 // - "Multirate Systems and Filter Banks", P. Vaidyanathan, Prentice-Hall, 1993
1355 // - Elementary filter theory: https://ccrma.stanford.edu/~jos/filters/
1356 //
1357 //------------------------- mth_octave_analyzer ----------------------------
1358 //
1359 // USAGE
1360 // _ : mth_octave_analyzer(O,M,ftop,N) : par(i,N,_); // Oth-order Butterworth
1361 // _ : mth_octave_analyzer6e(M,ftop,N) : par(i,N,_); // 6th-order elliptic
1362 //
1363 // where
51
1364 // O = order of filter used to split each frequency band into two
1365 // M = number of band-slices per octave
1366 // ftop = highest band-split crossover frequency (e.g., 20 kHz)
1367 // N = total number of bands (including dc and Nyquist)
1368 //
1369 // ACKNOWLEDGMENT
1370 // Recursive band-splitting formulation improved by Yann Orlarey.
1371
1372 mth_octave_analyzer6e(M,ftop,N) = _ <: bsplit(N-1) with {
1373 fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies
1374 lp(n) = lowpass6e(fc(n)); // 6th-order elliptic - see other choices above
1375 hp(n) = highpass6e(fc(n)); // (search for lowpass* and highpass*)
1376 bsplit(0) = _;
1377 bsplit(i) = hp(i), (lp(i) <: bsplit(i-1));
1378 };
1379
1380 // Butterworth analyzers may be cascaded with allpass
1381 // delay-equalizers to make (allpass-complementary) filter banks:
1382
1383 mth_octave_analyzer(O,M,ftop,N) = _ <: bsplit(N-1) with {
1384 fc(n) = ftop * 2^(float(n-N+1)/float(M));
1385 lp(n) = lowpass(O,fc(n)); // Order O Butterworth
1386 hp(n) = highpass(O,fc(n));
1387 bsplit(0) = _;
1388 bsplit(i) = hp(i), (lp(i) <: bsplit(i-1));
1389 };
1390
1391 mth_octave_analyzer3(M,ftop,N) = mth_octave_analyzer(3,M,ftop,N);
1392 mth_octave_analyzer5(M,ftop,N) = mth_octave_analyzer(5,M,ftop,N);
1393 mth_octave_analyzer_default = mth_octave_analyzer6e; // default analyzer
1394
1395 //------------------------ mth_octave_filterbank -------------------------
1396 // Allpass-complementary filter banks based on Butterworth band-splitting.
1397 // For Butterworth band-splits, the needed delay equalizer is easily found.
1398
1399 mth_octave_filterbank(O,M,ftop,N) =
1400 mth_octave_analyzer(O,M,ftop,N) :
1401 delayeq(N) with {
1402 fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies
1403 ap(n) = highpass_plus_lowpass(O,fc(n)); // delay-equalizing allpass
1404 delayeq(N) = par(i,N-2,apchain(i+1)), _, _;
1405 apchain(i) = seq(j,N-1-i,ap(j+1));
1406 };
1407
1408 // dc-inverted version. This reduces the delay-equalizer order for odd O.
1409 // Negating the input signal makes the dc band noninverting
1410 // and all higher bands sign-inverted (if preferred).
1411 mth_octave_filterbank_alt(O,M,ftop,N) =
1412 mth_octave_analyzer(O,M,ftop,N) : delayeqi(O,N) with {
1413 fc(n) = ftop * 2^(float(n-N+1)/float(M)); // -3dB crossover frequencies
1414 ap(n) = highpass_minus_lowpass(O,fc(n)); // half the order of plus case
1415 delayeqi(N) = par(i,N-2,apchain(i+1)), _, *(-1.0);
1416 apchain(i) = seq(j,N-1-i,ap(j+1));
1417 };
1418
1419 // Note that even-order cases require complex coefficients.
1420 // See Vaidyanathan 1993 and papers cited there for more info.
1421
1422 mth_octave_filterbank3(M,ftop,N) = mth_octave_filterbank_alt(3,M,ftop,N);
1423 mth_octave_filterbank5(M,ftop,N) = mth_octave_filterbank(5,M,ftop,N);
1424
1425 mth_octave_filterbank_default = mth_octave_filterbank5;
1426
1427 //======================= Mth-Octave Spectral Level =========================
1428 // Spectral Level: Display (in bar graphs) the average signal level in each
1429 // spectral band.
1430 //
1431 //------------------------ mth_octave_spectral_level -------------------------
52
1432 // USAGE: _ : mth_octave_spectral_level(M,ftop,NBands,tau,dB_offset);
1433 // where
1434 // M = bands per octave
1435 // ftop = lower edge frequency of top band
1436 // NBands = number of passbands (including highpass and dc bands),
1437 // tau = spectral display averaging-time (time constant) in seconds,
1438 // dB_offset = constant dB offset in all band level meters.
1439 //
1440 mth_octave_spectral_level6e(M,ftop,N,tau,dB_offset) = _<:
1441 _,mth_octave_analyzer6e(M,ftop,N) :
1442 _,(display:>_):attach with {
1443 display = par(i,N,dbmeter(i));
1444 dbmeter(i) = abs : smooth(tau2pole(tau)) : linear2db : +(dB_offset) :
1445 meter(N-i-1);
1446 meter(i) = speclevel_group(vbargraph("[%2i] [unit:dB]
1447 [tooltip: Spectral Band Level in dB]", -50, 10));
1448 // Can M be included in the label string somehow?
1449 speclevel_group(x) = hgroup("[0] CONSTANT-Q SPECTRUM ANALYZER (6E)
1450 [tooltip: See Fausts filter.lib for documentation and references]", x);
1451 };
1452
1453 mth_octave_spectral_level_default = mth_octave_spectral_level6e;
1454 spectral_level = mth_octave_spectral_level(2,10000,20); // simplest case
1455
1456 //---------------------- mth_octave_spectral_level_demo ----------------------
1457 // Demonstrate mth_octave_spectral_level in a standalone GUI.
1458 //
1459 // USAGE: _ : mth_octave_spectral_level_demo(BandsPerOctave);
1460
1461 mth_octave_spectral_level_demo(M) =
1462 mth_octave_spectral_level_default(M,ftop,N,tau,dB_offset)
1463 with {
1464 // Span nearly 10 octaves so that lowest band-edge is at
1465 // ftop*2^(-Noct+2) = 40 Hz when ftop=10 kHz:
1466 N = int(10*M); // without int(), segmentation fault observed for M=1.67
1467 ftop = 10000;
1468 ctl_group(x) = hgroup("[1] SPECTRUM ANALYZER CONTROLS", x);
1469 tau = ctl_group(hslider("[0] Level Averaging Time [unit:sec]
1470 [tooltip: band-level averaging time in seconds]",
1471 0.1,0,1,0.01));
1472 dB_offset = ctl_group(hslider("[1] Level dB Offset [unit:dB]
1473 [tooltip: Level offset in decibels]",
1474 50,0,100,1));
1475 };
1476
1477 spectral_level_demo = mth_octave_spectral_level_demo(1.5); // 2/3 octave
1478
1479 //---------------- (third|half)_octave_(analyzer|filterbank) -----------------
1480
1481 // Named special cases of mth_octave_* with defaults filled in:
1482
1483 third_octave_analyzer(N) = mth_octave_analyzer_default(3,10000,N);
1484 third_octave_filterbank(N) = mth_octave_filterbank_default(3,10000,N);
1485 // Third-Octave Filter-Banks have been used in audio for over a century.
1486 // See, e.g.,
1487 // Acoustics [the book], by L. L. Beranek
1488 // Amer. Inst. Physics for the Acoustical Soc. America,
1489 // http://asa.aip.org/publications.html, 1986 (1st ed.1954)
1490
1491 // Third-octave bands across the audio spectrum are too wide for current
1492 // typical computer screens, so half-octave bands are the default:
1493 half_octave_analyzer(N) = mth_octave_analyzer_default(2,10000,N);
1494 half_octave_filterbank(N) = mth_octave_filterbank_default(2,10000,N);
1495
1496 octave_filterbank(N) = mth_octave_filterbank_default(1,10000,N);
1497 octave_analyzer(N) = mth_octave_analyzer_default(1,10000,N);
1498
1499 //=========================== Filter-Bank Demos ==============================
53
1500 // Graphic Equalizer: Each filter-bank output signal routes through a fader.
1501 //
1502 // USAGE: _ : mth_octave_filterbank_demo(M) : _
1503 // where
1504 // M = number of bands per octave
1505
1506 mth_octave_filterbank_demo(M) = bp1(bp,mthoctavefilterbankdemo) with {
1507 bp1 = component("effect.lib").bypass1;
1508 mofb_group(x) = vgroup("CONSTANT-Q FILTER BANK (Butterworth dyadic tree)
1509 [tooltip: See Fausts filter.lib for documentation and references]", x);
1510 bypass_group(x) = mofb_group(hgroup("[0]", x));
1511 slider_group(x) = mofb_group(hgroup("[1]", x));
1512 N = 10*M; // total number of bands (highpass band, octave-bands, dc band)
1513 ftop = 10000;
1514 mthoctavefilterbankdemo = chan;
1515 chan = mth_octave_filterbank_default(M,ftop,N) :
1516 sum(i,N,(*(db2linear(fader(N-i)))));
1517 fader(i) = slider_group(vslider("[%2i] [unit:dB]
1518 [tooltip: Bandpass filter gain in dB]", -10, -70, 10, 0.1)) :
1519 smooth(0.999);
1520 bp = bypass_group(checkbox("[0] Bypass
1521 [tooltip: When this is checked, the filter-bank has no effect]"));
1522 };
1523
1524 filterbank_demo = mth_octave_filterbank_demo(1); // octave-bands = default
1525
1526 //=========== Arbritary-Crossover Filter-Banks and Spectrum Analyzers ========
1527 // These are similar to the Mth-octave filter-banks above, except that the
1528 // band-split frequencies are passed explicitly as arguments.
1529 //
1530 // USAGE:
1531 // _ : filterbank (O,freqs) : par(i,N,_); // Butterworth band-splits
1532 // _ : filterbanki(O,freqs) : par(i,N,_); // Inverted-dc version
1533 // _ : analyzer (O,freqs) : par(i,N,_); // No delay equalizer
1534 //
1535 // where
1536 // O = band-split filter order (ODD integer required for filterbank[i])
1537 // freqs = (fc1,fc2,...,fcNs) [in numerically ascending order], where
1538 // Ns=N-1 is the number of octave band-splits
1539 // (total number of bands N=Ns+1).
1540 //
1541 // If frequencies are listed explicitly as arguments, enclose them in parens:
1542 //
1543 // _ : filterbank(3,(fc1,fc2)) : _,_,_
1544 //
1545 // ACKNOWLEDGMENT
1546 // Technique for processing a variable number of signal arguments due
1547 // to Yann Orlarey (as is the entire Faust framework!)
1548 //
1549 //------------------------------ analyzer --------------------------------------
1550 analyzer(O,lfreqs) = _ <: bsplit(nb) with
1551 {
1552 nb = count(lfreqs);
1553 fc(n) = take(n, lfreqs);
1554 lp(n) = lowpass(O,fc(n));
1555 hp(n) = highpass(O,fc(n));
1556 bsplit(0) = _;
1557 bsplit(i) = hp(i), (lp(i) <: bsplit(i-1));
1558 };
1559
1560 //----------------------------- filterbank -------------------------------------
1561 filterbank(O,lfreqs) = analyzer(O,lfreqs) : delayeq with
1562 {
1563 nb = count(lfreqs);
1564 fc(n) = take(n, lfreqs);
1565 ap(n) = highpass_plus_lowpass(O,fc(n));
1566 delayeq = par(i,nb-1,apchain(nb-1-i)),_,_;
1567 apchain(0) = _;
54
1568 apchain(i) = ap(i) : apchain(i-1);
1569 };
1570
1571 //----------------------------- filterbanki ------------------------------------
1572 filterbanki(O,lfreqs) = _ <: bsplit(nb) with
1573 {
1574 fc(n) = take(n, lfreqs);
1575 lp(n) = lowpass(O,fc(n));
1576 hp(n) = highpass(O,fc(n));
1577 ap(n) = highpass_minus_lowpass(O,fc(n));
1578 bsplit(0) = *(-1.0);
1579 bsplit(i) = (hp(i) : delayeq(i-1)), (lp(i) <: bsplit(i-1));
1580 delayeq(0) = _; // moving the *(-1) here inverts all outputs BUT dc
1581 delayeq(i) = ap(i) : delayeq(i-1);
1582 };

Listing 6: effect.lib

1 declare name "Faust Audio Effect Library";
2 declare author "Julius O. Smith (jos at ccrma.stanford.edu)";
3 declare copyright "Julius O. Smith III";
4 declare version "1.33";
5 declare license "STK-4.3"; // Synthesis Tool Kit 4.3 (MIT style license)
6 declare reference "https://ccrma.stanford.edu/realsimple/faust_strings/";
7
8 import("filter.lib"); // dcblocker*, lowpass, filterbank, ...
9
10 // The following utilities (or equivalents) could go in music.lib:
11
12 //----------------------- midikey2hz,pianokey2hz ------------------------
13 midikey2hz(x) = 440.0*pow(2.0, (x-69.0)/12); // MIDI key 69 = A440
14 pianokey2hz(x) = 440.0*pow(2.0, (x-49.0)/12); // piano key 49 = A440
15
16 //---------------- cross2, bypass1, bypass2, select2stereo --------------
17 //
18 cross2 = _,_,_,_ <: _,!,_,!,!,_,!,_;
19
20 bypass1(bpc,e) = _ <: select2(bpc,(inswitch:e),_)
21 with {inswitch = select2(bpc,_,0);};
22
23 bypass2(bpc,e) = _,_ <: ((inswitch:e),_,_) : select2stereo(bpc) with {
24 inswitch = _,_ : (select2(bpc,_,0), select2(bpc,_,0)) : _,_;
25 };
26
27 select2stereo(bpc) = cross2 : select2(bpc), select2(bpc) : _,_;
28
29 //---------------------- levelfilter, levelfilterN ----------------------
30 // Dynamic level lowpass filter:
31 //
32 // USAGE: levelfilter(L,freq), where
33 // L = desired level (in dB) at Nyquist limit (SR/2), e.g., -60
34 // freq = corner frequency (-3dB point) usually set to fundamental freq
35 //
36 // REFERENCE:
37 // https://ccrma.stanford.edu/realsimple/faust_strings/Dynamic_Level_Lowpass_Filter.html
38 //
39 levelfilter(L,freq,x) = (L * L0 * x) + ((1.0-L) * lp2out(x))
40 with {
41 L0 = pow(L,1/3);
42 Lw = PI*freq/SR; // = w1 T / 2
43 Lgain = Lw / (1.0 + Lw);
44 Lpole2 = (1.0 - Lw) / (1.0 + Lw);
45 lp2out = *(Lgain) : + ~ *(Lpole2);
46 };
55
47
48 levelfilterN(N,freq,L) = seq(i,N,levelfilter((L/N),freq));
49
50 //------------------------- speakerbp -------------------------------
51 // Dirt-simple speaker simulator (overall bandpass eq with observed
52 // roll-offs above and below the passband).
53 //
54 // Low-frequency speaker model = +12 dB/octave slope breaking to
55 // flat near f1. Implemented using two dc blockers in series.
56 //
57 // High-frequency model = -24 dB/octave slope implemented using a
58 // fourth-order Butterworth lowpass.
59 //
60 // Example based on measured Celestion G12 (12" speaker):
61 // speakerbp(130,5000);
62 //
63 // Requires filter.lib
64 //
65 speakerbp(f1,f2) = dcblockerat(f1) : dcblockerat(f1) : lowpass(4,f2);
66
67
68 //--------------------- cubicnl(drive,offset) -----------------------
69 // Cubic nonlinearity distortion
70 //
71 // USAGE: cubicnl(drive,offset), where
72 // drive = distortion amount, between 0 and 1
73 // offset = constant added before nonlinearity to give even harmonics
74 // Note: offset can introduce a nonzero mean - feed
75 // cubicnl output to dcblocker to remove this.
76 //
77 // REFERENCES:
78 // https://ccrma.stanford.edu/~jos/pasp/Cubic_Soft_Clipper.html
79 // https://ccrma.stanford.edu/~jos/pasp/Nonlinear_Distortion.html
80 //
81 cubicnl(drive,offset) = *(pregain) : +(offset) : clip(-1,1) : cubic
82 with {
83 pregain = pow(10.0,2*drive);
84 clip(lo,hi) = min(hi) : max(lo);
85 cubic(x) = x - x*x*x/3;
86 postgain = max(1.0,1.0/pregain); // unity gain when nearly linear
87 };
88
89 cubicnl_nodc(drive,offset) = cubicnl(drive,offset) : dcblocker;
90
91 //--------------------------- cubicnl_demo --------------------------
92 // USAGE: _ : cubicnl_demo : _;
93 //
94 cubicnl_demo = bypass1(bp,
95 cubicnl_nodc(drive:smooth(0.999),offset:smooth(0.999)))
96 with {
97 cnl_group(x) = vgroup("CUBIC NONLINEARITY cubicnl
98 [tooltip: Reference:
99 https://ccrma.stanford.edu/~jos/pasp/Cubic_Soft_Clipper.html]", x);
100 // bypass_group(x) = cnl_group(hgroup("[0]", x));
101 slider_group(x) = cnl_group(hgroup("[1]", x));
102 // bp = bypass_group(checkbox("[0] Bypass
103 bp = slider_group(checkbox("[0] Bypass
104 [tooltip: When this is checked, the nonlinearity has no effect]"));
105 // drive = slider_group(vslider("[1] Drive [style: knob]
106 drive = slider_group(hslider("[1] Drive
107 [tooltip: Amount of distortion]",
108 0, 0, 1, 0.01));
109 // offset = slider_group(vslider("[2] Offset [style: knob]
110 offset = slider_group(hslider("[2] Offset
111 [tooltip: Brings in even harmonics]",
112 0, 0, 1, 0.01));
113 };
114
56
115 //------------------------- moog_vcf(res,fr) ---------------------------
116 // Moog "Voltage Controlled Filter" (VCF) in "analog" form
117 //
118 // USAGE: moog_vcf(res,fr), where
119 // fr = corner-resonance frequency in Hz ( less than SR/6.3 or so )
120 // res = Normalized amount of corner-resonance between 0 and 1
121 // (0 is no resonance, 1 is maximum)
122 // Requires filter.lib.
123 //
124 // DESCRIPTION: Moog VCF implemented using the same logical block diagram
125 // as the classic analog circuit. As such, it neglects the one-sample
126 // delay associated with the feedback path around the four one-poles.
127 // This extra delay alters the response, especially at high frequencies
128 // (see reference [1] for details).
129 // See moog_vcf_2b below for a more accurate implementation.
130 //
131 // REFERENCES:
132 // [1] https://ccrma.stanford.edu/~stilti/papers/moogvcf.pdf
133 // [2] https://ccrma.stanford.edu/~jos/pasp/vegf.html
134 //
135 moog_vcf(res,fr) = (+ : seq(i,4,pole(p)) : *(unitygain(p))) ~ *(mk)
136 with {
137 p = 1.0 - fr * 2.0 * PI / SR; // good approximation for fr << SR
138 unitygain(p) = pow(1.0-p,4.0); // one-pole unity-gain scaling
139 mk = -4.0*max(0,min(res,0.999999)); // need mk > -4 for stability
140 };
141
142 //----------------------- moog_vcf_2b[n] ---------------------------
143 // Moog "Voltage Controlled Filter" (VCF) as two biquads
144 //
145 // USAGE:
146 // moog_vcf_2b(res,fr)
147 // moog_vcf_2bn(res,fr)
148 // where
149 // fr = corner-resonance frequency in Hz
150 // res = Normalized amount of corner-resonance between 0 and 1
151 // (0 is min resonance, 1 is maximum)
152 //
153 // DESCRIPTION: Implementation of the ideal Moog VCF transfer
154 // function factored into second-order sections. As a result, it is
155 // more accurate than moog_vcf above, but its coefficient formulas are
156 // more complex when one or both parameters are varied. Here, res
157 // is the fourth root of that in moog_vcf, so, as the sampling rate
158 // approaches infinity, moog_vcf(res,fr) becomes equivalent
159 // to moog_vcf_2b[n](res^4,fr) (when res and fr are constant).
160 //
161 // moog_vcf_2b uses two direct-form biquads (tf2)
162 // moog_vcf_2bn uses two protected normalized-ladder biquads (tf2np)
163 //
164 // REQUIRES: filter.lib
165 //
166 moog_vcf_2b(res,fr) = tf2s(0,0,b0,a11,a01,w1) : tf2s(0,0,b0,a12,a02,w1)
167 with {
168 s = 1; // minus the open-loop location of all four poles
169 frl = max(20,min(10000,fr)); // limit fr to reasonable 20-10k Hz range
170 w1 = 2*PI*frl; // frequency-scaling parameter for bilinear xform
171 // Equivalent: w1 = 1; s = 2*PI*frl;
172 kmax = sqrt(2)*0.999; // 0.999 gives stability margin (tf2 is unprotected)
173 k = min(kmax,sqrt(2)*res); // fourth root of Moog VCF feedback gain
174 b0 = s^2;
175 s2k = sqrt(2) * k;
176 a11 = s * (2 + s2k);
177 a12 = s * (2 - s2k);
178 a01 = b0 * (1 + s2k + k^2);
179 a02 = b0 * (1 - s2k + k^2);
180 };
181
182 moog_vcf_2bn(res,fr) = tf2snp(0,0,b0,a11,a01,w1) : tf2snp(0,0,b0,a12,a02,w1)
57
183 with {
184 s = 1; // minus the open-loop location of all four poles
185 w1 = 2*PI*max(fr,20); // frequency-scaling parameter for bilinear xform
186 k = sqrt(2)*0.999*res; // fourth root of Moog VCF feedback gain
187 b0 = s^2;
188 s2k = sqrt(2) * k;
189 a11 = s * (2 + s2k);
190 a12 = s * (2 - s2k);
191 a01 = b0 * (1 + s2k + k^2);
192 a02 = b0 * (1 - s2k + k^2);
193 };
194
195 //------------------------- moog_vcf_demo ---------------------------
196 // Illustrate and compare all three Moog VCF implementations above
197 // (called by <faust>/examples/vcf_wah_pedals.dsp).
198 //
199 // USAGE: _ : moog_vcf_demo : _;
200
201 moog_vcf_demo = bypass1(bp,vcf) with {
202 mvcf_group(x) = hgroup("MOOG VCF (Voltage Controlled Filter)
203 [tooltip: See Fausts effect.lib for info and references]",x);
204
205 meter_group(x) = mvcf_group(vgroup("[0]",x));
206 cb_group(x) = meter_group(hgroup("[0]",x));
207
208 bp = cb_group(checkbox("[0] Bypass [tooltip: When this is checked, the Moog VCF has no
effect]"));
209 archsw = cb_group(checkbox("[1] Use Biquads
210 [tooltip: Select moog_vcf_2b (two-biquad) implementation, instead of the default moog_vcf
(analog style) implementation]"));
211 bqsw = cb_group(checkbox("[2] Normalized Ladders
212 [tooltip: If using biquads, make them normalized ladders (moog_vcf_2bn)]"));
213
214 freq = mvcf_group(hslider("[1] Corner Frequency [unit:PK] [style:knob]
215 [tooltip: The VCF resonates at the corner frequency (specified in PianoKey (PK) units,
with A440 = 49 PK). The VCF response is flat below the corner frequency, and rolls
off -24 dB per octave above.]",
216 25, 1, 88, 0.01) : pianokey2hz) : smooth(0.999);
217
218 res = mvcf_group(hslider("[2] Corner Resonance [style:knob]
219 [tooltip: Amount of resonance near VCF corner frequency (specified between 0 and 1)]",
220 0.9, 0, 1, 0.01));
221
222 outgain = meter_group(hslider("[1] VCF Output Level [unit:dB]
223 [tooltip: output level in decibels]",
224 5, -60, 20, 0.1)) : smooth(0.999)
225 : component("music.lib").db2linear;
226
227 vcfbq = _ <: select2(bqsw, moog_vcf_2b(res,freq), moog_vcf_2bn(res,freq));
228 vcfarch = _ <: select2(archsw, moog_vcf(res^4,freq), vcfbq);
229 vcf = vcfarch : *(outgain);
230 };
231
232 //-------------------------- wah4(fr) -------------------------------
233 // Wah effect, 4th order
234 // USAGE: wah4(fr), where fr = resonance frequency in Hz
235 // REFERENCE "https://ccrma.stanford.edu/~jos/pasp/vegf.html";
236 //
237 wah4(fr) = 4*moog_vcf((3.2/4),fr:smooth(0.999));
238
239 //------------------------- wah4_demo ---------------------------
240 // USAGE: _ : wah4_demo : _;
241
242 wah4_demo = bypass1(bp, wah4(fr)) with {
243 wah4_group(x) = hgroup("WAH4
244 [tooltip: Fourth-order wah effect made using moog_vcf]", x);
245 bp = wah4_group(checkbox("[0] Bypass
246 [tooltip: When this is checked, the wah pedal has no effect]"));
58
247 fr = wah4_group(hslider("[1] Resonance Frequency
248 [tooltip: wah resonance frequency in Hz]",
249 200,100,2000,1));
250 // Avoid dc with the moog_vcf (amplitude too high when freq comes up from dc)
251 // Also, avoid very high resonance frequencies (e.g., 5kHz or above).
252 };
253
254 //------------------------ autowah(level) -----------------------------
255 // Auto-wah effect
256 // USAGE: _ : autowah(level) : _;
257 // where level = amount of effect desired (0 to 1).
258 //
259 autowah(level,x) = level * crybaby(amp_follower(0.1,x),x) + (1.0-level)*x;
260
261 //-------------------------- crybaby(wah) -----------------------------
262 // Digitized CryBaby wah pedal
263 // USAGE: _ : crybaby(wah) : _;
264 // where wah = "pedal angle" from 0 to 1.
265 // REFERENCE: https://ccrma.stanford.edu/~jos/pasp/vegf.html
266 //
267 crybaby(wah) = *(gs) : tf2(1,-1,0,a1s,a2s)
268 with {
269 Q = pow(2.0,(2.0*(1.0-wah)+1.0)); // Resonance "quality factor"
270 fr = 450.0*pow(2.0,2.3*wah); // Resonance tuning
271 g = 0.1*pow(4.0,wah); // gain (optional)
272
273 // Biquad fit using z = exp(s T) ~ 1 + sT for low frequencies:
274 frn = fr/SR; // Normalized pole frequency (cycles per sample)
275 R = 1 - PI*frn/Q; // pole radius
276 theta = 2*PI*frn; // pole angle
277 a1 = 0-2.0*R*cos(theta); // biquad coeff
278 a2 = R*R; // biquad coeff
279
280 // dezippering of slider-driven signals:
281 s = 0.999; // smoothing parameter (one-pole pole location)
282 a1s = a1 : smooth(s);
283 a2s = a2 : smooth(s);
284 gs = g : smooth(s);
285
286 tf2 = component("filter.lib").tf2;
287 };
288
289 //------------------------- crybaby_demo ---------------------------
290 // USAGE: _ : crybaby_demo : _ ;
291
292 crybaby_demo = bypass1(bp, crybaby(wah)) with {
293 crybaby_group(x) = hgroup("CRYBABY [tooltip: Reference: https://ccrma.stanford.edu/~jos/
pasp/vegf.html]", x);
294 bp = crybaby_group(checkbox("[0] Bypass [tooltip: When this is checked, the wah pedal has
no effect]"));
295 wah = crybaby_group(hslider("[1] Wah parameter [tooltip: wah pedal angle between 0 (rocked
back) and 1 (rocked forward)]",0.8,0,1,0.01));
296 };
297
298 //------------ apnl(a1,a2) ---------------
299 // Passive Nonlinear Allpass:
300 // switch between allpass coefficient a1 and a2 at signal zero crossings
301 // REFERENCE:
302 // "A Passive Nonlinear Digital Filter Design ..."
303 // by John R. Pierce and Scott A. Van Duyne,
304 // JASA, vol. 101, no. 2, pp. 1120-1126, 1997
305 // Written by Romain Michon and JOS based on Pierce switching springs idea:
306 apnl(a1,a2,x) = nonLinFilter
307 with{
308 condition = _>0;
309 nonLinFilter = (x - _ <: _*(condition*a1 + (1-condition)*a2),_)~_ :> +;
310 };
311
59
312 //------------ piano_dispersion_filter(M,B,f0) ---------------
313 // Piano dispersion allpass filter in closed form
314 //
315 // ARGUMENTS:
316 // M = number of first-order allpass sections (compile-time only)
317 // Keep below 20. 8 is typical for medium-sized piano strings.
318 // B = string inharmonicity coefficient (0.0001 is typical)
319 // f0 = fundamental frequency in Hz
320 //
321 // INPUT:
322 // Signal to be filtered by the allpass chain
323 //
324 // OUTPUTS:
325 // 1. MINUS the estimated delay at f0 of allpass chain in samples,
326 // provided in negative form to facilitate subtraction
327 // from delay-line length (see USAGE below).
328 // 2. Output signal from allpass chain
329 //
330 // USAGE:
331 // piano_dispersion_filter(1,B,f0) : +(totalDelay),_ : fdelay(maxDelay)
332 //
333 // REFERENCE:
334 // "Dispersion Modeling in Waveguide Piano Synthesis
335 // Using Tunable Allpass Filters",
336 // by Jukka Rauhala and Vesa Valimaki, DAFX-2006, pp. 71-76
337 // URL: http://www.dafx.ca/proceedings/papers/p_071.pdf
338 // NOTE: An erratum in Eq. (7) is corrected in Dr. Rauhalas
339 // encompassing dissertation (and below).
340 // See also: http://www.acoustics.hut.fi/research/asp/piano/
341 //
342 piano_dispersion_filter(M,B,f0) = -Df0*M,seq(i,M,tf1(a1,1,a1))
343 with {
344 a1 = (1-D)/(1+D); // By Eq. 3, have D >= 0, hence a1 >= 0 also
345 D = exp(Cd - Ikey(f0)*kd);
346 trt = pow(2.0,1.0/12.0); // 12th root of 2
347 logb(b,x) = log(x) / log(b); // log-base-b of x
348 Ikey(f0) = logb(trt,f0*trt/27.5);
349 Bc = max(B,0.000001);
350 kd = exp(k1*log(Bc)*log(Bc) + k2*log(Bc)+k3);
351 Cd = exp((m1*log(M)+m2)*log(Bc)+m3*log(M)+m4);
352 k1 = -0.00179;
353 k2 = -0.0233;
354 k3 = -2.93;
355 m1 = 0.0126;
356 m2 = 0.0606;
357 m3 = -0.00825;
358 m4 = 1.97;
359 wT = 2*PI*f0/SR;
360 polydel(a) = atan(sin(wT)/(a+cos(wT)))/wT;
361 Df0 = polydel(a1) - polydel(1.0/a1);
362 };
363
364 //===================== Phasing and Flanging Effects ====================
365
366 //--------------- flanger_mono, flanger_stereo, flanger_demo -------------
367 // Flanging effect
368 //
369 // USAGE:
370 // _ : flanger_mono(dmax,curdel,depth,fb,invert) : _;
371 // _,_ : flanger_stereo(dmax,curdel1,curdel2,depth,fb,invert) : _,_;
372 // _,_ : flanger_demo : _,_;
373 //
374 // ARGUMENTS:
375 // dmax = maximum delay-line length (power of 2) - 10 ms typical
376 // curdel = current dynamic delay (not to exceed dmax)
377 // depth = effect strength between 0 and 1 (1 typical)
378 // fb = feedback gain between 0 and 1 (0 typical)
379 // invert = 0 for normal, 1 to invert sign of flanging sum
60
380 //
381 // REFERENCE:
382 // https://ccrma.stanford.edu/~jos/pasp/Flanging.html
383 //
384 flanger_mono(dmax,curdel,depth,fb,invert)
385 = _ <: _, (-:fdelay(dmax,curdel)) ~ *(fb) : _,
386 *(select2(invert,depth,0-depth))
387 : + : *(0.5);
388
389 flanger_stereo(dmax,curdel1,curdel2,depth,fb,invert)
390 = flanger_mono(dmax,curdel1,depth,fb,invert),
391 flanger_mono(dmax,curdel2,depth,fb,invert);
392
393 //------------------------- flanger_demo ---------------------------
394 // USAGE: _,_ : flanger_demo : _,_;
395 //
396 flanger_demo = bypass2(fbp,flanger_stereo_demo) with {
397 flanger_group(x) =
398 vgroup("FLANGER [tooltip: Reference: https://ccrma.stanford.edu/~jos/pasp/Flanging.html]"
, x);
399 meter_group(x) = flanger_group(hgroup("[0]", x));
400 ctl_group(x) = flanger_group(hgroup("[1]", x));
401 del_group(x) = flanger_group(hgroup("[2] Delay Controls", x));
402 lvl_group(x) = flanger_group(hgroup("[3]", x));
403
404 fbp = meter_group(checkbox(
405 "[0] Bypass [tooltip: When this is checked, the flanger has no effect]"));
406 invert = meter_group(checkbox("[1] Invert Flange Sum"));
407
408 // FIXME: This should be an amplitude-response display:
409 flangeview = lfor(freq) + lfol(freq) : meter_group(hbargraph(
410 "[2] Flange LFO [style: led] [tooltip: Display sum of flange delays]", -1.5,+1.5));
411
412 flanger_stereo_demo(x,y) = attach(x,flangeview),y :
413 *(level),*(level) : flanger_stereo(dmax,curdel1,curdel2,depth,fb,invert);
414
415 lfol = component("oscillator.lib").oscrs; // sine for left channel
416 lfor = component("oscillator.lib").oscrc; // cosine for right channel
417 dmax = 2048;
418 dflange = 0.001 * SR *
419 del_group(hslider("[1] Flange Delay [unit:ms] [style:knob]", 10, 0, 20, 0.001));
420 odflange = 0.001 * SR *
421 del_group(hslider("[2] Delay Offset [unit:ms] [style:knob]", 1, 0, 20, 0.001));
422 freq = ctl_group(hslider("[1] Speed [unit:Hz] [style:knob]", 0.5, 0, 10, 0.01));
423 depth = ctl_group(hslider("[2] Depth [style:knob]", 1, 0, 1, 0.001));
424 fb = ctl_group(hslider("[3] Feedback [style:knob]", 0, -0.999, 0.999, 0.001));
425 level = lvl_group(hslider("Flanger Output Level [unit:dB]", 0, -60, 10, 0.1)) : db2linear
;
426 curdel1 = odflange+dflange*(1 + lfol(freq))/2;
427 curdel2 = odflange+dflange*(1 + lfor(freq))/2;
428 };
429
430 //------- phaser2_mono, phaser2_stereo, phaser2_demo -------
431 // Phasing effect
432 //
433 // USAGE:
434 // _ : phaser2_mono(Notches,width,frqmin,fratio,frqmax,speed,depth,fb,invert) : _;
435 // _,_ : phaser2_stereo(") : _,_;
436 // _,_ : phaser2_demo : _,_;
437 //
438 // ARGUMENTS:
439 // Notches = number of spectral notches (MACRO ARGUMENT - not a signal)
440 // width = approximate width of spectral notches in Hz
441 // frqmin = approximate minimum frequency of first spectral notch in Hz
442 // fratio = ratio of adjacent notch frequencies
443 // frqmax = approximate maximum frequency of first spectral notch in Hz
444 // speed = LFO frequency in Hz (rate of periodic notch sweep cycles)
445 // depth = effect strength between 0 and 1 (1 typical) (aka "intensity")
61
446 // when depth=2, "vibrato mode" is obtained (pure allpass chain)
447 // fb = feedback gain between -1 and 1 (0 typical)
448 // invert = 0 for normal, 1 to invert sign of flanging sum
449 //
450 // REFERENCES:
451 // https://ccrma.stanford.edu/~jos/pasp/Phasing.html
452 // http://www.geofex.com/Article_Folders/phasers/phase.html
453 // An Allpass Approach to Digital Phasing and Flanging, Julius O. Smith III,
454 // Proc. Int. Computer Music Conf. (ICMC-84), pp. 103-109, Paris, 1984.
455 // CCRMA Tech. Report STAN-M-21: https://ccrma.stanford.edu/STANM/stanms/stanm21/
456
457 vibrato2_mono(sections,phase01,fb,width,frqmin,fratio,frqmax,speed) =
458 (+ : seq(i,sections,ap2p(R,th(i)))) ~ *(fb)
459 with {
460 tf2 = component("filter.lib").tf2;
461 // second-order resonant digital allpass given pole radius and angle:
462 ap2p(R,th) = tf2(a2,a1,1,a1,a2) with {
463 a2 = R^2;
464 a1 = -2*R*cos(th);
465 };
466 SR = component("music.lib").SR;
467 R = exp(-pi*width/SR);
468 cososc = component("oscillator.lib").oscrc;
469 sinosc = component("oscillator.lib").oscrs;
470 osc = cososc(speed) * phase01 + sinosc(speed) * (1-phase01);
471 lfo = (1-osc)/2; // in [0,1]
472 pi = 4*atan(1);
473 thmin = 2*pi*frqmin/SR;
474 thmax = 2*pi*frqmax/SR;
475 th1 = thmin + (thmax-thmin)*lfo;
476 th(i) = (fratio^(i+1))*th1;
477 };
478
479 phaser2_mono(Notches,phase01,width,frqmin,fratio,frqmax,speed,depth,fb,invert) =
480 _ <: *(g1) + g2mi*vibrato2_mono(Notches,phase01,fb,width,frqmin,fratio,frqmax,speed)
481 with { // depth=0 => direct-signal only
482 g1 = 1-depth/2; // depth=1 => phaser mode (equal sum of direct and allpass-chain)
483 g2 = depth/2; // depth=2 => vibrato mode (allpass-chain signal only)
484 g2mi = select2(invert,g2,-g2); // inversion negates the allpass-chain signal
485 };
486
487 phaser2_stereo(Notches,width,frqmin,fratio,frqmax,speed,depth,fb,invert)
488 = phaser2_mono(Notches,0,width,frqmin,fratio,frqmax,speed,depth,fb,invert),
489 phaser2_mono(Notches,1,width,frqmin,fratio,frqmax,speed,depth,fb,invert);
490
491 //------------------------- phaser2_demo ---------------------------
492 // USAGE: _,_ : phaser2_demo : _,_;
493 //
494 phaser2_demo = bypass2(pbp,phaser2_stereo_demo) with {
495 phaser2_group(x) =
496 vgroup("PHASER2 [tooltip: Reference: https://ccrma.stanford.edu/~jos/pasp/Flanging.html]"
, x);
497 meter_group(x) = phaser2_group(hgroup("[0]", x));
498 ctl_group(x) = phaser2_group(hgroup("[1]", x));
499 nch_group(x) = phaser2_group(hgroup("[2]", x));
500 lvl_group(x) = phaser2_group(hgroup("[3]", x));
501
502 pbp = meter_group(checkbox(
503 "[0] Bypass [tooltip: When this is checked, the phaser has no effect]"));
504 invert = meter_group(checkbox("[1] Invert Internal Phaser Sum"));
505 vibr = meter_group(checkbox("[2] Vibrato Mode")); // In this mode you can hear any "
Doppler"
506
507 // FIXME: This should be an amplitude-response display:
508 //flangeview = phaser2_amp_resp : meter_group(hspectrumview("[2] Phaser Amplitude Response
", 0,1));
509 //phaser2_stereo_demo(x,y) = attach(x,flangeview),y : ...
510
62
511 phaser2_stereo_demo = *(level),*(level) :
512 phaser2_stereo(Notches,width,frqmin,fratio,frqmax,speed,mdepth,fb,invert);
513
514 Notches = 4; // Compile-time parameter: 2 is typical for analog phaser stomp-boxes
515
516 // FIXME: Add tooltips
517 speed = ctl_group(hslider("[1] Speed [unit:Hz] [style:knob]", 0.5, 0, 10, 0.001));
518 depth = ctl_group(hslider("[2] Notch Depth (Intensity) [style:knob]", 1, 0, 1, 0.001));
519 fb = ctl_group(hslider("[3] Feedback Gain [style:knob]", 0, -0.999, 0.999, 0.001));
520
521 width = nch_group(hslider("[1] Notch width [unit:Hz] [style:knob]", 1000, 10, 5000, 1));
522 frqmin = nch_group(hslider("[2] Min Notch1 Freq [unit:Hz] [style:knob]", 100, 20, 5000, 1)
);
523 frqmax = nch_group(hslider("[3] Max Notch1 Freq [unit:Hz] [style:knob]", 800, 20, 10000,
1)) : max(frqmin);
524 fratio = nch_group(hslider("[4] Notch Freq Ratio: NotchFreq(n+1)/NotchFreq(n) [style:knob]
", 1.5, 1.1, 4, 0.001));
525
526 level = lvl_group(hslider("Phaser Output Level [unit:dB]", 0, -60, 10, 0.1)) : component(
"music.lib").db2linear;
527
528 mdepth = select2(vibr,depth,2); // Improve "ease of use"
529 };
530
531 //------------------------- stereo_width(w) ---------------------------
532 // Stereo Width effect using the Blumlein Shuffler technique.
533 //
534 // USAGE: "_,_ : stereo_width(w) : _,_", where
535 // w = stereo width between 0 and 1
536 //
537 // At w=0, the output signal is mono ((left+right)/2 in both channels).
538 // At w=1, there is no effect (original stereo image).
539 // Thus, w between 0 and 1 varies stereo width from 0 to "original".
540 //
541 // REFERENCE:
542 // "Applications of Blumlein Shuffling to Stereo Microphone Techniques"
543 // Michael A. Gerzon, JAES vol. 42, no. 6, June 1994
544 //
545 stereo_width(w) = shuffle : *(mgain),*(sgain) : shuffle
546 with {
547 shuffle = _,_ <: +,-; // normally scaled by 1/sqrt(2) for orthonormality,
548 mgain = 1-w/2; // but we pick up the needed normalization here.
549 sgain = w/2;
550 };
551
552 //--------------------------- amp_follower ---------------------------
553 // Classic analog audio envelope follower with infinitely fast rise and
554 // exponential decay. The amplitude envelope instantaneously follows
555 // the absolute value going up, but then floats down exponentially.
556 //
557 // USAGE:
558 // _ : amp_follower(rel) : _
559 //
560 // where
561 // rel = release time = amplitude-envelope time-constant (sec) going down
562 //
563 // REFERENCES:
564 // Musical Engineers Handbook, Bernie Hutchins, Ithaca NY, 1975
565 // Elecronotes Newsletter, Bernie Hutchins
566
567 amp_follower(rel) = abs : env with {
568 p = tau2pole(rel);
569 env(x) = x * (1.0 - p) : + ~ max(x,_) * p;
570 };
571
572 //--------------------------- amp_follower_ud ---------------------------
573 // Envelope follower with different up and down time-constants
574 //
63
575 // USAGE:
576 // _ : amp_follower_ud(att,rel) : _
577 //
578 // where
579 // att = attack time = amplitude-envelope time constant (sec) going up
580 // rel = release time = amplitude-envelope time constant (sec) going down
581 //
582 // For audio, att should be faster (smaller) than rel (e.g., 0.001 and 0.01)
583
584 amp_follower_ud(att,rel) = amp_follower(rel) : smooth(tau2pole(att));
585
586 //=============== Gates, Limiters, and Dynamic Range Compression ============
587
588 //----------------- gate_mono, gate_stereo -------------------
589 // Mono and stereo signal gates
590 //
591 // USAGE:
592 // _ : gate_mono(thresh,att,hold,rel) : _
593 // or
594 // _,_ : gate_stereo(thresh,att,hold,rel) : _,_
595 //
596 // where
597 // thresh = dB level threshold above which gate opens (e.g., -60 dB)
598 // att = attack time = time constant (sec) for gate to open (e.g., 0.0001 s = 0.1 ms)
599 // hold = hold time = time (sec) gate stays open after signal level < thresh (e.g., 0.1 s)
600 // rel = release time = time constant (sec) for gate to close (e.g., 0.020 s = 20 ms)
601 //
602 // REFERENCES:
603 // - http://en.wikipedia.org/wiki/Noise_gate
604 // - http://www.soundonsound.com/sos/apr01/articles/advanced.asp
605 // - http://en.wikipedia.org/wiki/Gating_(sound_engineering)
606
607 gate_mono(thresh,att,hold,rel,x) = x * gate_gain_mono(thresh,att,hold,rel,x);
608
609 gate_stereo(thresh,att,hold,rel,x,y) = ggm*x, ggm*y with {
610 ggm = gate_gain_mono(thresh,att,hold,rel,abs(x)+abs(y));
611 };
612
613 gate_gain_mono(thresh,att,hold,rel,x) = extendedrawgate : amp_follower_ud(att,rel) with {
614 extendedrawgate = max(rawgatesig,holdsig);
615 rawgatesig = inlevel(x) > db2linear(thresh);
616 inlevel(x) = amp_follower_ud(att/2,rel/2,x);
617 holdsig = ((max(holdreset & holdsamps,_) ~-(1)) > 0);
618 holdreset = rawgatesig > rawgatesig; // reset hold when raw gate falls
619 holdsamps = int(hold*SR);
620 };
621
622 //-------------------- compressor_mono, compressor_stereo ----------------------
623 // Mono and stereo dynamic range compressor_s
624 //
625 // USAGE:
626 // _ : compressor_mono(ratio,thresh,att,rel) : _
627 // or
628 // _,_ : compressor_stereo(ratio,thresh,att,rel) : _,_
629 //
630 // where
631 // ratio = compression ratio (1 = no compression, >1 means compression")
632 // thresh = dB level threshold above which compression kicks in
633 // att = attack time = time constant (sec) when level & compression going up
634 // rel = release time = time constant (sec) coming out of compression
635 //
636 // REFERENCES:
637 // - http://en.wikipedia.org/wiki/Dynamic_range_compression
638 // - https://ccrma.stanford.edu/~jos/filters/Nonlinear_Filter_Example_Dynamic.html
639 // - Albert Graefs <faust2pd>/examples/synth/compressor_.dsp
640 //
641
642 compressor_mono(ratio,thresh,att,rel,x) = x * compression_gain_mono(ratio,thresh,att,rel,x);
64
643
644 compressor_stereo(ratio,thresh,att,rel,x,y) = cgm*x, cgm*y with {
645 cgm = compression_gain_mono(ratio,thresh,att,rel,abs(x)+abs(y));
646 };
647
648 compression_gain_mono(ratio,thresh,att,rel) =
649 amp_follower_ud(att,rel) : linear2db : outminusindb(ratio,thresh) :
650 kneesmooth(att) : db2linear
651 with {
652 // kneesmooth(att) installs a "knee" in the dynamic-range compression,
653 // where knee smoothness is set equal to half that of the compression-attack.
654 // A general knee parameter could be used instead of tying it to att/2:
655 kneesmooth(att) = smooth(tau2pole(att/2.0));
656 // compression gain in dB:
657 outminusindb(ratio,thresh,level) = max(level-thresh,0) * (1/float(ratio)-1);
658 // Note: "float(ratio)" REQUIRED when ratio is an integer > 1!
659 };
660
661 //---------------------------- gate_demo -------------------------
662 // USAGE: _,_ : gate_demo : _,_;
663 //
664 gate_demo = bypass2(gbp,gate_stereo_demo) with {
665
666 gate_group(x) = vgroup("GATE [tooltip: Reference: http://en.wikipedia.org/wiki/Noise_gate]
", x);
667 meter_group(x) = gate_group(hgroup("[0]", x));
668 knob_group(x) = gate_group(hgroup("[1]", x));
669
670 gbp = meter_group(checkbox("[0] Bypass [tooltip: When this is checked, the gate has no
effect]"));
671
672 gateview = gate_gain_mono(gatethr,gateatt,gatehold,gaterel) : linear2db :
673 meter_group(hbargraph("[1] Gate Gain [unit:dB] [tooltip: Current gain of the gate in dB]
",
674 -50,+10)); // [style:led]
675
676 gate_stereo_demo(x,y) = attach(x,gateview(abs(x)+abs(y))),y :
677 gate_stereo(gatethr,gateatt,gatehold,gaterel);
678
679 gatethr = knob_group(hslider("[1] Threshold [unit:dB] [style:knob] [tooltip: When the
signal level falls below the Threshold (expressed in dB), the signal is muted]",
680 -30, -120, 0, 0.1));
681
682 gateatt = knob_group(hslider("[2] Attack [unit:us] [style:knob] [tooltip: Time constant in
MICROseconds (1/e smoothing time) for the gate gain to go (exponentially) from 0 (
muted) to 1 (unmuted)]",
683 10, 10, 10000, 1)) : *(0.000001) : max(1/SR);
684
685 gatehold = knob_group(hslider("[3] Hold [unit:ms] [style:knob] [tooltip: Time in ms to
keep the gate open (no muting) after the signal level falls below the Threshold]",
686 200, 0, 1000, 1)) : *(0.001) : max(1/SR);
687
688 gaterel = knob_group(hslider("[4] Release [unit:ms] [style:knob] [tooltip: Time constant
in ms (1/e smoothing time) for the gain to go (exponentially) from 1 (unmuted) to 0
(muted)]",
689 100, 0, 1000, 1)) : *(0.001) : max(1/SR);
690 };
691
692 //---------------------------- compressor_demo -------------------------
693 // USAGE: _,_ : compressor_demo : _,_;
694 //
695 compressor_demo = bypass2(cbp,compressor_stereo_demo) with {
696
697 comp_group(x) = vgroup("COMPRESSOR [tooltip: Reference: http://en.wikipedia.org/wiki/
Dynamic_range_compression]", x);
698
699 meter_group(x) = comp_group(hgroup("[0]", x));
700 knob_group(x) = comp_group(hgroup("[1]", x));
65
701
702 cbp = meter_group(checkbox("[0] Bypass [tooltip: When this is checked, the compressor has
no effect]"));
703
704 gainview =
705 compression_gain_mono(ratio,threshold,attack,release) : linear2db :
706 meter_group(hbargraph("[1] Compressor Gain [unit:dB] [tooltip: Current gain of the
compressor in dB]",
707 -50,+10));
708
709 displaygain = _,_ <: _,_,(abs,abs:+) : _,_,gainview : _,attach;
710
711 compressor_stereo_demo =
712 displaygain(compressor_stereo(ratio,threshold,attack,release)) :
713 *(makeupgain), *(makeupgain);
714
715 ctl_group(x) = knob_group(hgroup("[3] Compression Control", x));
716
717 ratio = ctl_group(hslider("[0] Ratio [style:knob] [tooltip: A compression Ratio of N means
that for each N dB increase in input signal level above Threshold, the output level
goes up 1 dB]",
718 5, 1, 20, 0.1));
719
720 threshold = ctl_group(hslider("[1] Threshold [unit:dB] [style:knob] [tooltip: When the
signal level exceeds the Threshold (in dB), its level is compressed according to the
Ratio]",
721 -30, -100, 10, 0.1));
722
723 env_group(x) = knob_group(hgroup("[4] Compression Response", x));
724
725 attack = env_group(hslider("[1] Attack [unit:ms] [style:knob] [tooltip: Time constant in
ms (1/e smoothing time) for the compression gain to approach (exponentially) a new
lower target level (the compression kicking in)]",
726 50, 0, 500, 0.1)) : *(0.001) : max(1/SR);
727
728 release = env_group(hslider("[2] Release [unit:ms] [style: knob] [tooltip: Time constant
in ms (1/e smoothing time) for the compression gain to approach (exponentially) a
new higher target level (the compression releasing)]",
729 500, 0, 1000, 0.1)) : *(0.001) : max(1/SR);
730
731 makeupgain = comp_group(hslider("[5] Makeup Gain [unit:dB] [tooltip: The compressed-signal
output level is increased by this amount (in dB) to make up for the level lost due
to compression]",
732 40, -96, 96, 0.1)) : db2linear;
733 };
734
735 //------------------------------- limiter_* ------------------------------------
736 // USAGE:
737 // _ : limiter_1176_R4_mono : _;
738 // _,_ : limiter_1176_R4_stereo : _,_;
739 //
740 // DESCRIPTION:
741 // A limiter guards against hard-clipping. It can be can be
742 // implemented as a compressor having a high threshold (near the
743 // clipping level), fast attack and release, and high ratio. Since
744 // the ratio is so high, some knee smoothing is
745 // desirable ("soft limiting"). This example is intended
746 // to get you started using compressor_* as a limiter, so all
747 // parameters are hardwired to nominal values here.
748 //
749 // REFERENCE: http://en.wikipedia.org/wiki/1176_Peak_Limiter
750 // Ratios: 4 (moderate compression), 8 (severe compression),
751 // 12 (mild limiting), or 20 to 1 (hard limiting)
752 // Att: 20-800 MICROseconds (Note: scaled by ratio in the 1176)
753 // Rel: 50-1100 ms (Note: scaled by ratio in the 1176)
754 // Mike Shipley likes 4:1 (Grammy-winning mixer for Queen, Tom Petty, etc.)
755 // Faster attack gives "more bite" (e.g. on vocals)
756 // He hears a bright, clear eq effect as well (not implemented here)
66
757 //
758 limiter_1176_R4_mono = compressor_mono(4,-6,0.0008,0.5);
759 limiter_1176_R4_stereo = compressor_stereo(4,-6,0.0008,0.5);
760
761 //========================== Schroeder Reverberators ======================
762
763 //------------------------------ jcrev,satrev ------------------------------
764 // USAGE:
765 // _ : jcrev : _,_,_,_
766 // _ : satrev : _,_
767 //
768 // DESCRIPTION:
769 // These artificial reverberators take a mono signal and output stereo
770 // (satrev) and quad (jcrev). They were implemented by John Chowning
771 // in the MUS10 computer-music language (descended from Music V by Max
772 // Mathews). They are Schroeder Reverberators, well tuned for their size.
773 // Nowadays, the more expensive freeverb is more commonly used (see the
774 // Faust examples directory).
775
776 // The reverb below was made from a listing of "RV", dated April 14, 1972,
777 // which was recovered from an old SAIL DART backup tape.
778 // John Chowning thinks this might be the one that became the
779 // well known and often copied JCREV:
780
781 jcrev = *(0.06) : allpass_chain <: comb_bank :> _ <: mix_mtx with {
782
783 rev1N = component("filter.lib").rev1;
784
785 rev12(len,g) = rev1N(2048,len,g);
786 rev14(len,g) = rev1N(4096,len,g);
787
788 allpass_chain =
789 rev2(512,347,0.7) :
790 rev2(128,113,0.7) :
791 rev2( 64, 37,0.7);
792
793 comb_bank =
794 rev12(1601,.802),
795 rev12(1867,.773),
796 rev14(2053,.753),
797 rev14(2251,.733);
798
799 mix_mtx = _,_,_,_ <: psum, -psum, asum, -asum : _,_,_,_ with {
800 psum = _,_,_,_ :> _;
801 asum = *(-1),_,*(-1),_ :> _;
802 };
803 };
804
805 // The reverb below was made from a listing of "SATREV", dated May 15, 1971,
806 // which was recovered from an old SAIL DART backup tape.
807 // John Chowning thinks this might be the one used on his
808 // often-heard brass canon sound examples, one of which can be found at
809 // https://ccrma.stanford.edu/~jos/wav/FM_BrassCanon2.wav
810
811 satrev = *(0.2) <: comb_bank :> allpass_chain <: _,*(-1) with {
812
813 rev1N = component("filter.lib").rev1;
814
815 rev11(len,g) = rev1N(1024,len,g);
816 rev12(len,g) = rev1N(2048,len,g);
817
818 comb_bank =
819 rev11( 778,.827),
820 rev11( 901,.805),
821 rev11(1011,.783),
822 rev12(1123,.764);
823
824 rev2N = component("filter.lib").rev2;
67
825
826 allpass_chain =
827 rev2N(128,125,0.7) :
828 rev2N( 64, 42,0.7) :
829 rev2N( 16, 12,0.7);
830 };
831
832 //-------------------------------- freeverb --------------------------------
833 // Freeverb is a widely used, free, open-source Schroeder reverb contributed
834 // by Jezar at Dreampoint. See <faust_distribution>/examples/freeverb.dsp
835
836 //=============== Feedback Delay Network (FDN) Reverberators ==============
837
838 //-------------------------------- fdnrev0 ---------------------------------
839 // Pure Feedback Delay Network Reverberator (generalized for easy scaling).
840 //
841 // USAGE:
842 // <1,2,4,...,N signals> <:
843 // fdnrev0(MAXDELAY,delays,BBSO,freqs,durs,loopgainmax,nonl) :>
844 // <1,2,4,...,N signals>
845 //
846 // WHERE
847 // N = 2, 4, 8, ... (power of 2)
848 // MAXDELAY = power of 2 at least as large as longest delay-line length
849 // delays = N delay lines, N a power of 2, lengths perferably coprime
850 // BBSO = odd positive integer = order of bandsplit desired at freqs
851 // freqs = NB-1 crossover frequencies separating desired frequency bands
852 // durs = NB decay times (t60) desired for the various bands
853 // loopgainmax = scalar gain between 0 and 1 used to "squelch" the reverb
854 // nonl = nonlinearity (0 to 0.999..., 0 being linear)
855 //
856 // REFERENCE:
857 // https://ccrma.stanford.edu/~jos/pasp/FDN_Reverberation.html
858 //
859 // DEPENDENCIES: filter.lib (filterbank)
860
861 fdnrev0(MAXDELAY, delays, BBSO, freqs, durs, loopgainmax, nonl)
862 = (bus(2*N) :> bus(N) : delaylines(N)) ~
863 (delayfilters(N,freqs,durs) : feedbackmatrix(N))
864 with {
865 N = count(delays);
866 NB = count(durs);
867 //assert(count(freqs)+1==NB);
868 delayval(i) = take(i+1,delays);
869 dlmax(i) = MAXDELAY; // must hardwire this from argument for now
870 //dlmax(i) = 2^max(1,nextpow2(delayval(i))) // try when slider min/max is known
871 // with { nextpow2(x) = ceil(log(x)/log(2.0)); };
872 // -1 is for feedback delay:
873 delaylines(N) = par(i,N,(delay(dlmax(i),(delayval(i)-1))));
874 delayfilters(N,freqs,durs) = par(i,N,filter(i,freqs,durs));
875 feedbackmatrix(N) = bhadamard(N);
876 vbutterfly(n) = bus(n) <: (bus(n):>bus(n/2)) , ((bus(n/2),(bus(n/2):par(i,n/2,*(-1)))) :>
bus(n/2));
877 bhadamard(2) = bus(2) <: +,-;
878 bhadamard(n) = bus(n) <: (bus(n):>bus(n/2)) , ((bus(n/2),(bus(n/2):par(i,n/2,*(-1)))) :>
bus(n/2))
879 : (bhadamard(n/2) , bhadamard(n/2));
880
881 // Experimental nonlinearities:
882 // nonlinallpass = apnl(nonl,-nonl);
883 // s = nonl*PI;
884 // nonlinallpass(x) = allpassnn(3,(s*x,s*x*x,s*x*x*x)); // filter.lib
885 nonlinallpass = _; // disabled by default (rather expensive)
886
887 filter(i,freqs,durs) = filterbank(BBSO,freqs) : par(j,NB,*(g(j,i)))
888 :> *(loopgainmax) / sqrt(N) : nonlinallpass
889 with {
890 dur(j) = take(j+1,durs);
68
891 n60(j) = dur(j)*SR; // decay time in samples
892 g(j,i) = exp(-3.0*log(10.0)*delayval(i)/n60(j));
893 // ~ 1.0 - 6.91*delayval(i)/(SR*dur(j)); // valid for large dur(j)
894 };
895 };
896
897 // ---------- prime_power_delays -----
898 // Prime Power Delay Line Lengths
899 //
900 // USAGE:
901 // bus(N) : prime_power_delays(N,pathmin,pathmax) : bus(N);
902 //
903 // WHERE
904 // N = positive integer up to 16
905 // (for higher powers of 2, extend primes array below.)
906 // pathmin = minimum acoustic ray length in the reverberator (in meters)
907 // pathmax = maximum acoustic ray length (meters) - think "room size"
908 //
909 // DEPENDENCIES:
910 // math.lib (SR, selector, take)
911 // music.lib (db2linear)
912 //
913 // REFERENCE:
914 // https://ccrma.stanford.edu/~jos/pasp/Prime_Power_Delay_Line.html
915 //
916 prime_power_delays(N,pathmin,pathmax) = par(i,N,delayvals(i)) with {
917 Np = 16;
918 primes = 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53;
919 prime(n) = primes : selector(n,Np); // math.lib
920
921 // Prime Power Bounds [matlab: floor(log(maxdel)./log(primes(53)))]
922 maxdel=8192; // more than 63 meters at 44100 samples/sec & 343 m/s
923 ppbs = 13,8,5,4, 3,3,3,3, 2,2,2,2, 2,2,2,2; // 8192 is enough for all
924 ppb(i) = take(i+1,ppbs);
925
926 // Approximate desired delay-line lengths using powers of distinct primes:
927 c = 343; // soundspeed in m/s at 20 degrees C for dry air
928 dmin = SR*pathmin/c;
929 dmax = SR*pathmax/c;
930 dl(i) = dmin * (dmax/dmin)^(i/float(N-1)); // desired delay in samples
931 ppwr(i) = floor(0.5+log(dl(i))/log(prime(i))); // best prime power
932 delayvals(i) = prime(i)^ppwr(i); // each delay a power of a distinct prime
933 };
934
935 //--------------------- stereo_reverb_tester --------------------
936 // Handy test inputs for reverberator demos below.
937
938 stereo_reverb_tester(revin_group,x,y) = inx,iny with {
939 ck_group(x) = revin_group(vgroup("[1] Input Config",x));
940 mutegain = 1 - ck_group(checkbox("[1] Mute Ext Inputs
941 [tooltip: When this is checked, the stereo external audio inputs are disabled (good
for hearing the impulse response or pink-noise response alone)]"));
942 pinkin = ck_group(checkbox("[2] Pink Noise
943 [tooltip: Pink Noise (or 1/f noise) is Constant-Q Noise (useful for adjusting the EQ
sections)]"));
944
945 impulsify = _ <: _,mem : - : >(0);
946 imp_group(x) = revin_group(hgroup("[2] Impulse Selection",x));
947 pulseL = imp_group(button("[1] Left
948 [tooltip: Send impulse into LEFT channel]")) : impulsify;
949 pulseC = imp_group(button("[2] Center
950 [tooltip: Send impulse into LEFT and RIGHT channels]")) : impulsify;
951 pulseR = imp_group(button("[3] Right
952 [tooltip: Send impulse into RIGHT channel]")) : impulsify;
953
954 inx = x*mutegain + (pulseL+pulseC) + pn;
955 iny = y*mutegain + (pulseR+pulseC) + pn;
956 pn = 0.1*pinkin*component("oscillator.lib").pink_noise;
69
957 };
958
959 //------------------------- fdnrev0_demo ---------------------------
960 // USAGE: _,_ : fdnrev0_demo(N,NB,BBSO) : _,_
961 // WHERE
962 // N = Feedback Delay Network (FDN) order
963 // = number of delay lines used = order of feedback matrix
964 // = 2, 4, 8, or 16 [extend primes array below for 32, 64, ...]
965 // NB = number of frequency bands
966 // = number of (nearly) independent T60 controls
967 // = integer 3 or greater
968 // BBSO = Butterworth band-split order
969 // = order of lowpass/highpass bandsplit used at each crossover freq
970 // = odd positive integer
971
972 fdnrev0_demo(N,NB,BBSO,x,y) = stereo_reverb_tester(revin_group,x,y)
973 <: fdnrev0(MAXDELAY,delays,BBSO,freqs,durs,loopgainmax,nonl)
974 :> *(gain),*(gain)
975 with {
976 MAXDELAY = 8192; // sync w delays and prime_power_delays above
977 defdurs = (8.4,6.5,5.0,3.8,2.7); // NB default durations (sec)
978 deffreqs = (500,1000,2000,4000); // NB-1 default crossover frequencies (Hz)
979 deflens = (56.3,63.0); // 2 default min and max path lengths
980
981 fdn_group(x) = vgroup("FEEDBACK DELAY NETWORK (FDN) REVERBERATOR, ORDER 16
982 [tooltip: See Fausts effect.lib for documentation and references]", x);
983
984 freq_group(x) = fdn_group(vgroup("[1] Band Crossover Frequencies", x));
985 t60_group(x) = fdn_group(hgroup("[2] Band Decay Times (T60)", x));
986 path_group(x) = fdn_group(vgroup("[3] Room Dimensions", x));
987 revin_group(x) = fdn_group(hgroup("[4] Input Controls", x));
988 nonl_group(x) = revin_group(vgroup("[4] Nonnlinearity",x));
989 quench_group(x) = revin_group(vgroup("[3] Reverb State",x));
990
991 nonl = nonl_group(hslider("[style:knob] [tooltip: nonlinear mode coupling]",
992 0, -0.999, 0.999, 0.001));
993 loopgainmax = 1.0-0.5*quench_group(button("[1] Quench
994 [tooltip: Hold down Quench to clear the reverberator]"));
995
996 pathmin = path_group(hslider("[1] min acoustic ray length [unit:m]
997 [tooltip: This length (in meters) determines the shortest delay-line used in the FDN
reverberator.
998 Think of it as the shortest wall-to-wall separation in the room.]",
999 46, 0.1, 63, 0.1));
1000 pathmax = path_group(hslider("[2] max acoustic ray length [unit:m]
1001 [tooltip: This length (in meters) determines the longest delay-line used in the FDN
reverberator.
1002 Think of it as the largest wall-to-wall separation in the room.]",
1003 63, 0.1, 63, 0.1));
1004
1005 durvals(i) = t60_group(vslider("[%i] %i [unit:s]
1006 [tooltip: T60 is the 60dB decay-time in seconds. For concert halls, an overall
reverberation time (T60) near 1.9 seconds is typical [Beranek 2004]. Here we may
set T60 independently in each frequency band. In real rooms, higher frequency bands
generally decay faster due to absorption and scattering.]",
1007 take(i+1,defdurs), 0.1, 10, 0.1));
1008 durs = par(i,NB,durvals(NB-1-i));
1009
1010 freqvals(i) = freq_group(hslider("[%i] Band %i upper edge in Hz [unit:Hz]
1011 [tooltip: Each delay-line signal is split into frequency-bands for separate decay-time
control in each band]",
1012 take(i+1,deffreqs), 100, 10000, 1));
1013 freqs = par(i,NB-1,freqvals(i));
1014
1015 delays = prime_power_delays(N,pathmin,pathmax);
1016
1017 gain = hslider("[3] Output Level (dB) [unit:dB]
1018 [tooltip: Output scale factor]", -40, -70, 20, 0.1) : db2linear;
70
1019 // (can cause infinite loop:) with { db2linear(x) = pow(10, x/20.0); };
1020 };
1021
1022 //------------------------------- zita_rev_fdn -------------------------------
1023 // Internal 8x8 late-reverberation FDN used in the FOSS Linux reverb zita-rev1
1024 // by Fons Adriaensen <fons@linuxaudio.org>. This is an FDN reverb with
1025 // allpass comb filters in each feedback delay in addition to the
1026 // damping filters.
1027 //
1028 // USAGE:
1029 // bus(8) : zita_rev_fdn(f1,f2,t60dc,t60m,fsmax) : bus(8)
1030 //
1031 // WHERE
1032 // f1 = crossover frequency (Hz) separating dc and midrange frequencies
1033 // f2 = frequency (Hz) above f1 where T60 = t60m/2 (see below)
1034 // t60dc = desired decay time (t60) at frequency 0 (sec)
1035 // t60m = desired decay time (t60) at midrange frequencies (sec)
1036 // fsmax = maximum sampling rate to be used (Hz)
1037 //
1038 // REFERENCES:
1039 // http://www.kokkinizita.net/linuxaudio/zita-rev1-doc/quickguide.html
1040 // https://ccrma.stanford.edu/~jos/pasp/Zita_Rev1.html
1041 //
1042 // DEPENDENCIES:
1043 // filter.lib (allpass_comb, lowpass, smooth)
1044 // math.lib (hadamard, take, etc.)
1045
1046 zita_rev_fdn(f1,f2,t60dc,t60m,fsmax) =
1047 ((bus(2*N) :> allpass_combs(N) : feedbackmatrix(N)) ~
1048 (delayfilters(N,freqs,durs) : fbdelaylines(N)))
1049 with {
1050 N = 8;
1051
1052 // Delay-line lengths in seconds:
1053 apdelays = (0.020346, 0.024421, 0.031604, 0.027333, 0.022904,
1054 0.029291, 0.013458, 0.019123); // feedforward delays in seconds
1055 tdelays = ( 0.153129, 0.210389, 0.127837, 0.256891, 0.174713,
1056 0.192303, 0.125000, 0.219991); // total delays in seconds
1057 tdelay(i) = floor(0.5 + SR*take(i+1,tdelays)); // samples
1058 apdelay(i) = floor(0.5 + SR*take(i+1,apdelays));
1059 fbdelay(i) = tdelay(i) - apdelay(i);
1060 // NOTE: Since SR is not bounded at compile time, we cant use it to
1061 // allocate delay lines; hence, the fsmax parameter:
1062 tdelaymaxfs(i) = floor(0.5 + fsmax*take(i+1,tdelays));
1063 apdelaymaxfs(i) = floor(0.5 + fsmax*take(i+1,apdelays));
1064 fbdelaymaxfs(i) = tdelaymaxfs(i) - apdelaymaxfs(i);
1065 nextpow2(x) = ceil(log(x)/log(2.0));
1066 maxapdelay(i) = int(2.0^max(1.0,nextpow2(apdelaymaxfs(i))));
1067 maxfbdelay(i) = int(2.0^max(1.0,nextpow2(fbdelaymaxfs(i))));
1068
1069 apcoeff(i) = select2(i&1,0.6,-0.6); // allpass comb-filter coefficient
1070 allpass_combs(N) =
1071 par(i,N,(allpass_comb(maxapdelay(i),apdelay(i),apcoeff(i)))); // filter.lib
1072 fbdelaylines(N) = par(i,N,(delay(maxfbdelay(i),(fbdelay(i)))));
1073 freqs = (f1,f2); durs = (t60dc,t60m);
1074 delayfilters(N,freqs,durs) = par(i,N,filter(i,freqs,durs));
1075 feedbackmatrix(N) = hadamard(N); // math.lib
1076
1077 staynormal = 10.0^(-20); // let signals decay well below LSB, but not to zero
1078
1079 special_lowpass(g,f) = smooth(p) with {
1080 // unity-dc-gain lowpass needs gain g at frequency f => quadratic formula:
1081 p = mbo2 - sqrt(max(0,mbo2*mbo2 - 1.0)); // other solution is unstable
1082 mbo2 = (1.0 - gs*c)/(1.0 - gs); // NOTE: must ensure |g|<1 (t60m finite)
1083 gs = g*g;
1084 c = cos(2.0*PI*f/float(SR));
1085 };
1086
71
1087 filter(i,freqs,durs) = lowshelf_lowpass(i)/sqrt(float(N))+staynormal
1088 with {
1089 lowshelf_lowpass(i) = gM*low_shelf1_l(g0/gM,f(1)):special_lowpass(gM,f(2));
1090 low_shelf1_l(G0,fx,x) = x + (G0-1)*lowpass(1,fx,x); // filter.lib
1091 g0 = g(0,i);
1092 gM = g(1,i);
1093 f(k) = take(k,freqs);
1094 dur(j) = take(j+1,durs);
1095 n60(j) = dur(j)*SR; // decay time in samples
1096 g(j,i) = exp(-3.0*log(10.0)*tdelay(i)/n60(j));
1097 };
1098 };
1099
1100 // Stereo input delay used by zita_rev1 in both stereo and ambisonics mode:
1101 zita_in_delay(rdel) = zita_delay_mono(rdel), zita_delay_mono(rdel) with {
1102 zita_delay_mono(rdel) = delay(8192,SR*rdel*0.001) * 0.3;
1103 };
1104
1105 // Stereo input mapping used by zita_rev1 in both stereo and ambisonics mode:
1106 zita_distrib2(N) = _,_ <: fanflip(N) with {
1107 fanflip(4) = _,_,*(-1),*(-1);
1108 fanflip(N) = fanflip(N/2),fanflip(N/2);
1109 };
1110
1111 //--------------------------- zita_rev_fdn_demo ------------------------------
1112 // zita_rev_fdn_demo = zita_rev_fdn (above) + basic GUI
1113 //
1114 // USAGE:
1115 // bus(8) : zita_rev_fdn_demo(f1,f2,t60dc,t60m,fsmax) : bus(8)
1116 //
1117 // WHERE
1118 // (args and references as for zita_rev_fdn above)
1119
1120 zita_rev_fdn_demo = zita_rev_fdn(f1,f2,t60dc,t60m,fsmax)
1121 with {
1122 fsmax = 48000.0;
1123 fdn_group(x) = hgroup(
1124 "Zita_Rev Internal FDN Reverb [tooltip: ~ Zita_Revs internal 8x8 Feedback Delay Network
(FDN) & Schroeder allpass-comb reverberator. See Fausts effect.lib for
documentation and references]",x);
1125 t60dc = fdn_group(vslider("[1] Low RT60 [unit:s] [style:knob]
1126 [style:knob]
1127 [tooltip: T60 = time (in seconds) to decay 60dB in low-frequency band]",
1128 3, 1, 8, 0.1));
1129 f1 = fdn_group(vslider("[2] LF X [unit:Hz] [style:knob]
1130 [tooltip: Crossover frequency (Hz) separating low and middle frequencies]",
1131 200, 50, 1000, 1));
1132 t60m = fdn_group(vslider("[3] Mid RT60 [unit:s] [style:knob]
1133 [tooltip: T60 = time (in seconds) to decay 60dB in middle band]",
1134 2, 1, 8, 0.1));
1135 f2 = fdn_group(vslider("[4] HF Damping [unit:Hz] [style:knob]
1136 [tooltip: Frequency (Hz) at which the high-frequency T60 is half the middle-bands T60]",
1137 6000, 1500, 0.49*fsmax, 1));
1138 };
1139
1140 //---------------------------- zita_rev1_stereo ---------------------------
1141 // Extend zita_rev_fdn to include zita_rev1 input/output mapping in stereo mode.
1142 //
1143 // USAGE:
1144 // _,_ : zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax) : _,_
1145 //
1146 // WHERE
1147 // rdel = delay (in ms) before reverberation begins (e.g., 0 to ~100 ms)
1148 // (remaining args and refs as for zita_rev_fdn above)
1149
1150 zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax) =
1151 zita_in_delay(rdel)
1152 : zita_distrib2(N)
72
1153 : zita_rev_fdn(f1,f2,t60dc,t60m,fsmax)
1154 : output2(N)
1155 with {
1156 N = 8;
1157 output2(N) = outmix(N) : *(t1),*(t1);
1158 t1 = 0.37; // zita-rev1 linearly ramps from 0 to t1 over one buffer
1159 outmix(4) = !,butterfly(2),!; // probably the result of some experimenting!
1160 outmix(N) = outmix(N/2),par(i,N/2,!);
1161 };
1162
1163 //----------------------------- zita_rev1_ambi ---------------------------
1164 // Extend zita_rev_fdn to include zita_rev1 input/output mapping in
1165 // "ambisonics mode", as provided in the Linux C++ version.
1166 //
1167 // USAGE:
1168 // _,_ : zita_rev1_ambi(rgxyz,rdel,f1,f2,t60dc,t60m,fsmax) : _,_,_,_
1169 //
1170 // WHERE
1171 // rgxyz = relative gain of lanes 1,4,2 to lane 0 in output (e.g., -9 to 9)
1172 // (remaining args and references as for zita_rev1_stereo above)
1173
1174 zita_rev1_ambi(rgxyz,rdel,f1,f2,t60dc,t60m,fsmax) =
1175 zita_in_delay(rdel)
1176 : zita_distrib2(N)
1177 : zita_rev_fdn(f1,f2,t60dc,t60m,fsmax)
1178 : output4(N) // ambisonics mode
1179 with {
1180 N=8;
1181 output4(N) = select4 : *(t0),*(t1),*(t1),*(t1);
1182 select4 = _,_,_,!,_,!,!,! : _,_,cross with { cross(x,y) = y,x; };
1183 t0 = 1.0/sqrt(2.0);
1184 t1 = t0 * 10.0^(0.05 * rgxyz);
1185 };
1186
1187 //---------------------------------- zita_rev1 ------------------------------
1188 // Example GUI for zita_rev1_stereo (mostly following the Linux zita-rev1 GUI).
1189 //
1190 // Only the dry/wet and output level parameters are "dezippered" here. If
1191 // parameters are to be varied in real time, use "smooth(0.999)" or the like
1192 // in the same way.
1193 //
1194 // REFERENCE:
1195 // http://www.kokkinizita.net/linuxaudio/zita-rev1-doc/quickguide.html
1196 //
1197 // DEPENDENCIES:
1198 // filter.lib (peak_eq_rm)
1199
1200 zita_rev1(x,y) = zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax,x,y)
1201 : out_eq : dry_wet(x,y) : out_level
1202 with {
1203
1204 fsmax = 48000.0; // highest sampling rate that will be used
1205
1206 fdn_group(x) = hgroup(
1207 "[0] Zita_Rev1 [tooltip: ~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER ALLPASS-
COMB REVERBERATOR (8x8). See Fausts effect.lib for documentation and references]",
x);
1208
1209 in_group(x) = fdn_group(hgroup("[1] Input", x));
1210
1211 rdel = in_group(vslider("[1] In Delay [unit:ms] [style:knob]
1212 [tooltip: Delay in ms before reverberation begins]",
1213 60,20,100,1));
1214
1215 freq_group(x) = fdn_group(hgroup("[2] Decay Times in Bands (see tooltips)", x));
1216
1217 f1 = freq_group(vslider("[1] LF X [unit:Hz] [style:knob]
1218 [tooltip: Crossover frequency (Hz) separating low and middle frequencies]",
73
1219 200, 50, 1000, 1));
1220
1221 t60dc = freq_group(vslider("[2] Low RT60 [unit:s] [style:knob]
1222 [style:knob] [tooltip: T60 = time (in seconds) to decay 60dB in low-frequency band]
",
1223 3, 1, 8, 0.1));
1224
1225 t60m = freq_group(vslider("[3] Mid RT60 [unit:s] [style:knob]
1226 [tooltip: T60 = time (in seconds) to decay 60dB in middle band]",
1227 2, 1, 8, 0.1));
1228
1229 f2 = freq_group(vslider("[4] HF Damping [unit:Hz] [style:knob]
1230 [tooltip: Frequency (Hz) at which the high-frequency T60 is half the middle-bands T60
]",
1231 6000, 1500, 0.49*fsmax, 1));
1232
1233 out_eq = pareq_stereo(eq1f,eq1l,eq1q) : pareq_stereo(eq2f,eq2l,eq2q);
1234 // Zolzer style peaking eq (not used in zita-rev1) (filter.lib):
1235 // pareq_stereo(eqf,eql,Q) = peak_eq(eql,eqf,eqf/Q), peak_eq(eql,eqf,eqf/Q);
1236 // Regalia-Mitra peaking eq with "Q" hard-wired near sqrt(g)/2 (filter.lib):
1237 pareq_stereo(eqf,eql,Q) = peak_eq_rm(eql,eqf,tpbt), peak_eq_rm(eql,eqf,tpbt)
1238 with {
1239 tpbt = wcT/sqrt(max(0,g)); // tan(PI*B/SR), B bw in Hz (Q^2 ~ g/4)
1240 wcT = 2*PI*eqf/SR; // peak frequency in rad/sample
1241 g = db2linear(eql); // peak gain
1242 };
1243
1244 eq1_group(x) = fdn_group(hgroup("[3] RM Peaking Equalizer 1", x));
1245
1246 eq1f = eq1_group(vslider("[1] Eq1 Freq [unit:Hz] [style:knob]
1247 [tooltip: Center-frequency of second-order Regalia-Mitra peaking equalizer section 1]"
,
1248 315, 40, 2500, 1));
1249
1250 eq1l = eq1_group(vslider("[2] Eq1 Level [unit:dB] [style:knob]
1251 [tooltip: Peak level in dB of second-order Regalia-Mitra peaking equalizer section 1]"
,
1252 0, -15, 15, 0.1));
1253
1254 eq1q = eq1_group(vslider("[3] Eq1 Q [style:knob]
1255 [tooltip: Q = centerFrequency/bandwidth of second-order peaking equalizer section 1]",
1256 3, 0.1, 10, 0.1));
1257
1258 eq2_group(x) = fdn_group(hgroup("[4] RM Peaking Equalizer 2", x));
1259
1260 eq2f = eq2_group(vslider("[1] Eq2 Freq [unit:Hz] [style:knob]
1261 [tooltip: Center-frequency of second-order Regalia-Mitra peaking equalizer section 2]"
,
1262 315, 40, 2500, 1));
1263
1264 eq2l = eq2_group(vslider("[2] Eq2 Level [unit:dB] [style:knob]
1265 [tooltip: Peak level in dB of second-order Regalia-Mitra peaking equalizer section 2]"
,
1266 0, -15, 15, 0.1));
1267
1268 eq2q = eq2_group(vslider("[3] Eq2 Q [style:knob]
1269 [tooltip: Q = centerFrequency/bandwidth of second-order peaking equalizer section 2]",
1270 3, 0.1, 10, 0.1));
1271
1272 out_group(x) = fdn_group(hgroup("[5] Output", x));
1273
1274 dry_wet(x,y) = *(wet) + dry*x, *(wet) + dry*y with {
1275 wet = 0.5*(drywet+1.0);
1276 dry = 1.0-wet;
1277 };
1278
1279 drywet = out_group(vslider("[1] Dry/Wet Mix [style:knob]
1280 [tooltip: -1 = dry, 1 = wet]",
74
1281 0, -1.0, 1.0, 0.01)) : smooth(0.999);
1282
1283 out_level = *(gain),*(gain);
1284
1285 gain = out_group(vslider("[2] Level [unit:dB] [style:knob]
1286 [tooltip: Output scale factor]", -20, -70, 40, 0.1))
1287 : smooth(0.999) : db2linear;
1288
1289 };
1290
1291 //---------------------------------- mesh_square ------------------------------
1292 // Square Rectangular Digital Waveguide Mesh
1293 //
1294 // USAGE:
1295 // bus(4*N) : mesh_square(N) : bus(4*N);
1296 //
1297 // WHERE
1298 // N = number of nodes along each edge - a power of two (1,2,4,8,...)
1299 //
1300 // EXAMPLE: Reflectively terminated mesh impulsed at one corner:
1301 // mesh_square_test(N,x) = mesh_square(N)~(busi(4*N,x)) // input to corner
1302 // with { busi(N,x) = bus(N) : par(i,N,*(-1)) : par(i,N-1,_), +(x); };
1303 // process = 1-1 : mesh_square_test(4); // all modes excited forever
1304 //
1305 // REQUIRES: math.lib.
1306 //
1307 // REFERENCE:
1308 // https://ccrma.stanford.edu/~jos/pasp/Digital_Waveguide_Mesh.html
1309
1310 // four-port scattering junction:
1311 mesh_square(1)
1312 = bus(4) <: par(i,4,*(-1)), (bus(4) :> (*(.5)) <: bus(4)) :> bus(4);
1313
1314 // rectangular NxN square waveguide mesh:
1315 mesh_square(N) = bus(4*N) : (route_inputs(N/2) : par(i,4,mesh_square(N/2)))
1316 ~(prune_feedback(N/2))
1317 : prune_outputs(N/2) : route_outputs(N/2) : bus(4*N)
1318 with {
1319 block(N) = par(i,N,!);
1320
1321 // select block i of N, block size = M:
1322 s(i,N,M) = par(j, M*N, Sv(i, j))
1323 with { Sv(i,i) = bus(N); Sv(i,j) = block(N); };
1324
1325 // prune mesh outputs down to the signals which make it out:
1326 prune_outputs(N)
1327 = bus(16*N) :
1328 block(N), bus(N), block(N), bus(N),
1329 block(N), bus(N), bus(N), block(N),
1330 bus(N), block(N), block(N), bus(N),
1331 bus(N), block(N), bus(N), block(N)
1332 : bus(8*N);
1333
1334 // collect mesh outputs into standard order (N,W,E,S):
1335 route_outputs(N)
1336 = bus(8*N)
1337 <: s(4,N,8),s(5,N,8), s(0,N,8),s(2,N,8),
1338 s(3,N,8),s(7,N,8), s(1,N,8),s(6,N,8)
1339 : bus(8*N);
1340
1341 // collect signals used as feedback:
1342 prune_feedback(N) = bus(16*N) :
1343 bus(N), block(N), bus(N), block(N),
1344 bus(N), block(N), block(N), bus(N),
1345 block(N), bus(N), bus(N), block(N),
1346 block(N), bus(N), block(N), bus(N) :
1347 bus(8*N);
1348
75
1349 // route mesh inputs (feedback, external inputs):
1350 route_inputs(N) = bus(8*N), bus(8*N)
1351 <:s(8,N,16),s(4,N,16), s(12,N,16),s(3,N,16),
1352 s(9,N,16),s(6,N,16), s(1,N,16),s(14,N,16),
1353 s(0,N,16),s(10,N,16), s(13,N,16),s(7,N,16),
1354 s(2,N,16),s(11,N,16), s(5,N,16),s(15,N,16)
1355 : bus(16*N);
1356 };

76

S-ar putea să vă placă și