1use std::borrow::Cow;
2
3use crate::Error;
4
5#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum Format {
17 U8,
19 S16,
21 S32,
23 #[default]
26 F32,
27 U8Planar,
29 S16Planar,
31 S32Planar,
33 F32Planar,
35}
36
37impl Format {
38 pub fn bytes_per_sample(self) -> usize {
40 match self {
41 Self::U8 | Self::U8Planar => 1,
42 Self::S16 | Self::S16Planar => 2,
43 Self::S32 | Self::S32Planar | Self::F32 | Self::F32Planar => 4,
44 }
45 }
46
47 pub fn is_planar(self) -> bool {
49 matches!(
50 self,
51 Self::U8Planar | Self::S16Planar | Self::S32Planar | Self::F32Planar
52 )
53 }
54
55 pub fn is_float(self) -> bool {
57 matches!(self, Self::F32 | Self::F32Planar)
58 }
59
60 pub fn as_interleaved_f32<'a>(self, data: &'a [u8], channels: u32) -> Result<Cow<'a, [f32]>, Error> {
66 let channels = channels as usize;
67 if channels == 0 {
68 return Err(Error::Unsupported("channel count must be > 0".into()));
69 }
70
71 let bps = self.bytes_per_sample();
72 if !data.len().is_multiple_of(bps * channels) {
73 return Err(Error::Misaligned {
74 got: data.len(),
75 expected: data.len().next_multiple_of(bps * channels),
76 });
77 }
78
79 if self == Self::F32 {
81 let (head, body, tail) = unsafe { data.align_to::<f32>() };
82 if head.is_empty() && tail.is_empty() {
83 return Ok(Cow::Borrowed(body));
84 }
85 }
86
87 Ok(Cow::Owned(self.to_interleaved_f32_owned(data, channels)))
88 }
89
90 fn to_interleaved_f32_owned(self, data: &[u8], channels: usize) -> Vec<f32> {
91 let total_samples = data.len() / self.bytes_per_sample();
92 let frames = total_samples / channels;
93 let mut out = vec![0.0f32; total_samples];
94
95 match self {
96 Self::F32 => {
97 for (i, chunk) in data.chunks_exact(4).enumerate() {
98 out[i] = f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
99 }
100 }
101 Self::F32Planar => {
102 for ch in 0..channels {
103 let plane = &data[ch * frames * 4..(ch + 1) * frames * 4];
104 for (frame, chunk) in plane.chunks_exact(4).enumerate() {
105 out[frame * channels + ch] = f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
106 }
107 }
108 }
109 Self::S16 => {
110 for (i, chunk) in data.chunks_exact(2).enumerate() {
111 let v = i16::from_le_bytes([chunk[0], chunk[1]]);
112 out[i] = (v as f32) / 32768.0;
113 }
114 }
115 Self::S16Planar => {
116 for ch in 0..channels {
117 let plane = &data[ch * frames * 2..(ch + 1) * frames * 2];
118 for (frame, chunk) in plane.chunks_exact(2).enumerate() {
119 let v = i16::from_le_bytes([chunk[0], chunk[1]]);
120 out[frame * channels + ch] = (v as f32) / 32768.0;
121 }
122 }
123 }
124 Self::S32 => {
125 for (i, chunk) in data.chunks_exact(4).enumerate() {
126 let v = i32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
127 out[i] = (v as f32) / (i32::MAX as f32 + 1.0);
128 }
129 }
130 Self::S32Planar => {
131 for ch in 0..channels {
132 let plane = &data[ch * frames * 4..(ch + 1) * frames * 4];
133 for (frame, chunk) in plane.chunks_exact(4).enumerate() {
134 let v = i32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
135 out[frame * channels + ch] = (v as f32) / (i32::MAX as f32 + 1.0);
136 }
137 }
138 }
139 Self::U8 => {
140 for (i, &b) in data.iter().enumerate() {
141 out[i] = (b as f32 - 128.0) / 128.0;
142 }
143 }
144 Self::U8Planar => {
145 for ch in 0..channels {
146 let plane = &data[ch * frames..(ch + 1) * frames];
147 for (frame, &b) in plane.iter().enumerate() {
148 out[frame * channels + ch] = (b as f32 - 128.0) / 128.0;
149 }
150 }
151 }
152 }
153
154 out
155 }
156
157 pub fn from_interleaved_f32(self, samples: &[f32], channels: u32) -> Result<Vec<u8>, Error> {
161 let channels = channels as usize;
162 if channels == 0 {
163 return Err(Error::Unsupported("channel count must be > 0".into()));
164 }
165 if !samples.len().is_multiple_of(channels) {
166 return Err(Error::Misaligned {
167 got: samples.len(),
168 expected: samples.len().next_multiple_of(channels),
169 });
170 }
171
172 let frames = samples.len() / channels;
173 let mut out = vec![0u8; samples.len() * self.bytes_per_sample()];
174
175 match self {
176 Self::F32 => {
177 for (i, &s) in samples.iter().enumerate() {
178 out[i * 4..i * 4 + 4].copy_from_slice(&s.to_le_bytes());
179 }
180 }
181 Self::F32Planar => {
182 for ch in 0..channels {
183 let plane = &mut out[ch * frames * 4..(ch + 1) * frames * 4];
184 for (frame, chunk) in plane.chunks_exact_mut(4).enumerate() {
185 chunk.copy_from_slice(&samples[frame * channels + ch].to_le_bytes());
186 }
187 }
188 }
189 Self::S16 => {
190 for (i, &s) in samples.iter().enumerate() {
191 let v = (s.clamp(-1.0, 1.0) * 32767.0).round() as i16;
192 out[i * 2..i * 2 + 2].copy_from_slice(&v.to_le_bytes());
193 }
194 }
195 Self::S16Planar => {
196 for ch in 0..channels {
197 let plane = &mut out[ch * frames * 2..(ch + 1) * frames * 2];
198 for (frame, chunk) in plane.chunks_exact_mut(2).enumerate() {
199 let v = (samples[frame * channels + ch].clamp(-1.0, 1.0) * 32767.0).round() as i16;
200 chunk.copy_from_slice(&v.to_le_bytes());
201 }
202 }
203 }
204 Self::S32 => {
205 for (i, &s) in samples.iter().enumerate() {
206 let v = (s.clamp(-1.0, 1.0) as f64 * i32::MAX as f64).round() as i32;
207 out[i * 4..i * 4 + 4].copy_from_slice(&v.to_le_bytes());
208 }
209 }
210 Self::S32Planar => {
211 for ch in 0..channels {
212 let plane = &mut out[ch * frames * 4..(ch + 1) * frames * 4];
213 for (frame, chunk) in plane.chunks_exact_mut(4).enumerate() {
214 let v =
215 (samples[frame * channels + ch].clamp(-1.0, 1.0) as f64 * i32::MAX as f64).round() as i32;
216 chunk.copy_from_slice(&v.to_le_bytes());
217 }
218 }
219 }
220 Self::U8 => {
221 for (i, &s) in samples.iter().enumerate() {
222 out[i] = ((s.clamp(-1.0, 1.0) * 127.0).round() + 128.0) as u8;
223 }
224 }
225 Self::U8Planar => {
226 for ch in 0..channels {
227 let plane = &mut out[ch * frames..(ch + 1) * frames];
228 for (frame, byte) in plane.iter_mut().enumerate() {
229 *byte = ((samples[frame * channels + ch].clamp(-1.0, 1.0) * 127.0).round() + 128.0) as u8;
230 }
231 }
232 }
233 }
234
235 Ok(out)
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn f32_interleaved_is_borrowed() {
245 let samples: Vec<f32> = vec![0.1, 0.2, 0.3, 0.4];
246 let bytes: Vec<u8> = samples.iter().flat_map(|s| s.to_le_bytes()).collect();
247 let cow = Format::F32.as_interleaved_f32(&bytes, 2).unwrap();
248 assert!(matches!(cow, Cow::Borrowed(_)));
249 assert_eq!(cow.as_ref(), samples.as_slice());
250 }
251
252 #[test]
253 fn s16_interleaved_is_owned_but_close() {
254 let samples = vec![-1.0_f32, -0.5, 0.0, 0.5, 0.9999];
255 let bytes = Format::S16.from_interleaved_f32(&samples, 1).unwrap();
256 let cow = Format::S16.as_interleaved_f32(&bytes, 1).unwrap();
257 assert!(matches!(cow, Cow::Owned(_)));
258 for (a, b) in samples.iter().zip(cow.iter()) {
259 assert!((a - b).abs() < 1.0 / 32767.0, "{a} vs {b}");
260 }
261 }
262
263 #[test]
264 fn planar_to_interleaved_orders_correctly() {
265 let planar: Vec<f32> = vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6];
266 let bytes: Vec<u8> = planar.iter().flat_map(|s| s.to_le_bytes()).collect();
267 let cow = Format::F32Planar.as_interleaved_f32(&bytes, 2).unwrap();
268 assert_eq!(cow.as_ref(), &[0.1, 0.4, 0.2, 0.5, 0.3, 0.6]);
269 }
270
271 #[test]
272 fn s16_clamps_out_of_range() {
273 let samples = vec![2.0_f32, -3.0];
274 let bytes = Format::S16.from_interleaved_f32(&samples, 1).unwrap();
275 let cow = Format::S16.as_interleaved_f32(&bytes, 1).unwrap();
276 assert!((cow[0] - 0.99997).abs() < 1e-4);
277 assert!((cow[1] + 1.0).abs() < 1e-4);
278 }
279
280 #[test]
281 fn rejects_misaligned_buffer() {
282 let result = Format::S16.as_interleaved_f32(&[0u8; 5], 2);
283 assert!(matches!(result, Err(Error::Misaligned { .. })));
284 }
285}