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
&& frames > max_frames as u64
{
return Err(LoadError::FileTooLarge(config.max_bytes));
}
let mut tmp_conversion_buf: Option<AudioBuffer<f32>> = None;
let final_output_frames = file_frames.map(|f| resampler.out_alloc_frames(f) as usize);
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: usize = 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;
let last_packet = if let Some(file_frames) = file_frames {
if total_in_frames as u64 >= file_frames {
let desired_output_frames =
if final_buf[0].len() <= final_output_frames.unwrap() {
Some((final_output_frames.unwrap() - final_buf[0].len()) as u64)
} else {
None
};
Some(LastPacketInfo {
desired_output_frames,
})
} else {
None
}
} else {
None
};
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,
);
}
},
last_packet,
true, );
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)),
}
}
if file_frames.is_none() {
let final_output_frames = resampler.out_alloc_frames(total_in_frames as u64) as usize;
if final_buf[0].len() < final_output_frames * 3 {
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);
} else {
assert_eq!(final_buf[0].len(), final_output_frames.unwrap());
}
Ok(DecodedAudioF32::new(
final_buf,
sample_rate,
original_sample_rate,
))
}