use std::io::{Read, Seek, SeekFrom};
use crate::error::{LufsError, Result};
use crate::decoders::AudioDecoder;
use symphonia::core::audio::AudioBuffer;
use symphonia::core::codecs::{DecoderOptions};
use symphonia::core::formats::FormatOptions;
use symphonia::core::io::{MediaSource, MediaSourceStream, MediaSourceStreamOptions};
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::{Hint};
struct SeekableSource<R: Read + Seek + Send + Sync> {
reader: R,
byte_len: Option<u64>,
}
impl<R: Read + Seek + Send + Sync> SeekableSource<R> {
fn new(mut reader: R) -> Result<Self> {
let byte_len = Self::detect_len_and_rewind(&mut reader)?;
Ok(Self { reader, byte_len })
}
fn detect_len_and_rewind(reader: &mut R) -> Result<Option<u64>> {
let current_pos = reader
.stream_position()
.map_err(LufsError::Io)?;
let end_pos = reader
.seek(SeekFrom::End(0))
.map_err(LufsError::Io)?;
reader
.seek(SeekFrom::Start(current_pos))
.map_err(LufsError::Io)?;
if end_pos == current_pos {
return Err(LufsError::InvalidData("Empty audio file".to_string()));
}
Ok(Some(end_pos))
}
}
impl<R: Read + Seek + Send + Sync> Read for SeekableSource<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.reader.read(buf)
}
}
impl<R: Read + Seek + Send + Sync> Seek for SeekableSource<R> {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
self.reader.seek(pos)
}
}
impl<R: Read + Seek + Send + Sync + 'static> MediaSource for SeekableSource<R> {
fn is_seekable(&self) -> bool {
true
}
fn byte_len(&self) -> Option<u64> {
self.byte_len
}
}
pub struct SymphoniaDecoder {
decoder: Box<dyn symphonia::core::codecs::Decoder>,
sample_rate: u32,
channels: u32,
format: Box<dyn symphonia::core::formats::FormatReader>,
ended: bool,
}
impl SymphoniaDecoder {
pub fn new<R: Read + Seek + Send + Sync + 'static>(reader: R) -> Result<Self> {
let source = Box::new(SeekableSource::new(reader)?);
let mss = MediaSourceStream::new(
source,
MediaSourceStreamOptions::default(),
);
let hint = Hint::new();
let probed = symphonia::default::get_probe().format(
&hint,
mss,
&FormatOptions::default(),
&MetadataOptions::default(),
)
.map_err(|e| {
LufsError::DecodeError(format!(
"Failed to detect audio format: {}. The file may be corrupt or use an unsupported format.",
e
))
})?;
let format = probed.format;
let track = format
.default_track()
.ok_or_else(|| LufsError::InvalidData("No audio track found".to_string()))?;
let codec_params = &track.codec_params;
let sample_rate = codec_params
.sample_rate
.ok_or_else(|| LufsError::InvalidData("Missing sample rate".to_string()))?;
let channels = codec_params
.channels
.map(|c| c.count() as u32)
.unwrap_or(2);
let decoder = symphonia::default::get_codecs()
.make(codec_params, &DecoderOptions::default())
.map_err(|e| {
LufsError::DecodeError(format!(
"Failed to create decoder for codec: {}. The audio format may not be supported.",
e
))
})?;
Ok(SymphoniaDecoder {
decoder,
sample_rate,
channels,
format,
ended: false,
})
}
fn decode_next_packet(&mut self) -> Result<Option<Vec<i16>>> {
if self.ended {
return Ok(None);
}
let packet = match self.format.next_packet() {
Ok(packet) => packet,
Err(symphonia::core::errors::Error::ResetRequired) => {
return Ok(None);
}
Err(symphonia::core::errors::Error::IoError(ref e))
if e.kind() == std::io::ErrorKind::UnexpectedEof =>
{
self.ended = true;
return Ok(None);
}
Err(e) => {
return Err(LufsError::DecodeError(format!("Packet read error: {}", e)));
}
};
let decoded_buf = match self.decoder.decode(&packet) {
Ok(buf) => buf,
Err(symphonia::core::errors::Error::IoError(_))
| Err(symphonia::core::errors::Error::DecodeError(_)) => {
return Ok(Some(Vec::new()));
}
Err(e) => {
return Err(LufsError::DecodeError(format!("Decode error: {}", e)));
}
};
let samples = Self::audio_buffer_to_i16(&decoded_buf);
Ok(Some(samples))
}
fn audio_buffer_to_i16(buf: &symphonia::core::audio::AudioBufferRef<'_>) -> Vec<i16> {
match buf {
symphonia::core::audio::AudioBufferRef::F32(buf_f32) => {
Self::convert_f32_to_i16(buf_f32.as_ref())
}
symphonia::core::audio::AudioBufferRef::S32(buf_s32) => {
Self::convert_s32_to_i16(buf_s32.as_ref())
}
symphonia::core::audio::AudioBufferRef::S16(buf_s16) => {
Self::convert_s16_to_i16(buf_s16.as_ref())
}
symphonia::core::audio::AudioBufferRef::S24(buf_s24) => {
Self::convert_i24_to_i16(buf_s24.as_ref())
}
symphonia::core::audio::AudioBufferRef::U8(buf_u8) => {
Self::convert_u8_to_i16(buf_u8.as_ref())
}
symphonia::core::audio::AudioBufferRef::U16(buf_u16) => {
Self::convert_u16_to_i16(buf_u16.as_ref())
}
symphonia::core::audio::AudioBufferRef::U24(buf_u24) => {
Self::convert_u24_to_i16(buf_u24.as_ref())
}
symphonia::core::audio::AudioBufferRef::U32(buf_u32) => {
Self::convert_u32_to_i16(buf_u32.as_ref())
}
symphonia::core::audio::AudioBufferRef::S8(buf_s8) => {
Self::convert_s8_to_i16(buf_s8.as_ref())
}
symphonia::core::audio::AudioBufferRef::F64(buf_f64) => {
Self::convert_f64_to_i16(buf_f64.as_ref())
}
}
}
fn convert_f32_to_i16(buf: &AudioBuffer<f32>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let i16_sample: i16 = (sample.clamp(-1.0_f32, 1.0_f32) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_f64_to_i16(buf: &AudioBuffer<f64>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let i16_sample: i16 = (sample.clamp(-1.0_f64, 1.0_f64) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_s32_to_i16(buf: &AudioBuffer<i32>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
let max_val = i32::MAX as f64;
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let sample_f64 = sample as f64 / max_val;
let i16_sample = (sample_f64.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_s16_to_i16(buf: &AudioBuffer<i16>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
result.push(sample);
}
}
result
}
fn convert_s8_to_i16(buf: &AudioBuffer<i8>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let sample_f32 = sample as f32 / 128.0;
let i16_sample = (sample_f32.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_i24_to_i16(buf: &AudioBuffer<symphonia::core::sample::i24>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let inner_val = sample.0;
let sample_f64 = inner_val as f64 / (i32::MAX as f64 / 256.0);
let i16_sample = (sample_f64.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_u8_to_i16(buf: &AudioBuffer<u8>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let sample_f32 = (sample as f32 - 128.0) / 128.0;
let i16_sample = (sample_f32.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_u16_to_i16(buf: &AudioBuffer<u16>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let sample_f32 = (sample as f32 - 32768.0) / 32768.0;
let i16_sample = (sample_f32.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_u24_to_i16(buf: &AudioBuffer<symphonia::core::sample::u24>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let inner_val = sample.0;
let max_val = (u32::MAX >> 8) as f64;
let sample_f64 = (inner_val as f64 - max_val / 2.0) / (max_val / 2.0);
let i16_sample = (sample_f64.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
fn convert_u32_to_i16(buf: &AudioBuffer<u32>) -> Vec<i16> {
let spec = *buf.spec();
let channels = spec.channels.count();
let planes = buf.planes();
let len = planes.planes()[0].len();
let mut result = Vec::with_capacity(len * channels);
for sample_idx in 0..len {
for plane_idx in 0..channels {
let plane = &planes.planes()[plane_idx];
let sample = plane[sample_idx];
let max_val = u32::MAX as f64;
let sample_f64 = (sample as f64 - max_val / 2.0) / (max_val / 2.0);
let i16_sample = (sample_f64.clamp(-1.0, 1.0) * 32767.0) as i16;
result.push(i16_sample);
}
}
result
}
}
impl AudioDecoder for SymphoniaDecoder {
fn sample_rate(&self) -> u32 {
self.sample_rate
}
fn channels(&self) -> u32 {
self.channels
}
fn decode_chunk(&mut self) -> Result<Option<Vec<i16>>> {
let mut all_samples = Vec::new();
let target_samples = 8192 * self.channels as usize;
while all_samples.len() < target_samples {
match self.decode_next_packet()? {
Some(mut samples) => {
if samples.is_empty() {
continue;
}
all_samples.append(&mut samples);
}
None => {
if all_samples.is_empty() {
return Ok(None); }
break;
}
}
}
Ok(Some(all_samples))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seekable_source_is_seekable() {
let data = vec![0u8; 1024];
let reader = std::io::Cursor::new(data);
let source = SeekableSource::new(reader).unwrap();
assert!(source.is_seekable());
assert_eq!(source.byte_len(), Some(1024));
}
#[test]
fn test_empty_data_error() {
let empty: &[u8] = &[];
let reader = std::io::Cursor::new(empty);
let result = SymphoniaDecoder::new(reader);
assert!(matches!(result, Err(LufsError::InvalidData(_))));
}
}