librespot_playback/
convert.rs1use crate::dither::{Ditherer, DithererBuilder};
2use zerocopy::{Immutable, IntoBytes};
3
4#[derive(Immutable, IntoBytes, Copy, Clone, Debug)]
5#[allow(non_camel_case_types)]
6#[repr(transparent)]
7pub struct i24([u8; 3]);
8impl i24 {
9 fn from_s24(sample: i32) -> Self {
10 #[allow(unused_variables)]
12 let [a, b, c, d] = sample.to_ne_bytes();
13 #[cfg(target_endian = "little")]
14 return Self([a, b, c]);
15 #[cfg(target_endian = "big")]
16 return Self([b, c, d]);
17 }
18}
19
20pub struct Converter {
21 ditherer: Option<Box<dyn Ditherer>>,
22}
23
24impl Converter {
25 pub fn new(dither_config: Option<DithererBuilder>) -> Self {
26 match dither_config {
27 Some(ditherer_builder) => {
28 let ditherer = (ditherer_builder)();
29 info!("Converting with ditherer: {}", ditherer.name());
30 Self {
31 ditherer: Some(ditherer),
32 }
33 }
34 None => Self { ditherer: None },
35 }
36 }
37
38 const SHIFT_S16: u8 = 15; const SHIFT_S24: u8 = 23; const SHIFT_S32: u8 = 31; const SHIFT_16_TO_24: u8 = Self::SHIFT_S24 - Self::SHIFT_S16; const SHIFT_16_TO_32: u8 = Self::SHIFT_S32 - Self::SHIFT_S16; const SCALE_S24: f64 = (1_u64 << Self::SHIFT_S24) as f64;
52
53 #[inline]
63 pub fn scale(&mut self, sample: f64, shift: u8) -> f64 {
64 match self.ditherer.as_mut() {
65 Some(d) => {
66 let dithered_16bit = sample * (1_u64 << Self::SHIFT_S16) as f64 + d.noise();
69 let scaled = dithered_16bit * (1_u64 << shift) as f64;
70 scaled.round()
71 }
72 None => {
73 let total_shift = Self::SHIFT_S16 + shift;
76 (sample * (1_u64 << total_shift) as f64).round()
77 }
78 }
79 }
80
81 #[inline]
85 pub fn clamping_scale_s24(&mut self, sample: f64) -> f64 {
86 let int_value = self.scale(sample, Self::SHIFT_16_TO_24);
87
88 let min = -Self::SCALE_S24;
90 let max = Self::SCALE_S24 - 1.0;
91
92 int_value.clamp(min, max)
93 }
94
95 #[inline]
96 pub fn f64_to_f32(&mut self, samples: &[f64]) -> Vec<f32> {
97 samples.iter().map(|sample| *sample as f32).collect()
98 }
99
100 #[inline]
101 pub fn f64_to_s32(&mut self, samples: &[f64]) -> Vec<i32> {
102 samples
103 .iter()
104 .map(|sample| self.scale(*sample, Self::SHIFT_16_TO_32) as i32)
105 .collect()
106 }
107
108 #[inline]
110 pub fn f64_to_s24(&mut self, samples: &[f64]) -> Vec<i32> {
111 samples
112 .iter()
113 .map(|sample| self.clamping_scale_s24(*sample) as i32)
114 .collect()
115 }
116
117 #[inline]
119 pub fn f64_to_s24_3(&mut self, samples: &[f64]) -> Vec<i24> {
120 samples
121 .iter()
122 .map(|sample| i24::from_s24(self.clamping_scale_s24(*sample) as i32))
123 .collect()
124 }
125
126 #[inline]
127 pub fn f64_to_s16(&mut self, samples: &[f64]) -> Vec<i16> {
128 samples
129 .iter()
130 .map(|sample| self.scale(*sample, 0) as i16)
131 .collect()
132 }
133}