First round of refactoring

- DRY-ups

 - Remove incorrect optimization attempt in the libvorbis decoder,
   that skewed 0.0 samples non-linear

 - PortAudio and SDL backends do not support S24 output. The PortAudio
   bindings could, but not through this API.
This commit is contained in:
Roderick van Domburg 2021-03-18 22:06:43 +01:00
parent b94879de62
commit a1326ba9f4
6 changed files with 25 additions and 51 deletions

View file

@ -45,13 +45,7 @@ where
packet packet
.data .data
.iter() .iter()
.map(|sample| { .map(|sample| ((*sample as f64 + 0.5) / (0x7FFF as f64 + 0.5)) as f32)
if *sample == 0 {
0.0
} else {
((*sample as f64 + 0.5) / (0x7FFF as f64 + 0.5)) as f32
}
})
.collect(), .collect(),
))); )));
} }

View file

@ -52,8 +52,6 @@ fn open_device(dev_name: &str, format: AudioFormat) -> Result<(PCM, Frames), Box
// For stereo samples encoded as 32-bit float, one frame has a length of eight bytes. // For stereo samples encoded as 32-bit float, one frame has a length of eight bytes.
let mut period_size = ((SAMPLES_PER_SECOND * format.size() as u32) as f32 let mut period_size = ((SAMPLES_PER_SECOND * format.size() as u32) as f32
* (BUFFERED_LATENCY / BUFFERED_PERIODS as f32)) as Frames; * (BUFFERED_LATENCY / BUFFERED_PERIODS as f32)) as Frames;
// Set hardware parameters: 44100 Hz / stereo / 32-bit float or 16-bit signed integer
{ {
let hwp = HwParams::any(&pcm)?; let hwp = HwParams::any(&pcm)?;
hwp.set_access(Access::RWInterleaved)?; hwp.set_access(Access::RWInterleaved)?;

View file

@ -5,8 +5,8 @@ use crate::player::NUM_CHANNELS;
use jack::{ use jack::{
AsyncClient, AudioOut, Client, ClientOptions, Control, Port, ProcessHandler, ProcessScope, AsyncClient, AudioOut, Client, ClientOptions, Control, Port, ProcessHandler, ProcessScope,
}; };
use std::io;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::{io, mem};
pub struct JackSink { pub struct JackSink {
send: SyncSender<f32>, send: SyncSender<f32>,
@ -53,7 +53,7 @@ impl Open for JackSink {
let ch_r = client.register_port("out_0", AudioOut::default()).unwrap(); let ch_r = client.register_port("out_0", AudioOut::default()).unwrap();
let ch_l = client.register_port("out_1", AudioOut::default()).unwrap(); let ch_l = client.register_port("out_1", AudioOut::default()).unwrap();
// buffer for samples from librespot (~10ms) // buffer for samples from librespot (~10ms)
let (tx, rx) = sync_channel::<f32>(NUM_CHANNELS as usize * 1024 * mem::size_of::<f32>()); let (tx, rx) = sync_channel::<f32>(NUM_CHANNELS as usize * 1024 * format.size());
let jack_data = JackData { let jack_data = JackData {
rec: rx, rec: rx,
port_l: ch_l, port_l: ch_l,
@ -75,7 +75,7 @@ impl Sink for JackSink {
for s in packet.samples().iter() { for s in packet.samples().iter() {
let res = self.send.send(*s); let res = self.send.send(*s);
if res.is_err() { if res.is_err() {
error!("jackaudio: cannot write to channel"); error!("cannot write to channel");
} }
} }
Ok(()) Ok(())

View file

@ -18,10 +18,6 @@ pub enum PortAudioSink<'a> {
Option<portaudio_rs::stream::Stream<'a, i32, i32>>, Option<portaudio_rs::stream::Stream<'a, i32, i32>>,
StreamParameters<i32>, StreamParameters<i32>,
), ),
S24(
Option<portaudio_rs::stream::Stream<'a, i32, i32>>,
StreamParameters<i32>,
),
S16( S16(
Option<portaudio_rs::stream::Stream<'a, i16, i16>>, Option<portaudio_rs::stream::Stream<'a, i16, i16>>,
StreamParameters<i16>, StreamParameters<i16>,
@ -91,11 +87,10 @@ impl<'a> Open for PortAudioSink<'a> {
match format { match format {
AudioFormat::F32 => open_sink!(Self::F32, f32), AudioFormat::F32 => open_sink!(Self::F32, f32),
AudioFormat::S32 => open_sink!(Self::S32, i32), AudioFormat::S32 => open_sink!(Self::S32, i32),
AudioFormat::S24 => open_sink!(Self::S24, i32),
AudioFormat::S24_3 => {
unimplemented!("PortAudio currently does not support S24_3 output")
}
AudioFormat::S16 => open_sink!(Self::S16, i16), AudioFormat::S16 => open_sink!(Self::S16, i16),
_ => {
unimplemented!("PortAudio currently does not support {:?} output", format)
}
} }
} }
} }
@ -123,7 +118,6 @@ impl<'a> Sink for PortAudioSink<'a> {
match self { match self {
Self::F32(stream, parameters) => start_sink!(stream, parameters), Self::F32(stream, parameters) => start_sink!(stream, parameters),
Self::S32(stream, parameters) => start_sink!(stream, parameters), Self::S32(stream, parameters) => start_sink!(stream, parameters),
Self::S24(stream, parameters) => start_sink!(stream, parameters),
Self::S16(stream, parameters) => start_sink!(stream, parameters), Self::S16(stream, parameters) => start_sink!(stream, parameters),
}; };
@ -140,7 +134,6 @@ impl<'a> Sink for PortAudioSink<'a> {
match self { match self {
Self::F32(stream, _parameters) => stop_sink!(stream), Self::F32(stream, _parameters) => stop_sink!(stream),
Self::S32(stream, _parameters) => stop_sink!(stream), Self::S32(stream, _parameters) => stop_sink!(stream),
Self::S24(stream, _parameters) => stop_sink!(stream),
Self::S16(stream, _parameters) => stop_sink!(stream), Self::S16(stream, _parameters) => stop_sink!(stream),
}; };
@ -162,10 +155,6 @@ impl<'a> Sink for PortAudioSink<'a> {
let samples_s32: Vec<i32> = AudioPacket::f32_to_s32(packet.samples()); let samples_s32: Vec<i32> = AudioPacket::f32_to_s32(packet.samples());
write_sink!(stream, &samples_s32) write_sink!(stream, &samples_s32)
} }
Self::S24(stream, _parameters) => {
let samples_s24: Vec<i32> = AudioPacket::f32_to_s24(packet.samples());
write_sink!(stream, &samples_s24)
}
Self::S16(stream, _parameters) => { Self::S16(stream, _parameters) => {
let samples_s16: Vec<i16> = AudioPacket::f32_to_s16(packet.samples()); let samples_s16: Vec<i16> = AudioPacket::f32_to_s16(packet.samples());
write_sink!(stream, &samples_s16) write_sink!(stream, &samples_s16)

View file

@ -8,7 +8,6 @@ use std::{io, mem, thread, time};
pub enum SdlSink { pub enum SdlSink {
F32(AudioQueue<f32>), F32(AudioQueue<f32>),
S32(AudioQueue<i32>), S32(AudioQueue<i32>),
S24(AudioQueue<i32>),
S16(AudioQueue<i16>), S16(AudioQueue<i16>),
} }
@ -42,9 +41,10 @@ impl Open for SdlSink {
match format { match format {
AudioFormat::F32 => open_sink!(Self::F32, f32), AudioFormat::F32 => open_sink!(Self::F32, f32),
AudioFormat::S32 => open_sink!(Self::S32, i32), AudioFormat::S32 => open_sink!(Self::S32, i32),
AudioFormat::S24 => open_sink!(Self::S24, i32),
AudioFormat::S24_3 => unimplemented!("SDL currently does not support S24_3 output"),
AudioFormat::S16 => open_sink!(Self::S16, i16), AudioFormat::S16 => open_sink!(Self::S16, i16),
_ => {
unimplemented!("SDL currently does not support {:?} output", format)
}
} }
} }
} }
@ -60,7 +60,6 @@ impl Sink for SdlSink {
match self { match self {
Self::F32(queue) => start_sink!(queue), Self::F32(queue) => start_sink!(queue),
Self::S32(queue) => start_sink!(queue), Self::S32(queue) => start_sink!(queue),
Self::S24(queue) => start_sink!(queue),
Self::S16(queue) => start_sink!(queue), Self::S16(queue) => start_sink!(queue),
}; };
Ok(()) Ok(())
@ -76,7 +75,6 @@ impl Sink for SdlSink {
match self { match self {
Self::F32(queue) => stop_sink!(queue), Self::F32(queue) => stop_sink!(queue),
Self::S32(queue) => stop_sink!(queue), Self::S32(queue) => stop_sink!(queue),
Self::S24(queue) => stop_sink!(queue),
Self::S16(queue) => stop_sink!(queue), Self::S16(queue) => stop_sink!(queue),
}; };
Ok(()) Ok(())
@ -101,11 +99,6 @@ impl Sink for SdlSink {
let samples_s32: Vec<i32> = AudioPacket::f32_to_s32(packet.samples()); let samples_s32: Vec<i32> = AudioPacket::f32_to_s32(packet.samples());
queue.queue(&samples_s32) queue.queue(&samples_s32)
} }
Self::S24(queue) => {
drain_sink!(queue, mem::size_of::<i32>());
let samples_s24: Vec<i32> = AudioPacket::f32_to_s24(packet.samples());
queue.queue(&samples_s24)
}
Self::S16(queue) => { Self::S16(queue) => {
drain_sink!(queue, mem::size_of::<i16>()); drain_sink!(queue, mem::size_of::<i16>());
let samples_s16: Vec<i16> = AudioPacket::f32_to_s16(packet.samples()); let samples_s16: Vec<i16> = AudioPacket::f32_to_s16(packet.samples());

View file

@ -14,17 +14,17 @@ impl FromStr for Bitrate {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"96" => Ok(Bitrate::Bitrate96), "96" => Ok(Self::Bitrate96),
"160" => Ok(Bitrate::Bitrate160), "160" => Ok(Self::Bitrate160),
"320" => Ok(Bitrate::Bitrate320), "320" => Ok(Self::Bitrate320),
_ => Err(()), _ => Err(()),
} }
} }
} }
impl Default for Bitrate { impl Default for Bitrate {
fn default() -> Bitrate { fn default() -> Self {
Bitrate::Bitrate160 Self::Bitrate160
} }
} }
@ -52,7 +52,7 @@ impl TryFrom<&String> for AudioFormat {
} }
impl Default for AudioFormat { impl Default for AudioFormat {
fn default() -> AudioFormat { fn default() -> Self {
Self::S16 Self::S16
} }
} }
@ -64,7 +64,7 @@ impl AudioFormat {
match self { match self {
Self::S24_3 => mem::size_of::<i24>(), Self::S24_3 => mem::size_of::<i24>(),
Self::S16 => mem::size_of::<i16>(), Self::S16 => mem::size_of::<i16>(),
_ => mem::size_of::<i32>(), _ => mem::size_of::<i32>(), // S32 and S24 are both stored in i32
} }
} }
} }
@ -79,16 +79,16 @@ impl FromStr for NormalisationType {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"album" => Ok(NormalisationType::Album), "album" => Ok(Self::Album),
"track" => Ok(NormalisationType::Track), "track" => Ok(Self::Track),
_ => Err(()), _ => Err(()),
} }
} }
} }
impl Default for NormalisationType { impl Default for NormalisationType {
fn default() -> NormalisationType { fn default() -> Self {
NormalisationType::Album Self::Album
} }
} }
@ -102,16 +102,16 @@ impl FromStr for NormalisationMethod {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"basic" => Ok(NormalisationMethod::Basic), "basic" => Ok(Self::Basic),
"dynamic" => Ok(NormalisationMethod::Dynamic), "dynamic" => Ok(Self::Dynamic),
_ => Err(()), _ => Err(()),
} }
} }
} }
impl Default for NormalisationMethod { impl Default for NormalisationMethod {
fn default() -> NormalisationMethod { fn default() -> Self {
NormalisationMethod::Dynamic Self::Dynamic
} }
} }