use std::num::{NonZeroU32, NonZeroUsize};
use fixed_resample::rubato::audioadapter::Adapter;
use fixed_resample::{
PacketResampler, Sequential, audioadapter_buffers::direct::SequentialSliceOfSlices,
};
use symphonia::core::audio::{Audio, AudioBuffer};
use symphonia::core::codecs::audio::AudioDecoder;
use symphonia::core::formats::FormatReader;
use super::{alloc_final_buf, constrain_file_frames, decode_warning, shrink_buffer};
use crate::{DecodeConfig, DecodedAudioF32, error::LoadError, get_track};
const MAX_TMP_BUFFER_FRAMES: usize = 1_000_000;
pub(crate) fn decode_resampled(
format_reader: &mut dyn FormatReader,
config: &DecodeConfig,
sample_rate: NonZeroU32,
original_sample_rate: NonZeroU32,
num_channels: NonZeroUsize,
resampler: &mut PacketResampler<f32, Sequential<f32>>,
decoder: &mut dyn AudioDecoder,
) -> Result<DecodedAudioF32, LoadError> {
use fixed_resample::LastPacketInfo;
const BYTES_PER_SAMPLE: usize = 4;
let track = get_track(format_reader, config.track_index)?;
let track_id = track.id;
let file_frames = if let Some(f) = track.num_frames {
constrain_file_frames(Some(resampler.out_alloc_frames(f)))?
} else {
None
};
let max_frames = config
.max_bytes
.checked_div(BYTES_PER_SAMPLE.checked_mul(num_channels.get()).unwrap())
.unwrap();
if let Some(frames) = file_frames
&& frames > max_frames
{
return Err(LoadError::FileTooLarge(config.max_bytes));
}
let max_frames_per_packet = track
.codec_params
.as_ref()
.and_then(|p| p.audio())
.and_then(|p| p.max_frames_per_packet)
.and_then(|f| {
usize::try_from(f)
.ok()
.and_then(|f| (f < MAX_TMP_BUFFER_FRAMES).then_some(f))
});
let mut tmp_conversion_buf: Option<AudioBuffer<f32>> = None;
let mut tmp_slice_buf: Vec<&[f32]>;
let mut final_buf: Vec<Vec<f32>> = alloc_final_buf(file_frames, num_channels, config);
let mut total_in_frames: u64 = 0;
while let Some(packet) = format_reader
.next_packet()
.map_err(LoadError::ErrorWhileDecoding)?
{
if packet.track_id != track_id {
continue;
}
match decoder.decode(&packet) {
Ok(decoded) => {
let decoded_frames = decoded.frames();
let tmp_conversion_buf = tmp_conversion_buf.get_or_insert_with(|| {
let spec = decoded.spec().clone();
let capacity = max_frames_per_packet.unwrap_or(decoded.capacity());
AudioBuffer::new(spec, capacity)
});
if tmp_conversion_buf.capacity() < decoded_frames {
let spec = decoded.spec().clone();
let capacity = decoded.capacity();
*tmp_conversion_buf = AudioBuffer::new(spec, capacity);
}
tmp_conversion_buf.resize_uninit(decoded_frames);
decoded.copy_to(tmp_conversion_buf);
total_in_frames = total_in_frames.saturating_add(decoded_frames as u64);
tmp_slice_buf = tmp_conversion_buf.iter_planes().collect();
let mut file_too_large = false;
resampler.process(
&SequentialSliceOfSlices::new(
&tmp_slice_buf,
num_channels.get(),
decoded_frames,
)
.unwrap(),
None,
None,
|in_buf, frames| {
if !file_too_large && final_buf[0].len().saturating_add(frames) > max_frames
{
file_too_large = true;
} else {
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_too_large {
return Err(LoadError::FileTooLarge(config.max_bytes));
}
}
Err(symphonia::core::errors::Error::DecodeError(err)) => decode_warning(err),
Err(symphonia::core::errors::Error::IoError(err)) => decode_warning(err),
Err(e) => return Err(LoadError::ErrorWhileDecoding(e)),
}
}
let final_output_frames = usize::try_from(resampler.out_alloc_frames(total_in_frames))
.map_err(|_| LoadError::FileTooLarge(config.max_bytes))?;
if let Some(desired_output_frames) = final_output_frames.checked_sub(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,
))
}