use std::num::{NonZeroU32, NonZeroUsize};
use symphonia::core::{audio::AudioBuffer, codecs::Decoder, probe::ProbeResult};
use super::{decode_warning, shrink_buffer};
use crate::{DecodeConfig, DecodedAudioF32, error::LoadError};
pub(crate) fn decode_f32(
probed: &mut ProbeResult,
config: &DecodeConfig,
num_channels: NonZeroUsize,
sample_rate: NonZeroU32,
original_sample_rate: NonZeroU32,
decoder: &mut dyn Decoder,
) -> Result<DecodedAudioF32, LoadError> {
const BYTES_PER_SAMPLE: usize = 4;
let track = probed
.format
.default_track()
.ok_or_else(|| LoadError::NoTrackFound)?;
let file_frames = track.codec_params.n_frames;
let max_frames = config.max_bytes / (BYTES_PER_SAMPLE * num_channels.get());
if let Some(frames) = file_frames
&& frames > max_frames as u64
{
return Err(LoadError::FileTooLarge(config.max_bytes));
}
let mut tmp_conversion_buf: Option<AudioBuffer<f32>> = None;
let estimated_final_frames = file_frames.unwrap_or(32768) as usize;
let mut final_buf: Vec<Vec<f32>> = (0..num_channels.get())
.map(|_| {
let mut v = Vec::new();
v.reserve_exact(estimated_final_frames);
v
})
.collect();
let track_id = track.id;
while let Ok(packet) = probed.format.next_packet() {
if packet.track_id() != track_id {
continue;
}
match decoder.decode(&packet) {
Ok(decoded) => {
if tmp_conversion_buf.is_none() {
let spec = *(decoded.spec());
let duration = decoded.capacity();
tmp_conversion_buf = Some(AudioBuffer::new(duration as u64, spec));
}
let tmp_conversion_buf = tmp_conversion_buf.as_mut().unwrap();
if tmp_conversion_buf.capacity() < decoded.capacity() {
let spec = *(decoded.spec());
let duration = decoded.capacity();
*tmp_conversion_buf = AudioBuffer::new(duration as u64, spec);
}
decoded.convert(tmp_conversion_buf);
let tmp_conversion_planes = tmp_conversion_buf.planes();
let converted_planes = tmp_conversion_planes.planes();
for (final_ch, decoded_ch) in final_buf.iter_mut().zip(converted_planes) {
final_ch.extend_from_slice(decoded_ch);
}
if file_frames.is_none() {
if final_buf[0].len() > max_frames {
return Err(LoadError::FileTooLarge(config.max_bytes));
}
}
}
Err(symphonia::core::errors::Error::DecodeError(err)) => decode_warning(err),
Err(e) => return Err(LoadError::ErrorWhileDecoding(e)),
}
}
shrink_buffer(&mut final_buf);
Ok(DecodedAudioF32::new(
final_buf,
sample_rate,
original_sample_rate,
))
}