diff --git a/README.md b/README.md index 2f3e289a..7fa7031a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ password = PASS backend = alsa device = alsa_audio_device # Given by `aplay -L` mixer = PCM -volume-control = alsa # or softvol +volume-control = alsa # or alsa_linear, or softvol onevent = command_run_on_playback_events device_name = name_in_spotify_connect bitrate = 96|160|320 diff --git a/src/alsa_mixer.rs b/src/alsa_mixer.rs index 3aad3a0e..0c036c8e 100644 --- a/src/alsa_mixer.rs +++ b/src/alsa_mixer.rs @@ -5,6 +5,7 @@ use alsa; pub struct AlsaMixer { pub device: String, pub mixer: String, + pub linear_scaling: bool, } impl AlsaMixer { @@ -17,8 +18,12 @@ impl AlsaMixer { let (min, max) = elem.get_playback_volume_range(); let volume_steps = (max - min) as f64; - let normalised_volume = - (f64::from(volume).log(65535.0) * volume_steps).floor() as i64 + min; + let normalised_volume = if self.linear_scaling { + ((f64::from(volume) / f64::from(u16::max_value())) * f64::from(volume_steps)) as i64 + + min + } else { + (f64::from(volume).log(f64::from(u16::max_value())) * volume_steps).floor() as i64 + min + }; elem.set_playback_volume_all(normalised_volume)?; Ok(()) @@ -30,6 +35,7 @@ impl Mixer for AlsaMixer { AlsaMixer { device: "default".to_string(), mixer: "Master".to_string(), + linear_scaling: false, } } fn start(&self) {} diff --git a/src/cli.rs b/src/cli.rs index c660b2ca..01952d11 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -46,7 +46,7 @@ pub fn command_line_argument_options() -> Options { opts.optopt( "", "volume-control", - "Possible values are alsa or softvol.", + "Possible values are alsa, alsa_linear, and softvol.", "CONTROLLER", ); opts.optflag("v", "verbose", "Add debug information to log."); diff --git a/src/config.rs b/src/config.rs index 31f8ef8d..21561c54 100644 --- a/src/config.rs +++ b/src/config.rs @@ -22,7 +22,7 @@ use hostname; const CONFIG_FILE: &str = "spotifyd.conf"; pub enum VolumeController { - Alsa, + Alsa { linear: bool }, SoftVol, } @@ -36,7 +36,8 @@ impl FromStr for VolumeController { type Err = (); fn from_str(s: &str) -> Result { match &*s.to_uppercase() { - "ALSA" => Ok(VolumeController::Alsa), + "ALSA" => Ok(VolumeController::Alsa { linear: false }), + "ALSA_LINEAR" => Ok(VolumeController::Alsa { linear: true }), "SOFTVOL" => Ok(VolumeController::SoftVol), _ => Err(()), } diff --git a/src/setup.rs b/src/setup.rs index 769cffd4..56bfec7d 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -28,7 +28,7 @@ pub fn initial_state(handle: Handle, matches: &Matches) -> main_loop::MainLoopSt let local_audio_device = config.audio_device.clone(); let local_mixer = config.mixer.clone(); let mut mixer = match config.volume_controller { - config::VolumeController::Alsa => { + config::VolumeController::Alsa { linear } => { info!("Using alsa volume controller."); Box::new(move || { Box::new(alsa_mixer::AlsaMixer { @@ -36,6 +36,7 @@ pub fn initial_state(handle: Handle, matches: &Matches) -> main_loop::MainLoopSt .clone() .unwrap_or_else(|| "default".to_string()), mixer: local_mixer.clone().unwrap_or_else(|| "Master".to_string()), + linear_scaling: linear, }) as Box }) as Box Box> }