From a77465313e9d23dd76d71811d2721c83cca805db Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Sun, 21 Nov 2021 18:56:38 +0100 Subject: [PATCH] core: Add simple stereo mapping --- psst-core/src/audio/output.rs | 6 +++++ psst-core/src/audio/source.rs | 45 ++++++++++++++++++++++++++++++++++ psst-core/src/player/worker.rs | 13 +++++++--- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/psst-core/src/audio/output.rs b/psst-core/src/audio/output.rs index dff8cb30..8931e1ef 100644 --- a/psst-core/src/audio/output.rs +++ b/psst-core/src/audio/output.rs @@ -37,6 +37,7 @@ impl AudioOutput { move |this| Stream::open(device, config, callback_recv, this).unwrap() }); let sink = AudioSink { + channel_count: supported.channels(), sample_rate: supported.sample_rate(), stream_send: handle.sender(), callback_send, @@ -75,12 +76,17 @@ impl AudioOutput { #[derive(Clone)] pub struct AudioSink { + channel_count: cpal::ChannelCount, sample_rate: cpal::SampleRate, callback_send: Sender, stream_send: Sender, } impl AudioSink { + pub fn channel_count(&self) -> usize { + self.channel_count as usize + } + pub fn sample_rate(&self) -> u32 { self.sample_rate.0 } diff --git a/psst-core/src/audio/source.rs b/psst-core/src/audio/source.rs index cadc3d73..88e70a8f 100644 --- a/psst-core/src/audio/source.rs +++ b/psst-core/src/audio/source.rs @@ -25,3 +25,48 @@ impl AudioSource for Empty { 0 } } + +pub struct StereoMapper { + source: S, + input_channels: usize, + output_channels: usize, + buffer: Vec, +} + +impl StereoMapper { + pub fn new( + source: S, + input_channels: usize, + output_channels: usize, + max_input_size: usize, + ) -> Self { + Self { + source, + input_channels, + output_channels, + buffer: vec![0.0; (max_input_size / input_channels) * output_channels], + } + } + + fn input_size(&mut self, output_size: usize) -> usize { + (output_size / self.output_channels) * self.input_channels + } +} + +impl AudioSource for StereoMapper +where + S: AudioSource, +{ + fn write(&mut self, output: &mut [f32]) -> usize { + let input_max = self.input_size(output.len()).min(self.buffer.len()); + let written = self.source.write(&mut self.buffer[..input_max]); + let input = &self.buffer[..written]; + let input_frames = input.chunks_exact(self.input_channels); + let output_frames = output.chunks_exact_mut(self.output_channels); + for (i, o) in input_frames.zip(output_frames) { + o[0] = i[0]; + o[1] = i[1]; + } + output.len() + } +} diff --git a/psst-core/src/player/worker.rs b/psst-core/src/player/worker.rs index dd4ad7c4..71faaca3 100644 --- a/psst-core/src/player/worker.rs +++ b/psst-core/src/player/worker.rs @@ -20,7 +20,7 @@ use crate::{ decode::AudioDecoder, output::AudioSink, resample::{AudioResampler, ResamplingQuality, ResamplingSpec}, - source::AudioSource, + source::{AudioSource, StereoMapper}, }, error::Error, }; @@ -47,9 +47,14 @@ impl PlaybackManager { pub fn play(&mut self, loaded: LoadedPlaybackItem) { let path = loaded.file.path(); - let source = DecoderSource::new(loaded, self.event_send.clone(), self.sink.sample_rate()); - self.current = Some((path, source.actor.sender())); - self.sink.play(source); + let decoder = DecoderSource::new(loaded, self.event_send.clone(), self.sink.sample_rate()); + self.current = Some((path, decoder.actor.sender())); + self.sink.play(StereoMapper::new( + decoder, + 2, + self.sink.channel_count(), + 8 * 1024, + )); self.sink.resume(); }