mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
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:
parent
b94879de62
commit
a1326ba9f4
6 changed files with 25 additions and 51 deletions
|
@ -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(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue