tuix_widgets/audio_widgets/
normalized_map.rs1pub trait NormalizedMap: 'static {
2 fn normalized_to_display(&self, normalized: f32) -> String;
3
4 fn snap(&self, normalized: f32) -> f32 {
5 normalized
6 }
7}
8
9#[derive(Debug, Clone, Copy, PartialEq)]
10pub enum DisplayDecimals {
11 Zero,
12 One,
13 Two,
14 Three,
15 Four,
16 Five
17}
18
19impl DisplayDecimals {
20 pub fn display_value(&self, value: f32) -> String {
21 match self {
22 DisplayDecimals::Zero => format!("{:.0}", value),
23 DisplayDecimals::One => format!("{:.1}", value),
24 DisplayDecimals::Two => format!("{:.2}", value),
25 DisplayDecimals::Three => format!("{:.3}", value),
26 DisplayDecimals::Four => format!("{:.4}", value),
27 DisplayDecimals::Five => format!("{:.5}", value),
28 }
29 }
30}
31
32impl Default for DisplayDecimals {
33 fn default() -> Self {
34 DisplayDecimals::One
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq)]
39pub enum ValueScaling {
40 Linear,
41 Power(f32),
42 Frequency,
43}
44
45impl ValueScaling {
46 pub fn normalized_to_value(&self, normalized: f32, min: f32, max: f32) -> f32 {
47 if normalized <= 0.0 {
48 return min;
49 } else if normalized >= 1.0 {
50 return max;
51 }
52
53 let map = |x: f32| -> f32 {
54 (x * (max - min)) + min
55 };
56
57 match self {
58 ValueScaling::Linear => map(normalized),
59
60 ValueScaling::Power(exponent) => map(normalized.powf(*exponent)),
61
62 ValueScaling::Frequency => {
63 let minl = min.log2();
64 let range = max.log2() - minl;
65 2.0f32.powf((normalized * range) + minl)
66 }
67 }
68 }
69
70 pub fn value_to_normalized(&self, value: f32, min: f32, max: f32) -> f32 {
71 if value <= min {
72 return 0.0;
73 } else if value >= max {
74 return 1.0;
75 }
76
77 let unmap = |x: f32| -> f32 {
78 (x - min) / (max - min)
79 };
80
81 match self {
82 ValueScaling::Linear => unmap(value),
83
84 ValueScaling::Power(exponent) => unmap(value).powf(1.0 / *exponent),
85
86 ValueScaling::Frequency => {
87 let minl = min.log2();
88 let range = max.log2() - minl;
89 (value.log2() - minl) / range
90 }
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
96pub struct GenericMap {
97 min: f32,
98 max: f32,
99 span_recip: f32, value_scaling: ValueScaling,
102
103 display_decimals: DisplayDecimals,
104 units: Option<String>,
105}
106
107impl GenericMap {
108 pub fn new(min: f32, max: f32, value_scaling: ValueScaling, display_decimals: DisplayDecimals, units: Option<String>) -> Self {
109 assert!(min < max);
110
111 Self {
112 min,
113 max,
114 span_recip: 1.0 / (max - min),
115 value_scaling,
116 display_decimals,
117 units,
118 }
119 }
120
121 pub fn min(&self) -> f32 {
122 self.min
123 }
124 pub fn max(&self) -> f32 {
125 self.max
126 }
127
128 pub fn value_scaling(&self) -> &ValueScaling {
129 &self.value_scaling
130 }
131
132 #[inline]
133 pub fn normalized_to_value(&self, normalized: f32) -> f32 {
134 self.value_scaling.normalized_to_value(normalized, self.min, self.max)
135 }
136
137 #[inline]
138 pub fn value_to_normalized(&self, value: f32) -> f32 {
139 self.value_scaling.value_to_normalized(value, self.min, self.max)
140 }
141
142 #[inline]
143 pub fn clamp_value(&self, value: f32) -> f32 {
144 value.min(self.max).max(self.min)
145 }
146}
147
148impl NormalizedMap for GenericMap {
149 fn normalized_to_display(&self, normalized: f32) -> String {
150 let mut s = self.display_decimals.display_value(self.normalized_to_value(normalized));
151 if let Some(units) = &self.units {
152 s += units;
153 }
154 s
155 }
156}
157
158#[derive(Debug, Clone)]
159pub struct DecibelMap {
160 min: f32,
161 max: f32,
162
163 value_scaling: ValueScaling,
164
165 display_decimals: DisplayDecimals,
166 display_units: bool,
167}
168
169impl DecibelMap {
170 pub fn new(min_db: f32, max_db: f32, value_scaling: ValueScaling, display_decimals: DisplayDecimals, display_units: bool) -> Self {
171 assert!(min_db < max_db);
172
173 Self {
174 min: min_db,
175 max: max_db,
176 value_scaling,
177 display_decimals,
178 display_units,
179 }
180 }
181
182 pub fn min_db(&self) -> f32 {
183 self.min
184 }
185 pub fn max_db(&self) -> f32 {
186 self.max
187 }
188
189 pub fn value_scaling(&self) -> &ValueScaling {
190 &self.value_scaling
191 }
192
193 #[inline]
194 pub fn normalized_to_db(&self, normalized: f32) -> f32 {
195 self.value_scaling.normalized_to_value(normalized, self.min, self.max)
196 }
197
198 #[inline]
199 pub fn normalized_to_amplitude(&self, normalized: f32) -> f32 {
200 db_to_amplitude(self.value_scaling.normalized_to_value(normalized, self.min, self.max))
201 }
202
203 #[inline]
204 pub fn db_to_normalized(&self, db: f32) -> f32 {
205 self.value_scaling.value_to_normalized(db, self.min, self.max)
206 }
207
208 #[inline]
209 pub fn amplitude_to_normalized(&self, amplitude: f32) -> f32 {
210 let db = amplitude_to_db(amplitude);
211 self.db_to_normalized(db)
212 }
213
214 #[inline]
215 pub fn clamp_db(&self, db: f32) -> f32 {
216 db.min(self.max).max(self.min)
217 }
218}
219
220impl NormalizedMap for DecibelMap {
221 fn normalized_to_display(&self, normalized: f32) -> String {
222 let mut s = self.display_decimals.display_value(self.normalized_to_db(normalized));
223 if self.display_units {
224 s += " dB"
225 }
226 s
227 }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq)]
231pub enum FrequencyDisplayMode {
232 OnlyHz(DisplayDecimals),
233 HzThenKHz {
234 under_1k: DisplayDecimals,
235 over_1k: DisplayDecimals,
236 }
237}
238
239impl Default for FrequencyDisplayMode {
240 fn default() -> Self {
241 FrequencyDisplayMode::HzThenKHz {
242 under_1k: DisplayDecimals::One,
243 over_1k: DisplayDecimals::Two,
244 }
245 }
246}
247
248#[derive(Debug, Clone)]
249pub struct FrequencyMap {
250 min: f32,
251 max: f32,
252
253 value_scaling: ValueScaling,
254
255 display_mode: FrequencyDisplayMode,
256 display_units: bool,
257}
258
259impl FrequencyMap {
260 pub fn new(
261 min_hz: f32,
262 max_hz: f32,
263 value_scaling: ValueScaling,
264 display_mode: FrequencyDisplayMode,
265 display_units: bool,
266 ) -> Self {
267 assert!(min_hz < max_hz);
268
269 Self {
270 min: min_hz,
271 max: max_hz,
272 value_scaling,
273 display_mode,
274 display_units,
275 }
276 }
277
278 pub fn min_hz(&self) -> f32 {
279 self.min
280 }
281 pub fn max_hz(&self) -> f32 {
282 self.max
283 }
284
285 pub fn value_scaling(&self) -> &ValueScaling {
286 &self.value_scaling
287 }
288
289 #[inline]
290 pub fn normalized_to_hz(&self, normalized: f32) -> f32 {
291 self.value_scaling.normalized_to_value(normalized, self.min, self.max)
292 }
293
294 #[inline]
295 pub fn hz_to_normalized(&self, hz: f32) -> f32 {
296 self.value_scaling.value_to_normalized(hz, self.min, self.max)
297 }
298
299 #[inline]
300 pub fn clamp_hz(&self, hz: f32) -> f32 {
301 hz.min(self.max).max(self.min)
302 }
303}
304
305impl NormalizedMap for FrequencyMap {
306 fn normalized_to_display(&self, normalized: f32) -> String {
307 let hz = self.normalized_to_hz(normalized);
308
309 match self.display_mode {
310 FrequencyDisplayMode::OnlyHz(display_decimals) => {
311 let mut s = display_decimals.display_value(hz);
312 if self.display_units {
313 s += " Hz"
314 }
315 s
316 }
317 FrequencyDisplayMode::HzThenKHz { under_1k, over_1k } => {
318 if hz < 1_000.0 {
319 let mut s = under_1k.display_value(hz);
320 if self.display_units {
321 s += " Hz"
322 }
323 s
324 } else {
325 let mut s = over_1k.display_value(hz / 1_000.0);
326 if self.display_units {
327 s += " kHz"
328 }
329 s
330 }
331 }
332 }
333 }
334}
335
336#[derive(Clone)]
337pub struct IntMap {
338 min: i32,
339 max: i32,
340 span: f32, display_map: Option<&'static dyn Fn(i32) -> String>,
343}
344
345impl IntMap {
346 pub fn new(min: i32, max: i32, display_map: Option<&'static dyn Fn(i32) -> String>) -> Self {
347 assert!(min <= max);
348
349 Self {
350 min,
351 max,
352 span: (max - min) as f32,
353 display_map,
354 }
355 }
356
357 pub fn min(&self) -> i32 {
358 self.min
359 }
360 pub fn max(&self) -> i32 {
361 self.max
362 }
363
364 #[inline]
365 pub fn normalized_to_int(&self, normalized: f32) -> i32 {
366 if normalized <= 0.0 {
367 return self.min;
368 } else if normalized >= 1.0 {
369 return self.max;
370 }
371
372 (normalized * self.span).round() as i32
373 }
374
375 #[inline]
376 pub fn int_to_normalized(&self, int: i32) -> f32 {
377 if self.min == self.max {
378 0.0
381 } else {
382 if int <= self.min {
383 return 0.0;
384 } else if int >= self.max {
385 return 1.0;
386 }
387
388 (int as f32 - self.min as f32) / self.span
389 }
390 }
391
392 #[inline]
393 pub fn clamp_int(&self, int: i32) -> i32 {
394 int.min(self.max).max(self.min)
395 }
396}
397
398impl NormalizedMap for IntMap {
399 fn normalized_to_display(&self, normalized: f32) -> String {
400 let int = self.normalized_to_int(normalized);
401
402 if let Some(display_map) = self.display_map {
403 (display_map)(int)
404 } else {
405 format!("{}", int)
407 }
408 }
409
410 fn snap(&self, normalized: f32) -> f32 {
411 let int = self.normalized_to_int(normalized);
412 self.int_to_normalized(int)
413 }
414}
415
416#[inline]
417pub fn db_to_amplitude(db: f32) -> f32 {
418 10.0f32.powf(db * 1.0 / 20.0)
419}
420
421#[inline]
422pub fn amplitude_to_db(amp: f32) -> f32 {
423 20.0f32 * amp.log10()
424}