1use crate::{Error, Result, SampleFormat};
2
3mod private {
4 use crate::{Result, SampleFormat};
5
6 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
8 pub struct Codec {
9 pub format: SampleFormat,
10 pub bits: u16,
12 pub container: u16,
14 pub shift: u32,
16 }
17
18 impl Codec {
19 pub fn new(format: SampleFormat, bits: u16, container: u16) -> Codec {
20 let shift = 32u32.saturating_sub(u32::from(bits));
21 Codec {
22 format,
23 bits,
24 container,
25 shift,
26 }
27 }
28
29 pub fn width(&self) -> usize {
30 usize::from(self.container)
31 }
32 }
33
34 pub trait SampleOps: Copy {
37 fn accepts_read(codec: &Codec) -> bool;
38 fn accepts_write(codec: &Codec) -> bool;
39 fn decode(bytes: &[u8], codec: &Codec) -> Self;
40 fn encode(self, codec: &Codec, out: &mut Vec<u8>) -> Result<()>;
41 }
42}
43
44pub(crate) use private::{Codec, SampleOps};
45
46pub trait Sample: Copy + private::SampleOps {}
51
52#[inline(always)]
53fn decode_int(bytes: &[u8], codec: &Codec) -> i32 {
54 match *bytes {
55 [a] => i32::from((a ^ 0x80) as i8),
56 [a, b] => ((u32::from(u16::from_le_bytes([a, b])) << codec.shift) as i32) >> codec.shift,
57 [a, b, c] => ((u32::from_le_bytes([a, b, c, 0]) << codec.shift) as i32) >> codec.shift,
58 [a, b, c, d] => ((u32::from_le_bytes([a, b, c, d]) << codec.shift) as i32) >> codec.shift,
59 _ => unreachable!("PCM container width is 1, 2, 3, or 4 after validate"),
60 }
61}
62
63#[inline(always)]
66fn encode_int(value: i32, source_bits: u16, codec: &Codec, out: &mut Vec<u8>) -> Result<()> {
67 if source_bits > codec.bits {
68 let half = 1i64 << (codec.bits - 1);
69 let v = i64::from(value);
70 if v < -half || v >= half {
71 return Err(Error::TooWide);
72 }
73 }
74 match codec.container {
75 1 => out.push((value as u8) ^ 0x80),
76 w => out.extend_from_slice(&value.to_le_bytes()[..usize::from(w)]),
77 }
78 Ok(())
79}
80
81macro_rules! int_sample {
82 ($t:ty, $bits:expr) => {
83 impl SampleOps for $t {
84 #[inline]
85 fn accepts_read(codec: &Codec) -> bool {
86 codec.format == SampleFormat::Int && codec.bits <= $bits
87 }
88 #[inline]
89 fn accepts_write(codec: &Codec) -> bool {
90 codec.format == SampleFormat::Int
91 }
92 #[inline(always)]
93 fn decode(bytes: &[u8], codec: &Codec) -> Self {
94 decode_int(bytes, codec) as $t
95 }
96 #[inline(always)]
97 fn encode(self, codec: &Codec, out: &mut Vec<u8>) -> Result<()> {
98 encode_int(i32::from(self), $bits, codec, out)
99 }
100 }
101 impl Sample for $t {}
102 };
103}
104
105int_sample!(i8, 8);
106int_sample!(i16, 16);
107int_sample!(i32, 32);
108
109impl SampleOps for f32 {
110 #[inline]
111 fn accepts_read(codec: &Codec) -> bool {
112 codec.format == SampleFormat::Float && codec.bits == 32
113 }
114 #[inline]
115 fn accepts_write(codec: &Codec) -> bool {
116 codec.format == SampleFormat::Float
117 }
118 #[inline(always)]
119 fn decode(bytes: &[u8], _codec: &Codec) -> Self {
120 match *bytes {
121 [a, b, c, d] => f32::from_le_bytes([a, b, c, d]),
122 _ => unreachable!("f32 files use 4-byte containers"),
123 }
124 }
125 #[inline(always)]
126 fn encode(self, codec: &Codec, out: &mut Vec<u8>) -> Result<()> {
127 match codec.container {
128 4 => out.extend_from_slice(&self.to_le_bytes()),
129 _ => out.extend_from_slice(&f64::from(self).to_le_bytes()),
130 }
131 Ok(())
132 }
133}
134impl Sample for f32 {}
135
136impl SampleOps for f64 {
137 #[inline]
138 fn accepts_read(codec: &Codec) -> bool {
139 codec.format == SampleFormat::Float && (codec.bits == 32 || codec.bits == 64)
140 }
141 #[inline]
142 fn accepts_write(codec: &Codec) -> bool {
143 codec.format == SampleFormat::Float && codec.bits == 64
144 }
145 #[inline(always)]
146 fn decode(bytes: &[u8], _codec: &Codec) -> Self {
147 match *bytes {
148 [a, b, c, d] => f64::from(f32::from_le_bytes([a, b, c, d])),
149 [a, b, c, d, e, f, g, h] => f64::from_le_bytes([a, b, c, d, e, f, g, h]),
150 _ => unreachable!("float files use 4-byte or 8-byte containers"),
151 }
152 }
153 #[inline(always)]
154 fn encode(self, _codec: &Codec, out: &mut Vec<u8>) -> Result<()> {
155 out.extend_from_slice(&self.to_le_bytes());
156 Ok(())
157 }
158}
159impl Sample for f64 {}
160
161#[inline]
164pub(crate) fn decode_block<S: SampleOps>(codec: &Codec, src: &[u8], dst: &mut [S]) {
165 match codec.container {
166 1 => decode_fixed::<S, 1>(codec, src, dst),
167 2 => decode_fixed::<S, 2>(codec, src, dst),
168 3 => decode_fixed::<S, 3>(codec, src, dst),
169 4 => decode_fixed::<S, 4>(codec, src, dst),
170 8 => decode_fixed::<S, 8>(codec, src, dst),
171 _ => unreachable!("container width is 1, 2, 3, 4, or 8 after validate"),
172 }
173}
174
175#[inline(always)]
176fn decode_fixed<S: SampleOps, const W: usize>(codec: &Codec, src: &[u8], dst: &mut [S]) {
177 for (d, c) in dst.iter_mut().zip(src.chunks_exact(W)) {
178 *d = S::decode(c, codec);
179 }
180}