mirror of
https://github.com/librespot-org/librespot.git
synced 2025-10-03 09:49:31 +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 {
|
||||
#[inline]
|
||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||
let mut start_index = 0;
|
||||
let data_len = data.len();
|
||||
|
|
|
@ -171,6 +171,7 @@ impl Drop for GstreamerSink {
|
|||
}
|
||||
|
||||
impl SinkAsBytes for GstreamerSink {
|
||||
#[inline]
|
||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||
if let Some(async_error) = &*self.async_error.lock() {
|
||||
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
|
||||
macro_rules! sink_as_bytes {
|
||||
() => {
|
||||
#[inline]
|
||||
fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
|
||||
use crate::convert::i24;
|
||||
use zerocopy::IntoBytes;
|
||||
|
|
|
@ -96,6 +96,7 @@ impl Sink for StdoutSink {
|
|||
}
|
||||
|
||||
impl SinkAsBytes for StdoutSink {
|
||||
#[inline]
|
||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||
self.output
|
||||
.as_deref_mut()
|
||||
|
|
|
@ -137,6 +137,7 @@ impl Sink for PulseAudioSink {
|
|||
}
|
||||
|
||||
impl SinkAsBytes for PulseAudioSink {
|
||||
#[inline]
|
||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||
let sink = self.sink.as_mut().ok_or(PulseError::NotConnected)?;
|
||||
|
||||
|
|
|
@ -139,6 +139,7 @@ impl Sink for SubprocessSink {
|
|||
}
|
||||
|
||||
impl SinkAsBytes for SubprocessSink {
|
||||
#[inline]
|
||||
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
||||
// We get one attempted restart per write.
|
||||
// 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_S32: u8 = 31; // 32-bit: 2^31 = 2147483648
|
||||
|
||||
|
||||
/// Additional bit shifts needed to scale from 16-bit to higher bit depths.
|
||||
/// 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
|
||||
|
@ -52,12 +51,12 @@ impl Converter {
|
|||
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.
|
||||
///
|
||||
///
|
||||
/// Since Spotify audio is always 16-bit depth, this function:
|
||||
/// 1. When dithering: applies noise at 16-bit level, preserves fractional precision,
|
||||
/// then scales to target format and rounds once at the end
|
||||
/// 2. When not dithering: scales directly from normalized float to target format
|
||||
///
|
||||
///
|
||||
/// 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).
|
||||
#[inline]
|
||||
|
@ -85,11 +84,11 @@ impl Converter {
|
|||
#[inline]
|
||||
pub fn clamping_scale_s24(&mut self, sample: f64) -> f64 {
|
||||
let int_value = self.scale(sample, Self::SHIFT_16_TO_24);
|
||||
|
||||
|
||||
// In two's complement, there are more negative than positive values.
|
||||
let min = -Self::SCALE_S24;
|
||||
let max = Self::SCALE_S24 - 1.0;
|
||||
|
||||
|
||||
int_value.clamp(min, max)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ pub enum AudioPacket {
|
|||
}
|
||||
|
||||
impl AudioPacket {
|
||||
#[inline]
|
||||
pub fn samples(&self) -> AudioPacketResult<&[f64]> {
|
||||
match self {
|
||||
AudioPacket::Samples(s) => Ok(s),
|
||||
|
@ -43,6 +44,7 @@ impl AudioPacket {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn raw(&self) -> AudioPacketResult<&[u8]> {
|
||||
match self {
|
||||
AudioPacket::Raw(d) => Ok(d),
|
||||
|
@ -50,6 +52,7 @@ impl AudioPacket {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
AudioPacket::Samples(s) => s.is_empty(),
|
||||
|
|
|
@ -131,6 +131,7 @@ impl SymphoniaDecoder {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ts_to_ms(&self, ts: u64) -> u32 {
|
||||
match self.decoder.codec_params().time_base {
|
||||
Some(time_base) => {
|
||||
|
|
|
@ -25,6 +25,7 @@ pub trait VolumeGetter {
|
|||
}
|
||||
|
||||
impl VolumeGetter for NoOpVolume {
|
||||
#[inline]
|
||||
fn attenuation_factor(&self) -> f64 {
|
||||
1.0
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ impl SoftMixer {
|
|||
struct SoftVolume(Arc<AtomicU64>);
|
||||
|
||||
impl VolumeGetter for SoftVolume {
|
||||
#[inline]
|
||||
fn attenuation_factor(&self) -> f64 {
|
||||
f64::from_bits(self.0.load(Ordering::Relaxed))
|
||||
}
|
||||
|
|
|
@ -279,10 +279,12 @@ impl PlayerEvent {
|
|||
|
||||
pub type PlayerEventChannel = mpsc::UnboundedReceiver<PlayerEvent>;
|
||||
|
||||
#[inline]
|
||||
pub fn db_to_ratio(db: f64) -> f64 {
|
||||
f64::powf(10.0, db / DB_VOLTAGE_RATIO)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ratio_to_db(ratio: f64) -> f64 {
|
||||
ratio.log10() * DB_VOLTAGE_RATIO
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue