1use sva_formula::{ContentHasher, HashDomain};
4
5#[derive(Clone, Copy, Debug, PartialEq)]
6pub struct Profile {
7 pub name: &'static str,
8 pub floor_db: f64,
9 pub floor_db_above_5k: f64,
10 pub ceiling_hz: f64,
11 pub precision_bits: i32,
12 pub silence_threshold_dbfs: f64,
13}
14
15pub const PSYCHOACOUSTIC_V1: Profile = Profile {
16 name: "psychoacoustic-v1",
17 floor_db: -20.0,
18 floor_db_above_5k: -25.0,
19 ceiling_hz: 20_000.0,
20 precision_bits: 24,
21 silence_threshold_dbfs: -120.0,
22};
23
24impl Profile {
25 pub fn ceiling(&self, rate: u32) -> f64 {
26 self.ceiling_hz.min(f64::from(rate) / 2.0)
27 }
28
29 pub fn half_lsb(&self) -> f64 {
30 2f64.powi(-self.precision_bits)
31 }
32
33 pub fn silence_threshold_amplitude(&self) -> f64 {
34 10f64.powf(self.silence_threshold_dbfs / 20.0)
35 }
36
37 pub fn deciding(&self) -> [u64; 6] {
39 let Profile {
40 name,
41 floor_db,
42 floor_db_above_5k,
43 ceiling_hz,
44 precision_bits,
45 silence_threshold_dbfs: _,
46 } = *self;
47 let mut named = ContentHasher::new(HashDomain::ProfileName);
48 named.text(name);
49 let named = named.finish();
50 [
51 named.0,
52 named.1,
53 floor_db.to_bits(),
54 floor_db_above_5k.to_bits(),
55 ceiling_hz.to_bits(),
56 precision_bits as u64,
57 ]
58 }
59
60 pub fn floor(&self, hz: f64) -> f64 {
61 if hz > 5_000.0 {
62 self.floor_db_above_5k
63 } else {
64 self.floor_db
65 }
66 }
67}