use symphonia::core::audio::sample::{i24, u24};
use symphonia::core::audio::{Audio, GenericAudioBufferRef};
use crate::wav::decode::scale;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) enum IntScale {
FullScale,
Ffmpeg,
}
pub(super) fn push_frame(
audio: &GenericAudioBufferRef<'_>,
order: &[usize],
int_scale: IntScale,
from: usize,
to: usize,
out: &mut Vec<f32>,
) {
macro_rules! interleave {
($buf:expr, $convert:expr) => {{
let to = to.min($buf.frames());
let planes: Vec<_> = order.iter().filter_map(|&c| $buf.plane(c)).collect();
if let [plane] = planes[..] {
out.extend(plane[from.min(to)..to].iter().map(|&x| $convert(x)));
} else {
out.reserve(to.saturating_sub(from) * planes.len());
for i in from..to {
for plane in &planes {
out.push($convert(plane[i]));
}
}
}
}};
}
let ffmpeg = int_scale == IntScale::Ffmpeg;
match audio {
GenericAudioBufferRef::S8(b) if ffmpeg => interleave!(b, |x: i8| f32::from(x) / 128.0),
GenericAudioBufferRef::S16(b) if ffmpeg => interleave!(b, |x: i16| f32::from(x) / 32_768.0),
GenericAudioBufferRef::S24(b) if ffmpeg => {
interleave!(b, |x: i24| x.inner() as f32 / 8_388_608.0)
}
GenericAudioBufferRef::S32(b) if ffmpeg => {
interleave!(b, |x: i32| x as f32 / 2_147_483_648.0)
}
GenericAudioBufferRef::U16(b) if ffmpeg => {
interleave!(b, |x: u16| (f32::from(x) - 32_768.0) / 32_768.0)
}
GenericAudioBufferRef::U24(b) if ffmpeg => interleave!(b, |x: u24| {
(x.inner() as f32 - 8_388_608.0) / 8_388_608.0
}),
GenericAudioBufferRef::U32(b) if ffmpeg => {
interleave!(
b,
|x: u32| ((f64::from(x) - 2_147_483_648.0) / 2_147_483_648.0) as f32
)
}
GenericAudioBufferRef::F32(b) => interleave!(b, |x: f32| x),
GenericAudioBufferRef::F64(b) => interleave!(b, |x: f64| x as f32),
GenericAudioBufferRef::S16(b) => interleave!(b, |x: i16| scale(x as f64, i16::MAX as f64)),
GenericAudioBufferRef::S32(b) => interleave!(b, |x: i32| scale(x as f64, i32::MAX as f64)),
GenericAudioBufferRef::U8(b) => interleave!(b, |x: u8| (x as f32 - 128.0) / 128.0),
GenericAudioBufferRef::U16(b) => {
interleave!(b, |x: u16| (x as f32 / u16::MAX as f32) * 2.0 - 1.0)
}
GenericAudioBufferRef::U32(b) => {
interleave!(b, |x: u32| (x as f32 / u32::MAX as f32) * 2.0 - 1.0)
}
GenericAudioBufferRef::S8(b) => interleave!(b, |x: i8| scale(x as f64, i8::MAX as f64)),
GenericAudioBufferRef::S24(b) => {
interleave!(b, |x: i24| scale(x.inner() as f64, 8_388_607.0))
}
GenericAudioBufferRef::U24(b) => {
interleave!(b, |x: u24| (x.inner() as f32 / 16_777_215.0) * 2.0 - 1.0)
}
}
}