audio_widgets/eq/
common.rs

1use crate::eq::plotter;
2use scales::prelude::*;
3
4pub type Frequency = f64;
5pub type Gain = f64;
6pub type Q = f64;
7pub type Slope = usize;
8pub type Active = bool;
9
10pub type X = f64;
11pub type Y = f64;
12pub type Radius = f64;
13
14#[derive(Debug, PartialEq, Clone)]
15pub struct EQ {
16    pub bands: Vec<(EqBand, Active)>,
17    pub min_gain: Gain,
18    pub max_gain: Gain,
19    pub min_frequency: Frequency,
20    pub max_frequency: Frequency,
21    pub min_q: Q,
22    pub max_q: Q,
23    pub active: Active,
24}
25
26impl EQ {
27    pub fn new(
28        bands: Vec<(EqBand, Active)>,
29        min_gain: f64,
30        max_gain: f64,
31        min_frequency: f64,
32        max_frequency: f64,
33        min_q: f64,
34        max_q: f64,
35        active: Active,
36    ) -> EQ {
37        EQ {
38            bands,
39            min_gain,
40            max_gain,
41            min_frequency,
42            max_frequency,
43            min_q,
44            max_q,
45            active,
46        }
47    }
48
49    pub fn plot(&self, width: f64, height: f64, invert_y: bool) -> EqGraph {
50        plotter::plot_eq(self, width, height, invert_y)
51    }
52
53    pub fn calc_major_frequency_grid_markers(&self, width: f64) -> Vec<X> {
54        let x_conv = self.x_to_frequency_converter(width);
55
56        let exp_start = self.min_frequency.log10().floor() as i32;
57        let exp_end = self.max_frequency.log10().ceil() as i32;
58        let mut out = Vec::new();
59        for exp in exp_start..exp_end {
60            let f = 10f64.powi(exp);
61            if self.min_frequency < f && f < self.max_frequency {
62                let x = x_conv.convert_back(f);
63                out.push(x);
64            }
65        }
66
67        out
68    }
69
70    pub fn calc_minor_frequency_grid_markers(&self, width: f64) -> Vec<X> {
71        let x_conv = self.x_to_frequency_converter(width);
72
73        let exp_start = self.min_frequency.log10().floor() as i32;
74        let exp_end = self.max_frequency.log10().ceil() as i32;
75        let mut out = Vec::new();
76        for exp in exp_start..exp_end {
77            for factor in 2..10 {
78                let f = factor as f64 * 10f64.powi(exp);
79                if self.min_frequency < f && f < self.max_frequency {
80                    let x = x_conv.convert_back(f);
81                    out.push(x);
82                }
83            }
84        }
85
86        out
87    }
88
89    pub fn update(&mut self, index: usize, change: Parameter) {
90        if index >= self.bands.len() {
91            return;
92        }
93
94        let band = self.bands[index].to_owned();
95        if let Some(new_band) = update_band(band.clone(), change) {
96            self.bands
97                .splice(index..index + 1, std::iter::once(new_band));
98        }
99    }
100
101    pub fn x_to_frequency_converter(
102        &self,
103        width: f64,
104    ) -> (LinearScale<f64>, LogarithmicScale<f64>) {
105        let x_scale = LinearScale::new(0.0, width as f64);
106        let freq_scale = LogarithmicScale::new(self.min_frequency, self.max_frequency);
107        (x_scale, freq_scale)
108    }
109
110    pub fn y_to_gain_converter(
111        &self,
112        height: f64,
113        inverted: bool,
114    ) -> (LinearScale<f64>, LinearScale<f64>) {
115        let y_scale = if inverted {
116            LinearScale::inverted(0.0, height as f64)
117        } else {
118            LinearScale::new(0.0, height as f64)
119        };
120        let gain_scale = LinearScale::new(self.min_gain, self.max_gain);
121        (y_scale, gain_scale)
122    }
123
124    pub fn q_to_radius_converter(
125        &self,
126        width: f64,
127    ) -> (LogarithmicScale<f64>, LogarithmicScale<f64>) {
128        let q_scale = LogarithmicScale::new(self.min_q, self.max_q);
129        let radius_scale = LogarithmicScale::inverted(width / 60.0, width / 15.0);
130        (q_scale, radius_scale)
131    }
132}
133
134impl Default for EQ {
135    fn default() -> Self {
136        let mut bands = Vec::new();
137        bands.push((
138            EqBand::HighPass {
139                frequency: 100.0,
140                slope: 12,
141            },
142            true,
143        ));
144        bands.push((
145            EqBand::Bell {
146                frequency: 400.0,
147                gain: 0.0,
148                q: 1.0,
149            },
150            true,
151        ));
152        bands.push((
153            EqBand::Bell {
154                frequency: 1_000.0,
155                gain: 0.0,
156                q: 1.0,
157            },
158            true,
159        ));
160        bands.push((
161            EqBand::HighShelf {
162                frequency: 4_000.0,
163                gain: 0.0,
164            },
165            true,
166        ));
167
168        let min_gain = -12.0;
169        let max_gain = 12.0;
170        let min_frequency = 20.0;
171        let max_frequency = 24_000.0;
172        let min_q = 0.1;
173        let max_q = 100.0;
174        let active = true;
175
176        EQ {
177            bands,
178            min_gain,
179            max_gain,
180            min_frequency,
181            max_frequency,
182            min_q,
183            max_q,
184            active,
185        }
186    }
187}
188
189#[derive(Debug, PartialEq, Clone)]
190pub enum EqBand {
191    Bell {
192        frequency: Frequency,
193        gain: Gain,
194        q: Q,
195    },
196    HighShelf {
197        frequency: Frequency,
198        gain: Gain,
199    },
200    LowShelf {
201        frequency: Frequency,
202        gain: Gain,
203    },
204    HighPass {
205        frequency: Frequency,
206        slope: Slope,
207    },
208    LowPass {
209        frequency: Frequency,
210        slope: Slope,
211    },
212}
213
214impl EqBand {
215    pub fn plot(
216        &self,
217        range: impl Iterator<Item = Frequency> + 'static,
218    ) -> Box<dyn Iterator<Item = (Frequency, Gain)>> {
219        plotter::plot(self, range)
220    }
221
222    pub fn frequency(&self) -> Frequency {
223        match self {
224            EqBand::Bell { frequency, .. } => *frequency,
225            EqBand::HighShelf { frequency, .. } => *frequency,
226            EqBand::LowShelf { frequency, .. } => *frequency,
227            EqBand::HighPass { frequency, .. } => *frequency,
228            EqBand::LowPass { frequency, .. } => *frequency,
229        }
230    }
231
232    pub fn gain(&self) -> Option<Gain> {
233        match self {
234            EqBand::Bell { gain, .. } => Some(*gain),
235            EqBand::HighShelf { gain, .. } => Some(*gain),
236            EqBand::LowShelf { gain, .. } => Some(*gain),
237            EqBand::HighPass { .. } => None,
238            EqBand::LowPass { .. } => None,
239        }
240    }
241
242    pub fn q(&self) -> Option<Q> {
243        if let EqBand::Bell { q, .. } = self {
244            Some(*q)
245        } else {
246            None
247        }
248    }
249}
250
251#[derive(Debug, Clone, PartialEq)]
252pub enum Parameter {
253    Frequency(f64),
254    Gain(f64),
255    Q(f64),
256    Slope(usize),
257    Active(bool),
258}
259
260pub struct EqGraph {
261    pub band_curves: Vec<(Vec<(X, Y)>, Active)>,
262    pub sum: Vec<(X, Y)>,
263}
264
265fn update_band(band: (EqBand, bool), change: Parameter) -> Option<(EqBand, bool)> {
266    match (band, change) {
267        ((EqBand::Bell { gain, q, .. }, active), Parameter::Frequency(frequency)) => {
268            Some((EqBand::Bell { frequency, gain, q }, active))
269        }
270        ((EqBand::Bell { frequency, q, .. }, active), Parameter::Gain(gain)) => {
271            Some((EqBand::Bell { frequency, gain, q }, active))
272        }
273        (
274            (
275                EqBand::Bell {
276                    frequency, gain, ..
277                },
278                active,
279            ),
280            Parameter::Q(q),
281        ) => Some((EqBand::Bell { frequency, gain, q }, active)),
282        ((EqBand::HighShelf { gain, .. }, active), Parameter::Frequency(frequency)) => {
283            Some((EqBand::HighShelf { frequency, gain }, active))
284        }
285        ((EqBand::HighShelf { frequency, .. }, active), Parameter::Gain(gain)) => {
286            Some((EqBand::HighShelf { frequency, gain }, active))
287        }
288        ((EqBand::LowShelf { gain, .. }, active), Parameter::Frequency(frequency)) => {
289            Some((EqBand::LowShelf { frequency, gain }, active))
290        }
291        ((EqBand::LowShelf { frequency, .. }, active), Parameter::Gain(gain)) => {
292            Some((EqBand::LowShelf { frequency, gain }, active))
293        }
294        ((EqBand::HighPass { slope, .. }, active), Parameter::Frequency(frequency)) => {
295            Some((EqBand::HighPass { frequency, slope }, active))
296        }
297        ((EqBand::HighPass { frequency, .. }, active), Parameter::Slope(slope)) => {
298            Some((EqBand::HighPass { frequency, slope }, active))
299        }
300        ((EqBand::LowPass { slope, .. }, active), Parameter::Frequency(frequency)) => {
301            Some((EqBand::LowPass { frequency, slope }, active))
302        }
303        ((EqBand::LowPass { frequency, .. }, active), Parameter::Slope(slope)) => {
304            Some((EqBand::LowPass { frequency, slope }, active))
305        }
306        ((band, _), Parameter::Active(active)) => Some((band, active)),
307        _ => None,
308    }
309}