1use truce_params::sample::Float;
2
3#[inline]
9#[must_use]
10pub fn db_to_linear<F: Float>(db: F) -> F {
11 (db * F::from_f64(std::f64::consts::LN_10 / 20.0)).exp()
12}
13
14#[inline]
18#[must_use]
19pub fn linear_to_db<F: Float>(linear: F) -> F {
20 F::from_f64(20.0) * linear.log10()
21}
22
23#[inline]
28#[must_use]
29pub fn midi_note_to_freq<F: Float>(note: u8) -> F {
30 let semitones = F::from_f64(f64::from(note) - 69.0);
31 F::from_f64(440.0) * F::from_f64(2.0).powf(semitones / F::from_f64(12.0))
32}
33
34#[inline]
40#[must_use]
41pub fn meter_display(linear_peak: f32) -> f32 {
42 if linear_peak < 1e-6 {
43 return 0.0;
44 }
45 let db = 20.0 * linear_peak.log10();
46 ((db + 60.0) / 60.0).clamp(0.0, 1.0)
48}
49
50#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn db_linear_round_trip_f64() {
61 let db = -6.0_f64;
62 let linear = db_to_linear(db);
63 let back = linear_to_db(linear);
64 assert!((back - db).abs() < 1e-10);
65 }
66
67 #[test]
68 fn db_linear_round_trip_f32() {
69 let db = -6.0_f32;
73 let linear = db_to_linear(db);
74 let back = linear_to_db(linear);
75 assert!((back - db).abs() < 1e-5);
76 }
77
78 #[test]
79 fn zero_db_is_unity_f64() {
80 let linear: f64 = db_to_linear(0.0_f64);
81 assert!((linear - 1.0).abs() < 1e-10);
82 }
83
84 #[test]
85 fn zero_db_is_unity_f32() {
86 let linear: f32 = db_to_linear(0.0_f32);
87 assert!((linear - 1.0).abs() < 1e-6);
88 }
89
90 #[test]
91 fn a4_is_440_f64() {
92 let freq: f64 = midi_note_to_freq(69);
93 assert!((freq - 440.0).abs() < 1e-10);
94 }
95
96 #[test]
97 fn a4_is_440_f32() {
98 let freq: f32 = midi_note_to_freq(69);
99 assert!((freq - 440.0).abs() < 1e-3);
100 }
101}