1 use super::player::db_to_ratio; 2 use crate::convert::i24; 3 pub use crate::dither::{mk_ditherer, DithererBuilder, TriangularDitherer}; 4 5 use std::mem; 6 use std::str::FromStr; 7 use std::time::Duration; 8 9 #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] 10 pub enum Bitrate { 11 Bitrate96, 12 Bitrate160, 13 Bitrate320, 14 } 15 16 impl FromStr for Bitrate { 17 type Err = (); from_str(s: &str) -> Result<Self, Self::Err>18 fn from_str(s: &str) -> Result<Self, Self::Err> { 19 match s { 20 "96" => Ok(Self::Bitrate96), 21 "160" => Ok(Self::Bitrate160), 22 "320" => Ok(Self::Bitrate320), 23 _ => Err(()), 24 } 25 } 26 } 27 28 impl Default for Bitrate { default() -> Self29 fn default() -> Self { 30 Self::Bitrate160 31 } 32 } 33 34 #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] 35 pub enum AudioFormat { 36 F64, 37 F32, 38 S32, 39 S24, 40 S24_3, 41 S16, 42 } 43 44 impl FromStr for AudioFormat { 45 type Err = (); from_str(s: &str) -> Result<Self, Self::Err>46 fn from_str(s: &str) -> Result<Self, Self::Err> { 47 match s.to_uppercase().as_ref() { 48 "F64" => Ok(Self::F64), 49 "F32" => Ok(Self::F32), 50 "S32" => Ok(Self::S32), 51 "S24" => Ok(Self::S24), 52 "S24_3" => Ok(Self::S24_3), 53 "S16" => Ok(Self::S16), 54 _ => Err(()), 55 } 56 } 57 } 58 59 impl Default for AudioFormat { default() -> Self60 fn default() -> Self { 61 Self::S16 62 } 63 } 64 65 impl AudioFormat { 66 // not used by all backends 67 #[allow(dead_code)] size(&self) -> usize68 pub fn size(&self) -> usize { 69 match self { 70 Self::F64 => mem::size_of::<f64>(), 71 Self::F32 => mem::size_of::<f32>(), 72 Self::S24_3 => mem::size_of::<i24>(), 73 Self::S16 => mem::size_of::<i16>(), 74 _ => mem::size_of::<i32>(), // S32 and S24 are both stored in i32 75 } 76 } 77 } 78 79 #[derive(Clone, Debug, PartialEq)] 80 pub enum NormalisationType { 81 Album, 82 Track, 83 Auto, 84 } 85 86 impl FromStr for NormalisationType { 87 type Err = (); from_str(s: &str) -> Result<Self, Self::Err>88 fn from_str(s: &str) -> Result<Self, Self::Err> { 89 match s.to_lowercase().as_ref() { 90 "album" => Ok(Self::Album), 91 "track" => Ok(Self::Track), 92 "auto" => Ok(Self::Auto), 93 _ => Err(()), 94 } 95 } 96 } 97 98 impl Default for NormalisationType { default() -> Self99 fn default() -> Self { 100 Self::Auto 101 } 102 } 103 104 #[derive(Clone, Debug, PartialEq)] 105 pub enum NormalisationMethod { 106 Basic, 107 Dynamic, 108 } 109 110 impl FromStr for NormalisationMethod { 111 type Err = (); from_str(s: &str) -> Result<Self, Self::Err>112 fn from_str(s: &str) -> Result<Self, Self::Err> { 113 match s.to_lowercase().as_ref() { 114 "basic" => Ok(Self::Basic), 115 "dynamic" => Ok(Self::Dynamic), 116 _ => Err(()), 117 } 118 } 119 } 120 121 impl Default for NormalisationMethod { default() -> Self122 fn default() -> Self { 123 Self::Dynamic 124 } 125 } 126 127 #[derive(Clone)] 128 pub struct PlayerConfig { 129 pub bitrate: Bitrate, 130 pub gapless: bool, 131 pub passthrough: bool, 132 133 pub normalisation: bool, 134 pub normalisation_type: NormalisationType, 135 pub normalisation_method: NormalisationMethod, 136 pub normalisation_pregain: f64, 137 pub normalisation_threshold: f64, 138 pub normalisation_attack: Duration, 139 pub normalisation_release: Duration, 140 pub normalisation_knee: f64, 141 142 // pass function pointers so they can be lazily instantiated *after* spawning a thread 143 // (thereby circumventing Send bounds that they might not satisfy) 144 pub ditherer: Option<DithererBuilder>, 145 } 146 147 impl Default for PlayerConfig { default() -> Self148 fn default() -> Self { 149 Self { 150 bitrate: Bitrate::default(), 151 gapless: true, 152 normalisation: false, 153 normalisation_type: NormalisationType::default(), 154 normalisation_method: NormalisationMethod::default(), 155 normalisation_pregain: 0.0, 156 normalisation_threshold: db_to_ratio(-2.0), 157 normalisation_attack: Duration::from_millis(5), 158 normalisation_release: Duration::from_millis(100), 159 normalisation_knee: 1.0, 160 passthrough: false, 161 ditherer: Some(mk_ditherer::<TriangularDitherer>), 162 } 163 } 164 } 165 166 // fields are intended for volume control range in dB 167 #[derive(Clone, Copy, Debug)] 168 pub enum VolumeCtrl { 169 Cubic(f64), 170 Fixed, 171 Linear, 172 Log(f64), 173 } 174 175 impl FromStr for VolumeCtrl { 176 type Err = (); from_str(s: &str) -> Result<Self, Self::Err>177 fn from_str(s: &str) -> Result<Self, Self::Err> { 178 Self::from_str_with_range(s, Self::DEFAULT_DB_RANGE) 179 } 180 } 181 182 impl Default for VolumeCtrl { default() -> VolumeCtrl183 fn default() -> VolumeCtrl { 184 VolumeCtrl::Log(Self::DEFAULT_DB_RANGE) 185 } 186 } 187 188 impl VolumeCtrl { 189 pub const MAX_VOLUME: u16 = u16::MAX; 190 191 // Taken from: https://www.dr-lex.be/info-stuff/volumecontrols.html 192 pub const DEFAULT_DB_RANGE: f64 = 60.0; 193 from_str_with_range(s: &str, db_range: f64) -> Result<Self, <Self as FromStr>::Err>194 pub fn from_str_with_range(s: &str, db_range: f64) -> Result<Self, <Self as FromStr>::Err> { 195 use self::VolumeCtrl::*; 196 match s.to_lowercase().as_ref() { 197 "cubic" => Ok(Cubic(db_range)), 198 "fixed" => Ok(Fixed), 199 "linear" => Ok(Linear), 200 "log" => Ok(Log(db_range)), 201 _ => Err(()), 202 } 203 } 204 } 205