use audio_samples::AudioSamples;
use audio_samples::traits::StandardSample;
use audio_samples_io::error::AudioIOError;
use audio_samples_io::flac::FlacFile;
use audio_samples_io::traits::{AudioFile, AudioFileMetadata, AudioFileRead};
use crate::error::StreamingError;
use crate::traits::AudioStream;
pub struct FlacFileStream<T: StandardSample> {
data: AudioSamples<'static, T>,
frame_pos: usize,
total_frames: usize,
sample_rate: u32,
channels: u16,
}
impl<T: StandardSample + 'static> FlacFileStream<T> {
pub fn open<P: AsRef<std::path::Path>>(path: P) -> Result<Self, AudioIOError> {
let flac = FlacFile::open(path)?;
let sample_rate = flac.base_info()?.sample_rate.get();
let channels = flac.num_channels();
let data: AudioSamples<'static, T> = flac.read::<T>()?.into_owned();
let total_frames = data.samples_per_channel().get();
Ok(Self {
data,
frame_pos: 0,
total_frames,
sample_rate,
channels,
})
}
pub fn sample_rate(&self) -> u32 {
self.sample_rate
}
pub fn channels(&self) -> u16 {
self.channels
}
pub fn total_frames(&self) -> usize {
self.total_frames
}
pub fn remaining_frames(&self) -> usize {
self.total_frames - self.frame_pos
}
pub fn seek_to_frame(&mut self, frame: usize) {
self.frame_pos = frame.min(self.total_frames);
}
pub fn reset(&mut self) {
self.frame_pos = 0;
}
}
impl<T: StandardSample + 'static> AudioStream for FlacFileStream<T> {
type Sample = T;
type Error = StreamingError;
fn fill_chunk(
&mut self,
buffer: &mut AudioSamples<'static, T>,
) -> Result<Option<usize>, StreamingError> {
if self.frame_pos >= self.total_frames {
return Ok(None);
}
let buf_frames = buffer.samples_per_channel().get();
let available = self.total_frames - self.frame_pos;
let n = buf_frames.min(available);
let channels = self.channels as usize;
if channels == 1 {
let src = self
.data
.as_mono()
.ok_or_else(|| StreamingError::Parameter("expected mono source".into()))?;
let src_slice = src
.as_slice()
.ok_or_else(|| StreamingError::Parameter("source buffer not contiguous".into()))?;
let dst = buffer
.as_mono_mut()
.ok_or_else(|| StreamingError::Parameter("expected mono buffer".into()))?;
dst.as_slice_mut()[..n].copy_from_slice(&src_slice[self.frame_pos..self.frame_pos + n]);
} else {
let total_frames = self.total_frames;
let src = self
.data
.as_multi_channel()
.ok_or_else(|| StreamingError::Parameter("expected multi-channel source".into()))?;
let src_flat = src
.as_slice()
.ok_or_else(|| StreamingError::Parameter("source buffer not contiguous".into()))?;
let dst = buffer
.as_multi_channel_mut()
.ok_or_else(|| StreamingError::Parameter("expected multi-channel buffer".into()))?;
let dst_flat = dst
.as_slice_mut()
.ok_or_else(|| StreamingError::Parameter("buffer not contiguous".into()))?;
for ch in 0..channels {
let src_start = ch * total_frames + self.frame_pos;
let dst_start = ch * buf_frames;
dst_flat[dst_start..dst_start + n]
.copy_from_slice(&src_flat[src_start..src_start + n]);
}
}
self.frame_pos += n;
Ok(Some(n))
}
}