use std::collections::VecDeque;
use audioadapter_buffers::direct::InterleavedSlice;
use lunar_lib::trace;
use rubato::{Fft, FixedSync, Resampler, ResamplerConstructionError};
use selene_core::decoding::RawDecoder;
use symphonia::core::{
errors::Error as SymphoniaError,
formats::{SeekMode, SeekTo},
units::Time,
};
use crate::{player::PlayerError, playlist::ResolvedTrack};
pub struct OpenedDecoder {
pub decoded_from: ResolvedTrack,
inner: RawDecoder,
resampler: Fft<f32>,
resample_buffer: VecDeque<f32>,
pub current_frame: usize,
pub at_eof: bool,
}
impl OpenedDecoder {
#[must_use]
pub fn time(&self) -> f64 {
let sample_rate = f64::from(self.inner.stream.codec_params.sample_rate.unwrap());
self.current_frame as f64 / sample_rate
}
pub fn decode_next_packet(&mut self) -> Result<VecDeque<f32>, PlayerError> {
let channel_count = self.resampler.nbr_channels();
loop {
let next_frame_size = self.resampler.input_frames_next();
let Some(packet) = self.inner.decode_next_packet()? else {
let mut samples = self.resample_buffer.drain(..).collect::<Vec<_>>();
let needed_samples = next_frame_size * channel_count;
samples.resize(needed_samples, 0.0);
let buffer_in = InterleavedSlice::new(&samples, channel_count, next_frame_size)
.expect("Sampler buffer contained less capacity then expected");
let resampled = self.resampler.process(&buffer_in, 0, None).expect(
"Resampler expects input and output to have the same number of channels",
);
self.at_eof = true;
return Ok(resampled.take_data().into());
};
self.current_frame += packet.frame_count;
self.resample_buffer.extend(packet.sample_buf.samples());
let mut output = Vec::new();
while self.resample_buffer.len() >= next_frame_size * channel_count {
let samples: Vec<f32> = self
.resample_buffer
.drain(..next_frame_size * channel_count)
.collect();
let buffer_in = InterleavedSlice::new(&samples, channel_count, next_frame_size)
.expect("Sampler buffer contained less capacity then expected");
let resampled = self.resampler.process(&buffer_in, 0, None).expect(
"Resampler expects input and output to have the same number of channels",
);
output.extend(resampled.take_data());
}
if !output.is_empty() {
return Ok(output.into());
}
}
}
pub fn seek(&mut self, seconds: f64, increment: bool) -> Result<f64, SymphoniaError> {
let seconds = if increment {
(self.time() + seconds).max(0.0)
} else {
seconds
};
let timestamp = Time::from(seconds);
let seeked_to = self.inner.format_reader.seek(
SeekMode::Accurate,
SeekTo::Time {
time: timestamp,
track_id: Some(self.inner.stream.id),
},
)?;
self.inner.decoder.reset();
let time_base = self.inner.stream.codec_params.time_base.unwrap();
let raw_time = time_base.calc_time(seeked_to.actual_ts);
let time = raw_time.seconds as f64 + raw_time.frac;
let sample_rate = self.inner.stream.codec_params.sample_rate.unwrap();
self.current_frame = (time * f64::from(sample_rate)) as usize;
Ok(time)
}
}
impl OpenedDecoder {
pub fn new(playable: ResolvedTrack, output_sample_rate: usize) -> Result<Self, PlayerError> {
let container = playable
.track
.container()
.expect("Engine should handle tracks without containers");
trace!(
"Opening a new decoder from track: '{}'",
container.path().display()
);
let inner = RawDecoder::from_container(container, 64 * 1024)?;
let resampler = new_resampler(
inner.stream.codec_params.sample_rate.unwrap() as usize,
output_sample_rate,
inner.stream.codec_params.channels.unwrap().count(),
)?;
Ok(OpenedDecoder {
inner,
current_frame: 0,
decoded_from: playable,
resampler,
resample_buffer: VecDeque::with_capacity(1024),
at_eof: false,
})
}
}
fn new_resampler(
input_sample_rate: usize,
output_sample_rate: usize,
channel_count: usize,
) -> Result<Fft<f32>, ResamplerConstructionError> {
Fft::new(
input_sample_rate,
output_sample_rate,
1024,
1,
channel_count,
FixedSync::Both,
)
}