1use crate::SampleFormat;
4
5use super::AudioFrame;
6
7impl AudioFrame {
8 #[must_use]
23 pub fn total_size(&self) -> usize {
24 self.planes.iter().map(Vec::len).sum()
25 }
26
27 #[must_use]
41 #[inline]
42 pub fn bytes_per_sample(&self) -> usize {
43 self.format.bytes_per_sample()
44 }
45
46 #[must_use]
57 #[inline]
58 pub fn sample_count(&self) -> usize {
59 self.samples * self.channels as usize
60 }
61
62 #[must_use]
92 #[allow(
93 clippy::cast_possible_truncation,
94 clippy::cast_precision_loss,
95 clippy::too_many_lines
96 )]
97 pub fn to_f32_interleaved(&self) -> Vec<f32> {
98 let total = self.sample_count();
99 if total == 0 {
100 return Vec::new();
101 }
102
103 match self.format {
104 SampleFormat::F32 => self.as_f32().map(<[f32]>::to_vec).unwrap_or_default(),
105 SampleFormat::F32p => {
106 let mut out = vec![0f32; total];
107 let ch_count = self.channels as usize;
108 for ch in 0..ch_count {
109 if let Some(plane) = self.channel_as_f32(ch) {
110 for (i, &s) in plane.iter().enumerate() {
111 out[i * ch_count + ch] = s;
112 }
113 }
114 }
115 out
116 }
117 SampleFormat::F64 => {
118 let bytes = self.data();
119 bytes
120 .chunks_exact(8)
121 .map(|b| {
122 f64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]) as f32
123 })
124 .collect()
125 }
126 SampleFormat::F64p => {
127 let mut out = vec![0f32; total];
128 let ch_count = self.channels as usize;
129 for ch in 0..ch_count {
130 if let Some(bytes) = self.channel(ch) {
131 for (i, b) in bytes.chunks_exact(8).enumerate() {
132 out[i * ch_count + ch] = f64::from_le_bytes([
133 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
134 ]) as f32;
135 }
136 }
137 }
138 out
139 }
140 SampleFormat::I16 => {
141 let bytes = self.data();
142 bytes
143 .chunks_exact(2)
144 .map(|b| f32::from(i16::from_le_bytes([b[0], b[1]])) / f32::from(i16::MAX))
145 .collect()
146 }
147 SampleFormat::I16p => {
148 let mut out = vec![0f32; total];
149 let ch_count = self.channels as usize;
150 for ch in 0..ch_count {
151 if let Some(bytes) = self.channel(ch) {
152 for (i, b) in bytes.chunks_exact(2).enumerate() {
153 out[i * ch_count + ch] =
154 f32::from(i16::from_le_bytes([b[0], b[1]])) / f32::from(i16::MAX);
155 }
156 }
157 }
158 out
159 }
160 SampleFormat::I32 => {
161 let bytes = self.data();
162 bytes
163 .chunks_exact(4)
164 .map(|b| i32::from_le_bytes([b[0], b[1], b[2], b[3]]) as f32 / i32::MAX as f32)
165 .collect()
166 }
167 SampleFormat::I32p => {
168 let mut out = vec![0f32; total];
169 let ch_count = self.channels as usize;
170 for ch in 0..ch_count {
171 if let Some(bytes) = self.channel(ch) {
172 for (i, b) in bytes.chunks_exact(4).enumerate() {
173 out[i * ch_count + ch] = i32::from_le_bytes([b[0], b[1], b[2], b[3]])
174 as f32
175 / i32::MAX as f32;
176 }
177 }
178 }
179 out
180 }
181 SampleFormat::U8 => {
182 let bytes = self.data();
183 bytes
184 .iter()
185 .map(|&b| (f32::from(b) - 128.0) / 128.0)
186 .collect()
187 }
188 SampleFormat::U8p => {
189 let mut out = vec![0f32; total];
190 let ch_count = self.channels as usize;
191 for ch in 0..ch_count {
192 if let Some(bytes) = self.channel(ch) {
193 for (i, &b) in bytes.iter().enumerate() {
194 out[i * ch_count + ch] = (f32::from(b) - 128.0) / 128.0;
195 }
196 }
197 }
198 out
199 }
200 SampleFormat::Other(_) => Vec::new(),
201 }
202 }
203
204 #[must_use]
229 #[allow(clippy::cast_possible_truncation, clippy::too_many_lines)] pub fn to_i16_interleaved(&self) -> Vec<i16> {
231 let total = self.sample_count();
232 if total == 0 {
233 return Vec::new();
234 }
235
236 match self.format {
237 SampleFormat::I16 => self.as_i16().map(<[i16]>::to_vec).unwrap_or_default(),
238 SampleFormat::I16p => {
239 let mut out = vec![0i16; total];
240 let ch_count = self.channels as usize;
241 for ch in 0..ch_count {
242 if let Some(plane) = self.channel_as_i16(ch) {
243 for (i, &s) in plane.iter().enumerate() {
244 out[i * ch_count + ch] = s;
245 }
246 }
247 }
248 out
249 }
250 SampleFormat::F32 => {
251 let bytes = self.data();
252 bytes
253 .chunks_exact(4)
254 .map(|b| {
255 let s = f32::from_le_bytes([b[0], b[1], b[2], b[3]]);
256 (s.clamp(-1.0, 1.0) * f32::from(i16::MAX)) as i16
257 })
258 .collect()
259 }
260 SampleFormat::F32p => {
261 let mut out = vec![0i16; total];
262 let ch_count = self.channels as usize;
263 for ch in 0..ch_count {
264 if let Some(bytes) = self.channel(ch) {
265 for (i, b) in bytes.chunks_exact(4).enumerate() {
266 let s = f32::from_le_bytes([b[0], b[1], b[2], b[3]]);
267 out[i * ch_count + ch] =
268 (s.clamp(-1.0, 1.0) * f32::from(i16::MAX)) as i16;
269 }
270 }
271 }
272 out
273 }
274 SampleFormat::F64 => {
275 let bytes = self.data();
276 bytes
277 .chunks_exact(8)
278 .map(|b| {
279 let s =
280 f64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
281 (s.clamp(-1.0, 1.0) * f64::from(i16::MAX)) as i16
282 })
283 .collect()
284 }
285 SampleFormat::F64p => {
286 let mut out = vec![0i16; total];
287 let ch_count = self.channels as usize;
288 for ch in 0..ch_count {
289 if let Some(bytes) = self.channel(ch) {
290 for (i, b) in bytes.chunks_exact(8).enumerate() {
291 let s = f64::from_le_bytes([
292 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
293 ]);
294 out[i * ch_count + ch] =
295 (s.clamp(-1.0, 1.0) * f64::from(i16::MAX)) as i16;
296 }
297 }
298 }
299 out
300 }
301 SampleFormat::I32 => {
302 let bytes = self.data();
303 bytes
304 .chunks_exact(4)
305 .map(|b| (i32::from_le_bytes([b[0], b[1], b[2], b[3]]) >> 16) as i16)
306 .collect()
307 }
308 SampleFormat::I32p => {
309 let mut out = vec![0i16; total];
310 let ch_count = self.channels as usize;
311 for ch in 0..ch_count {
312 if let Some(bytes) = self.channel(ch) {
313 for (i, b) in bytes.chunks_exact(4).enumerate() {
314 out[i * ch_count + ch] =
315 (i32::from_le_bytes([b[0], b[1], b[2], b[3]]) >> 16) as i16;
316 }
317 }
318 }
319 out
320 }
321 SampleFormat::U8 => {
322 let bytes = self.data();
323 bytes.iter().map(|&b| (i16::from(b) - 128) << 8).collect()
324 }
325 SampleFormat::U8p => {
326 let mut out = vec![0i16; total];
327 let ch_count = self.channels as usize;
328 for ch in 0..ch_count {
329 if let Some(bytes) = self.channel(ch) {
330 for (i, &b) in bytes.iter().enumerate() {
331 out[i * ch_count + ch] = (i16::from(b) - 128) << 8;
332 }
333 }
334 }
335 out
336 }
337 SampleFormat::Other(_) => Vec::new(),
338 }
339 }
340}
341
342#[cfg(test)]
343#[allow(clippy::unwrap_used)]
344mod tests {
345 use super::*;
346 use crate::{Rational, Timestamp};
347
348 #[test]
353 fn total_size_packed_should_equal_samples_times_channels_times_bytes() {
354 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
356 assert_eq!(frame.total_size(), 1024 * 2 * 4);
357
358 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32p).unwrap();
360 assert_eq!(frame.total_size(), 1024 * 4 * 2);
361 }
362
363 #[test]
364 fn bytes_per_sample_should_match_format_width() {
365 assert_eq!(
366 AudioFrame::empty(1024, 2, 48000, SampleFormat::U8)
367 .unwrap()
368 .bytes_per_sample(),
369 1
370 );
371 assert_eq!(
372 AudioFrame::empty(1024, 2, 48000, SampleFormat::I16)
373 .unwrap()
374 .bytes_per_sample(),
375 2
376 );
377 assert_eq!(
378 AudioFrame::empty(1024, 2, 48000, SampleFormat::F32)
379 .unwrap()
380 .bytes_per_sample(),
381 4
382 );
383 assert_eq!(
384 AudioFrame::empty(1024, 2, 48000, SampleFormat::F64)
385 .unwrap()
386 .bytes_per_sample(),
387 8
388 );
389 }
390
391 #[test]
392 fn sample_count_should_return_samples_times_channels() {
393 let frame = AudioFrame::empty(1024, 2, 48000, SampleFormat::F32).unwrap();
394 assert_eq!(frame.sample_count(), 2048);
395
396 let mono = AudioFrame::empty(512, 1, 44100, SampleFormat::I16).unwrap();
397 assert_eq!(mono.sample_count(), 512);
398 }
399
400 #[test]
405 fn to_f32_interleaved_f32p_should_transpose_to_interleaved() {
406 let left: Vec<u8> = [1.0f32, 2.0f32]
409 .iter()
410 .flat_map(|f| f.to_le_bytes())
411 .collect();
412 let right: Vec<u8> = [3.0f32, 4.0f32]
413 .iter()
414 .flat_map(|f| f.to_le_bytes())
415 .collect();
416
417 let frame = AudioFrame::new(
418 vec![left, right],
419 2,
420 2,
421 48000,
422 SampleFormat::F32p,
423 Timestamp::default(),
424 )
425 .unwrap();
426
427 let pcm = frame.to_f32_interleaved();
428 assert_eq!(pcm.len(), 4);
429 assert!((pcm[0] - 1.0).abs() < f32::EPSILON); assert!((pcm[1] - 3.0).abs() < f32::EPSILON); assert!((pcm[2] - 2.0).abs() < f32::EPSILON); assert!((pcm[3] - 4.0).abs() < f32::EPSILON); }
434
435 #[test]
436 fn to_f32_interleaved_i16p_should_scale_to_minus_one_to_one() {
437 let make_i16_bytes = |v: i16| v.to_le_bytes().to_vec();
439
440 let left: Vec<u8> = [i16::MAX, 0i16]
441 .iter()
442 .flat_map(|&v| make_i16_bytes(v))
443 .collect();
444 let right: Vec<u8> = [i16::MIN, 0i16]
445 .iter()
446 .flat_map(|&v| make_i16_bytes(v))
447 .collect();
448
449 let frame = AudioFrame::new(
450 vec![left, right],
451 2,
452 2,
453 48000,
454 SampleFormat::I16p,
455 Timestamp::default(),
456 )
457 .unwrap();
458
459 let pcm = frame.to_f32_interleaved();
460 for &s in &pcm {
463 assert!(s >= -1.001 && s <= 1.001, "out of range: {s}");
464 }
465 assert!((pcm[0] - 1.0).abs() < 0.0001); assert!((pcm[1] - (-1.0)).abs() < 0.001); }
468
469 #[test]
470 fn to_f32_interleaved_unknown_should_return_empty() {
471 let frame = AudioFrame::new(
474 vec![vec![0u8; 16]],
475 4,
476 1,
477 48000,
478 SampleFormat::Other(999),
479 Timestamp::default(),
480 )
481 .unwrap();
482 assert_eq!(frame.to_f32_interleaved(), Vec::<f32>::new());
483 }
484
485 #[test]
486 fn to_i16_interleaved_i16p_should_transpose_to_interleaved() {
487 let left: Vec<u8> = [100i16, 200i16]
488 .iter()
489 .flat_map(|v| v.to_le_bytes())
490 .collect();
491 let right: Vec<u8> = [300i16, 400i16]
492 .iter()
493 .flat_map(|v| v.to_le_bytes())
494 .collect();
495
496 let frame = AudioFrame::new(
497 vec![left, right],
498 2,
499 2,
500 48000,
501 SampleFormat::I16p,
502 Timestamp::default(),
503 )
504 .unwrap();
505
506 let pcm = frame.to_i16_interleaved();
507 assert_eq!(pcm, vec![100, 300, 200, 400]);
508 }
509
510 #[test]
511 fn to_i16_interleaved_f32_should_scale_and_clamp() {
512 let samples: &[f32] = &[1.0, -1.0, 2.0, -2.0];
514 let bytes: Vec<u8> = samples.iter().flat_map(|f| f.to_le_bytes()).collect();
515
516 let frame = AudioFrame::new(
517 vec![bytes],
518 4,
519 1,
520 48000,
521 SampleFormat::F32,
522 Timestamp::default(),
523 )
524 .unwrap();
525
526 let pcm = frame.to_i16_interleaved();
527 assert_eq!(pcm.len(), 4);
528 assert_eq!(pcm[0], i16::MAX);
529 assert_eq!(pcm[1], -i16::MAX);
530 assert_eq!(pcm[2], i16::MAX);
532 assert_eq!(pcm[3], -i16::MAX);
533 }
534
535 #[test]
536 fn audio_frame_clone_should_have_identical_data() {
537 let samples = 512;
538 let channels = 2u32;
539 let bytes_per_sample = 4; let plane_data = vec![7u8; samples * bytes_per_sample];
541 let ts = Timestamp::new(500, Rational::new(1, 1000));
542
543 let original = AudioFrame::new(
544 vec![plane_data.clone()],
545 samples,
546 channels,
547 44100,
548 SampleFormat::F32,
549 ts,
550 )
551 .unwrap();
552
553 let clone = original.clone();
554
555 assert_eq!(clone.samples(), original.samples());
556 assert_eq!(clone.channels(), original.channels());
557 assert_eq!(clone.sample_rate(), original.sample_rate());
558 assert_eq!(clone.format(), original.format());
559 assert_eq!(clone.timestamp(), original.timestamp());
560 assert_eq!(clone.num_planes(), original.num_planes());
561 assert_eq!(clone.plane(0), original.plane(0));
562 }
563}