use std::num::{NonZeroU32, NonZeroUsize};
use fixed_resample::rubato::audioadapter::Adapter;
use fixed_resample::{
PacketResampler, Sequential, audioadapter_buffers::direct::SequentialSliceOfSlices,
};
use symphonia::core::codecs::Decoder;
use symphonia::core::{
audio::{AudioBuffer, Signal},
probe::ProbeResult,
};
use super::{decode_warning, shrink_buffer};
use crate::DecodeConfig;
use crate::{DecodedAudioF32, error::LoadError};
pub(crate) fn decode_resampled(
probed: &mut ProbeResult,
config: &DecodeConfig,
sample_rate: NonZeroU32,
original_sample_rate: NonZeroU32,
num_channels: NonZeroUsize,
resampler: &mut PacketResampler<f32, Sequential<f32>>,
decoder: &mut dyn Decoder,
) -> Result<DecodedAudioF32, LoadError> {
use fixed_resample::LastPacketInfo;
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 / (4 * num_channels.get());
if let Some(frames) = file_frames
&& resampler.out_alloc_frames(frames) > max_frames as u64
{
return Err(LoadError::FileTooLarge(config.max_bytes));
}
let mut tmp_conversion_buf: Option<AudioBuffer<f32>> = None;
let alloc_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(alloc_frames);
v
})
.collect();
let track_id = track.id;
let mut total_in_frames: u64 = 0;
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 decoded_channels = tmp_conversion_buf.spec().channels.count();
let decoded_frames = tmp_conversion_buf.frames();
total_in_frames += decoded_frames as u64;
resampler.process(
&SequentialSliceOfSlices::new(
tmp_conversion_buf.planes().planes(),
decoded_channels,
decoded_frames,
)
.unwrap(),
None,
None,
|in_buf, frames| {
for ch in 0..in_buf.channels().min(final_buf.len()) {
fixed_resample::extend_from_adapter_channel(
&mut final_buf[ch],
in_buf,
0,
ch,
frames,
);
}
},
None,
true, );
if file_frames.is_none() && 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)),
}
}
let final_output_frames = resampler.out_alloc_frames(total_in_frames) as usize;
if final_buf[0].len() < final_output_frames {
let desired_output_frames = final_output_frames - final_buf[0].len();
resampler.process(
&SequentialSliceOfSlices::new(&[&[]], 0, 0).unwrap(),
Some(0..0),
None,
|in_buf, frames| {
for ch in 0..in_buf.channels().min(final_buf.len()) {
fixed_resample::extend_from_adapter_channel(
&mut final_buf[ch],
in_buf,
0,
ch,
frames,
);
}
},
Some(LastPacketInfo {
desired_output_frames: Some(desired_output_frames as u64),
}),
true, );
} else {
for ch in final_buf.iter_mut() {
ch.resize(final_output_frames, 0.0);
}
}
shrink_buffer(&mut final_buf);
Ok(DecodedAudioF32::new(
final_buf,
sample_rate,
original_sample_rate,
))
}