mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-03 17:59:24 +02:00
perf: inline functions in the audio hot path
This commit is contained in:
parent
9f37808851
commit
19f635f90b
12 changed files with 18 additions and 5 deletions
|
@ -452,6 +452,7 @@ impl Sink for AlsaSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkAsBytes for AlsaSink {
|
impl SinkAsBytes for AlsaSink {
|
||||||
|
#[inline]
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||||
let mut start_index = 0;
|
let mut start_index = 0;
|
||||||
let data_len = data.len();
|
let data_len = data.len();
|
||||||
|
|
|
@ -171,6 +171,7 @@ impl Drop for GstreamerSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkAsBytes for GstreamerSink {
|
impl SinkAsBytes for GstreamerSink {
|
||||||
|
#[inline]
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||||
if let Some(async_error) = &*self.async_error.lock() {
|
if let Some(async_error) = &*self.async_error.lock() {
|
||||||
return Err(SinkError::OnWrite(async_error.to_string()));
|
return Err(SinkError::OnWrite(async_error.to_string()));
|
||||||
|
|
|
@ -46,6 +46,7 @@ fn mk_sink<S: Sink + Open + 'static>(device: Option<String>, format: AudioFormat
|
||||||
// reuse code for various backends
|
// reuse code for various backends
|
||||||
macro_rules! sink_as_bytes {
|
macro_rules! sink_as_bytes {
|
||||||
() => {
|
() => {
|
||||||
|
#[inline]
|
||||||
fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
|
fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
|
||||||
use crate::convert::i24;
|
use crate::convert::i24;
|
||||||
use zerocopy::IntoBytes;
|
use zerocopy::IntoBytes;
|
||||||
|
|
|
@ -96,6 +96,7 @@ impl Sink for StdoutSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkAsBytes for StdoutSink {
|
impl SinkAsBytes for StdoutSink {
|
||||||
|
#[inline]
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||||
self.output
|
self.output
|
||||||
.as_deref_mut()
|
.as_deref_mut()
|
||||||
|
|
|
@ -137,6 +137,7 @@ impl Sink for PulseAudioSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkAsBytes for PulseAudioSink {
|
impl SinkAsBytes for PulseAudioSink {
|
||||||
|
#[inline]
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||||
let sink = self.sink.as_mut().ok_or(PulseError::NotConnected)?;
|
let sink = self.sink.as_mut().ok_or(PulseError::NotConnected)?;
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,7 @@ impl Sink for SubprocessSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SinkAsBytes for SubprocessSink {
|
impl SinkAsBytes for SubprocessSink {
|
||||||
|
#[inline]
|
||||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||||
// We get one attempted restart per write.
|
// We get one attempted restart per write.
|
||||||
// We don't want to get stuck in a restart loop.
|
// We don't want to get stuck in a restart loop.
|
||||||
|
|
|
@ -42,7 +42,6 @@ impl Converter {
|
||||||
const SHIFT_S24: u8 = 23; // 24-bit: 2^23 = 8388608
|
const SHIFT_S24: u8 = 23; // 24-bit: 2^23 = 8388608
|
||||||
const SHIFT_S32: u8 = 31; // 32-bit: 2^31 = 2147483648
|
const SHIFT_S32: u8 = 31; // 32-bit: 2^31 = 2147483648
|
||||||
|
|
||||||
|
|
||||||
/// Additional bit shifts needed to scale from 16-bit to higher bit depths.
|
/// Additional bit shifts needed to scale from 16-bit to higher bit depths.
|
||||||
/// These are the differences between the base shift amounts above.
|
/// These are the differences between the base shift amounts above.
|
||||||
const SHIFT_16_TO_24: u8 = Self::SHIFT_S24 - Self::SHIFT_S16; // 23 - 15 = 8
|
const SHIFT_16_TO_24: u8 = Self::SHIFT_S24 - Self::SHIFT_S16; // 23 - 15 = 8
|
||||||
|
@ -52,12 +51,12 @@ impl Converter {
|
||||||
const SCALE_S24: f64 = (1_u64 << Self::SHIFT_S24) as f64;
|
const SCALE_S24: f64 = (1_u64 << Self::SHIFT_S24) as f64;
|
||||||
|
|
||||||
/// Scale audio samples with optimal dithering strategy for Spotify's 16-bit source material.
|
/// Scale audio samples with optimal dithering strategy for Spotify's 16-bit source material.
|
||||||
///
|
///
|
||||||
/// Since Spotify audio is always 16-bit depth, this function:
|
/// Since Spotify audio is always 16-bit depth, this function:
|
||||||
/// 1. When dithering: applies noise at 16-bit level, preserves fractional precision,
|
/// 1. When dithering: applies noise at 16-bit level, preserves fractional precision,
|
||||||
/// then scales to target format and rounds once at the end
|
/// then scales to target format and rounds once at the end
|
||||||
/// 2. When not dithering: scales directly from normalized float to target format
|
/// 2. When not dithering: scales directly from normalized float to target format
|
||||||
///
|
///
|
||||||
/// The `shift` parameter specifies how many extra bits to shift beyond
|
/// The `shift` parameter specifies how many extra bits to shift beyond
|
||||||
/// the base 16-bit scaling (0 for 16-bit, 8 for 24-bit, 16 for 32-bit).
|
/// the base 16-bit scaling (0 for 16-bit, 8 for 24-bit, 16 for 32-bit).
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -85,11 +84,11 @@ impl Converter {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clamping_scale_s24(&mut self, sample: f64) -> f64 {
|
pub fn clamping_scale_s24(&mut self, sample: f64) -> f64 {
|
||||||
let int_value = self.scale(sample, Self::SHIFT_16_TO_24);
|
let int_value = self.scale(sample, Self::SHIFT_16_TO_24);
|
||||||
|
|
||||||
// In two's complement, there are more negative than positive values.
|
// In two's complement, there are more negative than positive values.
|
||||||
let min = -Self::SCALE_S24;
|
let min = -Self::SCALE_S24;
|
||||||
let max = Self::SCALE_S24 - 1.0;
|
let max = Self::SCALE_S24 - 1.0;
|
||||||
|
|
||||||
int_value.clamp(min, max)
|
int_value.clamp(min, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub enum AudioPacket {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AudioPacket {
|
impl AudioPacket {
|
||||||
|
#[inline]
|
||||||
pub fn samples(&self) -> AudioPacketResult<&[f64]> {
|
pub fn samples(&self) -> AudioPacketResult<&[f64]> {
|
||||||
match self {
|
match self {
|
||||||
AudioPacket::Samples(s) => Ok(s),
|
AudioPacket::Samples(s) => Ok(s),
|
||||||
|
@ -43,6 +44,7 @@ impl AudioPacket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn raw(&self) -> AudioPacketResult<&[u8]> {
|
pub fn raw(&self) -> AudioPacketResult<&[u8]> {
|
||||||
match self {
|
match self {
|
||||||
AudioPacket::Raw(d) => Ok(d),
|
AudioPacket::Raw(d) => Ok(d),
|
||||||
|
@ -50,6 +52,7 @@ impl AudioPacket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
AudioPacket::Samples(s) => s.is_empty(),
|
AudioPacket::Samples(s) => s.is_empty(),
|
||||||
|
|
|
@ -131,6 +131,7 @@ impl SymphoniaDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn ts_to_ms(&self, ts: u64) -> u32 {
|
fn ts_to_ms(&self, ts: u64) -> u32 {
|
||||||
match self.decoder.codec_params().time_base {
|
match self.decoder.codec_params().time_base {
|
||||||
Some(time_base) => {
|
Some(time_base) => {
|
||||||
|
|
|
@ -25,6 +25,7 @@ pub trait VolumeGetter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VolumeGetter for NoOpVolume {
|
impl VolumeGetter for NoOpVolume {
|
||||||
|
#[inline]
|
||||||
fn attenuation_factor(&self) -> f64 {
|
fn attenuation_factor(&self) -> f64 {
|
||||||
1.0
|
1.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ impl SoftMixer {
|
||||||
struct SoftVolume(Arc<AtomicU64>);
|
struct SoftVolume(Arc<AtomicU64>);
|
||||||
|
|
||||||
impl VolumeGetter for SoftVolume {
|
impl VolumeGetter for SoftVolume {
|
||||||
|
#[inline]
|
||||||
fn attenuation_factor(&self) -> f64 {
|
fn attenuation_factor(&self) -> f64 {
|
||||||
f64::from_bits(self.0.load(Ordering::Relaxed))
|
f64::from_bits(self.0.load(Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,10 +279,12 @@ impl PlayerEvent {
|
||||||
|
|
||||||
pub type PlayerEventChannel = mpsc::UnboundedReceiver<PlayerEvent>;
|
pub type PlayerEventChannel = mpsc::UnboundedReceiver<PlayerEvent>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn db_to_ratio(db: f64) -> f64 {
|
pub fn db_to_ratio(db: f64) -> f64 {
|
||||||
f64::powf(10.0, db / DB_VOLTAGE_RATIO)
|
f64::powf(10.0, db / DB_VOLTAGE_RATIO)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn ratio_to_db(ratio: f64) -> f64 {
|
pub fn ratio_to_db(ratio: f64) -> f64 {
|
||||||
ratio.log10() * DB_VOLTAGE_RATIO
|
ratio.log10() * DB_VOLTAGE_RATIO
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue