mirror of
https://github.com/oSumAtrIX/free-librespot.git
synced 2025-12-20 18:34:23 +00:00
- Store and output samples as 32-bit floats instead of 16-bit integers. This provides 24-25 bits of transparency, allowing for 42-48 dB of headroom to do volume control and normalisation without throwing away bits or dropping dynamic range below 96 dB CD quality. - Perform volume control and normalisation in 64-bit arithmetic. - Add a dynamic limiter with configurable threshold, attack time, release or decay time, and steepness for the sigmoid transfer function. This mimics the native Spotify limiter, offering greater dynamic range than the old limiter, that just reduced overall gain to prevent clipping. - Make the configurable threshold also apply to the old limiter, which is still available. Resolves: librespot-org/librespot#608
105 lines
2.5 KiB
Rust
105 lines
2.5 KiB
Rust
use std::str::FromStr;
|
|
|
|
#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
|
|
pub enum Bitrate {
|
|
Bitrate96,
|
|
Bitrate160,
|
|
Bitrate320,
|
|
}
|
|
|
|
impl FromStr for Bitrate {
|
|
type Err = ();
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"96" => Ok(Bitrate::Bitrate96),
|
|
"160" => Ok(Bitrate::Bitrate160),
|
|
"320" => Ok(Bitrate::Bitrate320),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Bitrate {
|
|
fn default() -> Bitrate {
|
|
Bitrate::Bitrate160
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum NormalisationType {
|
|
Album,
|
|
Track,
|
|
}
|
|
|
|
impl FromStr for NormalisationType {
|
|
type Err = ();
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"album" => Ok(NormalisationType::Album),
|
|
"track" => Ok(NormalisationType::Track),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for NormalisationType {
|
|
fn default() -> NormalisationType {
|
|
NormalisationType::Album
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub enum NormalisationMethod {
|
|
Basic,
|
|
Dynamic,
|
|
}
|
|
|
|
impl FromStr for NormalisationMethod {
|
|
type Err = ();
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
match s {
|
|
"basic" => Ok(NormalisationMethod::Basic),
|
|
"dynamic" => Ok(NormalisationMethod::Dynamic),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for NormalisationMethod {
|
|
fn default() -> NormalisationMethod {
|
|
NormalisationMethod::Dynamic
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct PlayerConfig {
|
|
pub bitrate: Bitrate,
|
|
pub normalisation: bool,
|
|
pub normalisation_type: NormalisationType,
|
|
pub normalisation_method: NormalisationMethod,
|
|
pub normalisation_pregain: f32,
|
|
pub normalisation_threshold: f32,
|
|
pub normalisation_attack: f32,
|
|
pub normalisation_release: f32,
|
|
pub normalisation_steepness: f32,
|
|
pub gapless: bool,
|
|
pub passthrough: bool,
|
|
}
|
|
|
|
impl Default for PlayerConfig {
|
|
fn default() -> PlayerConfig {
|
|
PlayerConfig {
|
|
bitrate: Bitrate::default(),
|
|
normalisation: false,
|
|
normalisation_type: NormalisationType::default(),
|
|
normalisation_method: NormalisationMethod::default(),
|
|
normalisation_pregain: 0.0,
|
|
normalisation_threshold: -1.0,
|
|
normalisation_attack: 0.005,
|
|
normalisation_release: 0.1,
|
|
normalisation_steepness: 1.0,
|
|
gapless: true,
|
|
passthrough: false,
|
|
}
|
|
}
|
|
}
|