614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 1 | //! db <-> linear conversions, time constants. |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 2 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 3 | /// lower bound to avoid `log10(0)`. |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 4 | pub const PEAK_FLOOR: f32 = 1e-20; |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 5 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 6 | /// inputs at or below [`PEAK_FLOOR`] clamp to `-200 dB`. |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 7 | #[must_use] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 8 | pub fn lin_to_db(x: f32) -> f32 { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 9 | if x <= PEAK_FLOOR { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 10 | -200.0 |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 11 | } else { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 12 | 20.0 * x.log10() |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 13 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 14 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 15 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 16 | #[must_use] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 17 | pub fn db_to_lin(db: f32) -> f32 { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 18 | 10.0_f32.powf(db / 20.0) |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 19 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 20 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 21 | /// one-pole smoother coefficient for `y[n] = y[n-1] + alpha * (x[n] - y[n-1])`. |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 22 | /// alpha = `1 - exp(-1 / (tau * fs))`, tau = `time_ms / 1000`. time_ms <= 0 → 1.0 (instant). |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 23 | #[must_use] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 24 | pub fn time_to_alpha(time_ms: f32, sample_rate: f32) -> f32 { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 25 | if time_ms <= 0.0 || sample_rate <= 0.0 { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 26 | 1.0 |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 27 | } else { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 28 | let tau_samples = (time_ms * 1e-3) * sample_rate; |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 29 | 1.0 - (-1.0 / tau_samples).exp() |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 30 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 31 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 32 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 33 | #[cfg(test)] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 34 | mod tests { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 35 | use super::*; |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 36 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 37 | #[test] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 38 | fn db_round_trips() { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 39 | for db in [-60.0, -20.0, -6.0, -0.1, 0.0, 3.0, 6.0_f32] { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 40 | let lin = db_to_lin(db); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 41 | let back = lin_to_db(lin); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 42 | assert!((back - db).abs() < 1e-3, "db={db} back={back}"); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 43 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 44 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 45 | |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 46 | #[test] |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 47 | fn time_to_alpha_endpoints() { |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 48 | assert_eq!(time_to_alpha(0.0, 48_000.0), 1.0); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 49 | assert!(time_to_alpha(1000.0, 48_000.0) < 0.01); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 50 | // Very fast attack: alpha approaches 1. |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 51 | let a_fast = time_to_alpha(0.01, 48_000.0); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 52 | assert!(a_fast > 0.05, "fast alpha was {a_fast}"); |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 53 | } |
614b4e43f9f3 | atagen | 2026-05-27 15:49 UTC | 54 | } |