firewheel_core/param/
range.rs

1/// A parameter range with a linear mapping
2#[derive(Debug, Clone, Copy, PartialEq)]
3pub struct LinearRange {
4    pub min: f32,
5    pub max: f32,
6}
7
8impl LinearRange {
9    pub fn new(min: f32, max: f32) -> Self {
10        Self { min, max }
11    }
12
13    /// Map a value to its corresponding raw value for use in DSP
14    pub fn clamp(&self, val: f32) -> f32 {
15        if self.min > self.max {
16            val.min(self.min).max(self.max)
17        } else {
18            val.min(self.max).max(self.min)
19        }
20    }
21}
22
23impl Default for LinearRange {
24    fn default() -> Self {
25        Self { min: 0.0, max: 1.0 }
26    }
27}
28
29/// A parameter range that takes a normalized value in the range `[0.0, 1.0]`
30/// as input and outputs a frequency value in Hz.
31#[derive(Debug, Clone, Copy, PartialEq)]
32pub struct NormToFreqRange {
33    min_hz: f32,
34    max_hz: f32,
35
36    min_log2: f32,
37    range: f32,
38}
39
40impl NormToFreqRange {
41    pub fn new(min_hz: f32, max_hz: f32) -> Self {
42        assert!(min_hz < max_hz);
43        assert_ne!(min_hz, 0.0);
44        assert_ne!(max_hz, 0.0);
45
46        let min_log2 = min_hz.log2();
47        let range = max_hz.log2() - min_log2;
48
49        Self {
50            min_hz,
51            max_hz,
52            min_log2,
53            range,
54        }
55    }
56
57    pub fn min_hz(&self) -> f32 {
58        self.min_hz
59    }
60
61    pub fn max_hz(&self) -> f32 {
62        self.max_hz
63    }
64
65    /// Convert the normalized value in the range `[0.0, 1.0]` to the
66    /// corresponding frequency value in hz.
67    pub fn to_hz(&self, normalized: f32) -> f32 {
68        if normalized <= 0.0 {
69            return self.min_hz;
70        }
71
72        if normalized >= 1.0 {
73            return self.max_hz;
74        }
75
76        2.0f32.powf((normalized * self.range) + self.min_log2)
77    }
78}
79
80/// A parameter range that takes a normalized value in the range `[0.0, 1.0]`
81/// as input and outputs a corresponding value using a power curve.
82#[derive(Debug, Clone, Copy, PartialEq)]
83pub struct NormToPowRange {
84    pub exponent: f32,
85    min: f32,
86    max: f32,
87}
88
89impl NormToPowRange {
90    pub fn new(min: f32, max: f32, exponent: f32) -> Self {
91        assert!(min <= max);
92
93        Self { exponent, min, max }
94    }
95
96    pub fn min(&self) -> f32 {
97        self.min
98    }
99
100    pub fn max(&self) -> f32 {
101        self.max
102    }
103
104    /// Convert the normalized value in the range `[0.0, 1.0]` to the
105    /// corresponding value for use in DSP.
106    pub fn to_dsp(&self, normalized: f32) -> f32 {
107        if normalized <= 0.0 {
108            return self.min;
109        }
110
111        if normalized >= 1.0 {
112            return self.max;
113        }
114
115        normalized.powf(self.exponent) * (self.max - self.min) + self.min
116    }
117}