1#[allow(unused_imports)]
10use crate::math::FloatMath;
11
12#[derive(Debug, Clone, Copy)]
14pub struct StateVariableFilter {
15 sample_rate_hz: f32,
16 cutoff_max_hz: f32,
17 resonance: f32,
18 pre_drive: f32,
19 drive: f32,
20 freq: f32,
21 damp: f32,
22 low: f32,
23 high: f32,
24 band: f32,
25 notch: f32,
26 out_low: f32,
27 out_high: f32,
28 out_band: f32,
29 out_notch: f32,
30 out_peak: f32,
31}
32
33impl StateVariableFilter {
34 pub fn new(sample_rate_hz: f32) -> Self {
36 let mut svf = Self {
37 sample_rate_hz,
38 cutoff_max_hz: sample_rate_hz / 3.0,
39 resonance: 0.5,
40 pre_drive: 0.5,
41 drive: 0.0,
42 freq: 0.25,
43 damp: 0.0,
44 low: 0.0,
45 high: 0.0,
46 band: 0.0,
47 notch: 0.0,
48 out_low: 0.0,
49 out_high: 0.0,
50 out_band: 0.0,
51 out_notch: 0.0,
52 out_peak: 0.0,
53 };
54 svf.set_cutoff(200.0);
55 svf.set_resonance(0.5);
56 svf
57 }
58
59 pub fn set_cutoff(&mut self, cutoff_hz: f32) {
62 let cutoff_hz = cutoff_hz.clamp(1.0e-6, self.cutoff_max_hz);
63 self.freq = 2.0
65 * (core::f32::consts::PI * (cutoff_hz / (self.sample_rate_hz * 2.0)).min(0.25)).sin();
66 self.recompute_damp();
67 }
68
69 pub fn set_resonance(&mut self, resonance: f32) {
71 self.resonance = resonance.clamp(0.0, 1.0);
72 self.recompute_damp();
73 self.drive = self.pre_drive * self.resonance;
74 }
75
76 pub fn set_drive(&mut self, drive: f32) {
78 self.pre_drive = (drive * 0.1).clamp(0.0, 1.0);
79 self.drive = self.pre_drive * self.resonance;
80 }
81
82 fn recompute_damp(&mut self) {
83 let res_damp = 2.0 * (1.0 - self.resonance.powf(0.25));
84 let freq_damp = (2.0 / self.freq - self.freq * 0.5).min(2.0);
85 self.damp = res_damp.min(freq_damp);
86 }
87
88 pub fn process(&mut self, input: f32) {
90 self.pass(input);
91 self.out_low = 0.5 * self.low;
92 self.out_high = 0.5 * self.high;
93 self.out_band = 0.5 * self.band;
94 self.out_peak = 0.5 * (self.low - self.high);
95 self.out_notch = 0.5 * self.notch;
96
97 self.pass(input);
98 self.out_low += 0.5 * self.low;
99 self.out_high += 0.5 * self.high;
100 self.out_band += 0.5 * self.band;
101 self.out_peak += 0.5 * (self.low - self.high);
102 self.out_notch += 0.5 * self.notch;
103 }
104
105 #[inline]
106 fn pass(&mut self, input: f32) {
107 self.notch = input - self.damp * self.band;
108 self.low += self.freq * self.band;
109 self.high = self.notch - self.low;
110 self.band += self.freq * self.high - self.drive * self.band * self.band * self.band;
111
112 const STATE_LIMIT: f32 = 1.0e3;
118 self.low = self.low.clamp(-STATE_LIMIT, STATE_LIMIT);
119 self.high = self.high.clamp(-STATE_LIMIT, STATE_LIMIT);
120 self.band = self.band.clamp(-STATE_LIMIT, STATE_LIMIT);
121 self.notch = self.notch.clamp(-STATE_LIMIT, STATE_LIMIT);
122 }
123
124 pub fn low(&self) -> f32 {
126 self.out_low
127 }
128
129 pub fn high(&self) -> f32 {
131 self.out_high
132 }
133
134 pub fn band(&self) -> f32 {
136 self.out_band
137 }
138
139 pub fn notch(&self) -> f32 {
141 self.out_notch
142 }
143
144 pub fn peak(&self) -> f32 {
146 self.out_peak
147 }
148
149 pub fn reset(&mut self) {
151 self.low = 0.0;
152 self.high = 0.0;
153 self.band = 0.0;
154 self.notch = 0.0;
155 self.out_low = 0.0;
156 self.out_high = 0.0;
157 self.out_band = 0.0;
158 self.out_notch = 0.0;
159 self.out_peak = 0.0;
160 }
161}