From 347bf05dbe26d04e1e7a50c1acefb7049614787a Mon Sep 17 00:00:00 2001 From: Daniel Romero Date: Fri, 20 Jan 2017 20:39:05 +0100 Subject: [PATCH] Refactored to have apply_volume in a specifix mixer --- src/lib.rs | 1 + src/main.rs | 5 ++++- src/mixer/mod.rs | 14 +++++++++++++ src/mixer/softmixer.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ src/player.rs | 33 +++++++++--------------------- 5 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 src/mixer/mod.rs create mode 100644 src/mixer/softmixer.rs diff --git a/src/lib.rs b/src/lib.rs index 31671d0c..59e46547 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,7 @@ pub mod player; pub mod stream; pub mod util; pub mod version; +pub mod mixer; #[cfg(feature = "with-syntex")] include!(concat!(env!("OUT_DIR"), "/lib.rs")); #[cfg(not(feature = "with-syntex"))] include!("lib.in.rs"); diff --git a/src/main.rs b/src/main.rs index cfe1b9e8..038d2cea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use librespot::audio_backend::{self, BACKENDS}; use librespot::cache::{Cache, DefaultCache, NoCache}; use librespot::player::Player; use librespot::session::{Bitrate, Config, Session}; +use librespot::mixer::softmixer::SoftMixer; use librespot::version; fn usage(program: &str, opts: &getopts::Options) -> String { @@ -120,8 +121,10 @@ fn setup(args: &[String]) -> (Session, Player) { matches.opt_str("password")); session.login(credentials).unwrap(); + let mixer = SoftMixer::new(); + let device_name = matches.opt_str("device"); - let player = Player::new(session.clone(), move || { + let player = Player::new(session.clone(), Box::new(mixer), move || { (backend)(device_name.as_ref().map(AsRef::as_ref)) }); diff --git a/src/mixer/mod.rs b/src/mixer/mod.rs new file mode 100644 index 00000000..27bbdacd --- /dev/null +++ b/src/mixer/mod.rs @@ -0,0 +1,14 @@ +use std::borrow::Cow; + +pub mod softmixer; + +pub trait Mixer { + fn init(&mut self); + fn inuse(&mut self); + fn release(&mut self); + fn set(&mut self, volume: u16); + fn volume(&self) -> u16; + fn apply_volume<'a>(&mut self, data: &'a [i16]) -> Cow<'a, [i16]> { + Cow::Borrowed(data) + } +} \ No newline at end of file diff --git a/src/mixer/softmixer.rs b/src/mixer/softmixer.rs new file mode 100644 index 00000000..2dedf67b --- /dev/null +++ b/src/mixer/softmixer.rs @@ -0,0 +1,46 @@ +use super::Mixer; +use std::borrow::Cow; + +pub struct SoftMixer { + volume: u16, +} + +impl SoftMixer { + pub fn new() -> SoftMixer { + SoftMixer { + volume: 0xFFFF + } + } +} + +impl Mixer for SoftMixer { + fn init(&mut self) { + } + + fn inuse(&mut self) { + } + + fn release(&mut self) { + } + + fn set(&mut self, volume: u16) { + self.volume = volume; + } + + fn volume(&self) -> u16 { + self.volume + } + fn apply_volume<'a>(&mut self, data: &'a [i16]) -> Cow<'a, [i16]> { + if self.volume == 0xFFFF { + Cow::Borrowed(data) + } else { + Cow::Owned(data.iter() + .map(|&x| { + (x as i32 + * self.volume as i32 + / 0xFFFF) as i16 + }) + .collect()) + } + } +} \ No newline at end of file diff --git a/src/player.rs b/src/player.rs index 60a5ad01..430a38d6 100644 --- a/src/player.rs +++ b/src/player.rs @@ -7,6 +7,7 @@ use vorbis; use audio_decrypt::AudioDecrypt; use audio_backend::Sink; +use mixer::Mixer; use metadata::{FileFormat, Track, TrackRef}; use session::{Bitrate, Session}; use util::{self, ReadSeek, SpotifyId, Subfile}; @@ -74,8 +75,9 @@ enum PlayerCommand { } impl Player { - pub fn new(session: Session, sink_builder: F) -> Player - where F: FnOnce() -> Box + Send + 'static { + pub fn new(session: Session, mixer: Box, sink_builder: F) -> Player + where F: FnOnce() -> Box + Send + 'static, + M: Mixer + Send + 'static { let (cmd_tx, cmd_rx) = mpsc::channel(); let state = Arc::new(Mutex::new(PlayerState { @@ -83,7 +85,7 @@ impl Player { position_ms: 0, position_measured_at: 0, update_time: util::now_ms(), - volume: 0xFFFF, + volume: mixer.volume(), track: None, end_of_track: false, })); @@ -97,7 +99,7 @@ impl Player { observers: observers.clone(), }; - thread::spawn(move || internal.run(sink_builder())); + thread::spawn(move || internal.run(sink_builder(), mixer)); Player { commands: cmd_tx, @@ -147,21 +149,6 @@ impl Player { } } -fn apply_volume(volume: u16, data: &[i16]) -> Cow<[i16]> { - // Fast path when volume is 100% - if volume == 0xFFFF { - Cow::Borrowed(data) - } else { - Cow::Owned(data.iter() - .map(|&x| { - (x as i32 - * volume as i32 - / 0xFFFF) as i16 - }) - .collect()) - } -} - fn find_available_alternative<'a>(session: &Session, track: &'a Track) -> Option> { if track.available { Some(Cow::Borrowed(track)) @@ -229,7 +216,7 @@ fn run_onstop(session: &Session) { } impl PlayerInternal { - fn run(self, mut sink: Box) { + fn run(self, mut sink: Box, mut mixer: Box) { let mut decoder = None; loop { @@ -344,8 +331,9 @@ impl PlayerInternal { run_onstop(&self.session); } Some(PlayerCommand::Volume(vol)) => { + mixer.set(vol); self.update(|state| { - state.volume = vol; + state.volume = mixer.volume(); true }); } @@ -371,8 +359,7 @@ impl PlayerInternal { match packet { Some(Ok(packet)) => { - let buffer = apply_volume(self.state.lock().unwrap().volume, - &packet.data); + let buffer = mixer.apply_volume(&packet.data); sink.write(&buffer).unwrap(); self.update(|state| {