use std::cmp::Ordering;
use std::io::{Read, Seek, SeekFrom};
use std::mem;
use std::time::Duration;
use crate::source::SeekError;
use crate::Source;
use claxon::FlacReader;
pub struct FlacDecoder<R>
where
R: Read + Seek,
{
reader: FlacReader<R>,
current_block: Vec<i32>,
current_block_channel_len: usize,
current_block_off: usize,
bits_per_sample: u32,
sample_rate: u32,
channels: u16,
samples: Option<u64>,
}
impl<R> FlacDecoder<R>
where
R: Read + Seek,
{
pub fn new(mut data: R) -> Result<FlacDecoder<R>, R> {
if !is_flac(data.by_ref()) {
return Err(data);
}
let reader = FlacReader::new(data).unwrap();
let spec = reader.streaminfo();
Ok(FlacDecoder {
reader,
current_block: Vec::with_capacity(
spec.max_block_size as usize * spec.channels as usize,
),
current_block_channel_len: 1,
current_block_off: 0,
bits_per_sample: spec.bits_per_sample,
sample_rate: spec.sample_rate,
channels: spec.channels as u16,
samples: spec.samples,
})
}
pub fn into_inner(self) -> R {
self.reader.into_inner()
}
}
impl<R> Source for FlacDecoder<R>
where
R: Read + Seek,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
None
}
#[inline]
fn channels(&self) -> u16 {
self.channels
}
#[inline]
fn sample_rate(&self) -> u32 {
self.sample_rate
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.samples
.map(|s| Duration::from_micros(s * 1_000_000 / self.sample_rate as u64))
}
#[inline]
fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
Err(SeekError::NotSupported {
underlying_source: std::any::type_name::<Self>(),
})
}
}
impl<R> Iterator for FlacDecoder<R>
where
R: Read + Seek,
{
type Item = i16;
#[inline]
fn next(&mut self) -> Option<i16> {
loop {
if self.current_block_off < self.current_block.len() {
let real_offset = (self.current_block_off % self.channels as usize)
* self.current_block_channel_len
+ self.current_block_off / self.channels as usize;
let raw_val = self.current_block[real_offset];
self.current_block_off += 1;
let real_val = match self.bits_per_sample.cmp(&16) {
Ordering::Less => (raw_val << (16 - self.bits_per_sample)) as i16,
Ordering::Equal => raw_val as i16,
Ordering::Greater => (raw_val >> (self.bits_per_sample - 16)) as i16,
};
return Some(real_val);
}
self.current_block_off = 0;
let buffer = mem::take(&mut self.current_block);
match self.reader.blocks().read_next_or_eof(buffer) {
Ok(Some(block)) => {
self.current_block_channel_len = (block.len() / block.channels()) as usize;
self.current_block = block.into_buffer();
}
_ => return None,
}
}
}
}
fn is_flac<R>(mut data: R) -> bool
where
R: Read + Seek,
{
let stream_pos = data.stream_position().unwrap();
if FlacReader::new(data.by_ref()).is_err() {
data.seek(SeekFrom::Start(stream_pos)).unwrap();
return false;
}
data.seek(SeekFrom::Start(stream_pos)).unwrap();
true
}