From f0b3b2c7e85e4d48ab940f170edd76cae87c68f9 Mon Sep 17 00:00:00 2001 From: Ash Date: Sat, 25 Jul 2020 09:38:08 +0200 Subject: [PATCH] Refactor Volume control, allow for a fixed volume option (#447) Refactored the old `--linear-volume` flag to a more generic `--volume-ctrl` flag that takes the options of `[linear, log, fixed]`. It defaults as previously to log. --- connect/src/spirc.rs | 32 +++++++++++++++++++------------- core/src/config.rs | 28 +++++++++++++++++++++++++++- src/main.rs | 17 ++++++++++++----- 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 539a4833..50dbeaa8 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -14,8 +14,7 @@ use crate::playback::mixer::Mixer; use crate::playback::player::{Player, PlayerEvent, PlayerEventChannel}; use crate::protocol; use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef}; - -use librespot_core::config::ConnectConfig; +use librespot_core::config::{ConnectConfig, VolumeCtrl}; use librespot_core::mercury::MercuryError; use librespot_core::session::Session; use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError}; @@ -80,7 +79,7 @@ pub enum SpircCommand { } struct SpircTaskConfig { - linear_volume: bool, + volume_ctrl: VolumeCtrl, autoplay: bool, } @@ -161,7 +160,11 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState { msg.set_typ(protocol::spirc::CapabilityType::kVolumeSteps); { let repeated = msg.mut_intValue(); - repeated.push(64) + if let VolumeCtrl::Fixed = config.volume_ctrl { + repeated.push(0) + } else { + repeated.push(64) + } }; msg }; @@ -170,7 +173,7 @@ fn initial_device_state(config: ConnectConfig) -> DeviceState { msg.set_typ(protocol::spirc::CapabilityType::kSupportsPlaylistV2); { let repeated = msg.mut_intValue(); - repeated.push(64) + repeated.push(1) }; msg }; @@ -230,12 +233,14 @@ fn calc_logarithmic_volume(volume: u16) -> u16 { val } -fn volume_to_mixer(volume: u16, linear_volume: bool) -> u16 { - if linear_volume { - debug!("linear volume: {}", volume); - volume - } else { - calc_logarithmic_volume(volume) +fn volume_to_mixer(volume: u16, volume_ctrl: &VolumeCtrl) -> u16 { + match volume_ctrl { + VolumeCtrl::Linear => { + debug!("linear volume: {}", volume); + volume + } + VolumeCtrl::Log => calc_logarithmic_volume(volume), + VolumeCtrl::Fixed => volume, } } @@ -274,9 +279,10 @@ impl Spirc { let volume = config.volume; let task_config = SpircTaskConfig { - linear_volume: config.linear_volume, + volume_ctrl: config.volume_ctrl.to_owned(), autoplay: config.autoplay, }; + let device = initial_device_state(config); let player_events = player.get_player_event_channel(); @@ -1292,7 +1298,7 @@ impl SpircTask { fn set_volume(&mut self, volume: u16) { self.device.set_volume(volume as u32); self.mixer - .set_volume(volume_to_mixer(volume, self.config.linear_volume)); + .set_volume(volume_to_mixer(volume, &self.config.volume_ctrl)); if let Some(cache) = self.session.cache() { cache.save_volume(Volume { volume }) } diff --git a/core/src/config.rs b/core/src/config.rs index 38be4597..db856e9d 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -84,6 +84,32 @@ pub struct ConnectConfig { pub name: String, pub device_type: DeviceType, pub volume: u16, - pub linear_volume: bool, + pub volume_ctrl: VolumeCtrl, pub autoplay: bool, } + +#[derive(Clone, Debug)] +pub enum VolumeCtrl { + Linear, + Log, + Fixed, +} + +impl FromStr for VolumeCtrl { + type Err = (); + fn from_str(s: &str) -> Result { + use self::VolumeCtrl::*; + match s.to_lowercase().as_ref() { + "linear" => Ok(Linear), + "log" => Ok(Log), + "fixed" => Ok(Fixed), + _ => Err(()), + } + } +} + +impl Default for VolumeCtrl { + fn default() -> VolumeCtrl { + VolumeCtrl::Linear + } +} diff --git a/src/main.rs b/src/main.rs index 583e6ece..552a0fbd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use url::Url; use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::cache::Cache; -use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig}; +use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; use librespot::core::session::Session; use librespot::core::version; @@ -173,10 +173,11 @@ fn setup(args: &[String]) -> Setup { "Pregain (dB) applied by volume normalisation", "PREGAIN", ) - .optflag( + .optopt( "", - "linear-volume", - "increase volume linear instead of logarithmic.", + "volume-ctrl", + "Volume control type - [linear, log, fixed]. Default is logarithmic", + "VOLUME_CTRL" ) .optflag( "", @@ -337,11 +338,17 @@ fn setup(args: &[String]) -> Setup { .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type")) .unwrap_or(DeviceType::default()); + let volume_ctrl = matches + .opt_str("volume-ctrl") + .as_ref() + .map(|volume_ctrl| VolumeCtrl::from_str(volume_ctrl).expect("Invalid volume ctrl type")) + .unwrap_or(VolumeCtrl::default()); + ConnectConfig { name: name, device_type: device_type, volume: initial_volume, - linear_volume: matches.opt_present("linear-volume"), + volume_ctrl: volume_ctrl, autoplay: matches.opt_present("autoplay"), } };