use std::convert::TryFrom;
use std::io::Read;
pub type DsdSourceError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub const DSD_64_RATE: u32 = 2_822_400;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Endianness {
LsbFirst,
MsbFirst,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FmtType {
Planar,
Interleaved,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DsdRate {
#[default]
DSD64 = 1,
DSD128 = 2,
DSD256 = 4,
DSD512 = 8,
}
impl TryFrom<u32> for DsdRate {
type Error = &'static str;
fn try_from(v: u32) -> Result<Self, Self::Error> {
match v {
1 => Ok(DsdRate::DSD64),
2 => Ok(DsdRate::DSD128),
4 => Ok(DsdRate::DSD256),
8 => Ok(DsdRate::DSD512),
_ => Err("Invalid DSD rate multiplier (expected 1,2,4,8)"),
}
}
}
#[derive(Clone)]
pub struct DsdSourceInfo {
pub channels: Option<usize>,
pub endianness: Option<Endianness>,
pub layout: Option<FmtType>,
pub block_size: Option<u32>,
pub sample_rate: Option<u32>,
pub audio_length: u64,
pub data_offset: u64,
pub tag: Option<id3::Tag>,
}
impl std::fmt::Debug for DsdSourceInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DsdSourceInfo")
.field("channels", &self.channels)
.field("endianness", &self.endianness)
.field("layout", &self.layout)
.field("block_size", &self.block_size)
.field("sample_rate", &self.sample_rate)
.field("audio_length", &self.audio_length)
.field("data_offset", &self.data_offset)
.field("tag", &self.tag.is_some())
.finish()
}
}
pub trait DsdSource: Send {
fn info(&self) -> Result<DsdSourceInfo, DsdSourceError>;
fn reader(&self) -> Result<Box<dyn Read + Send>, DsdSourceError>;
fn channels(&self) -> Option<usize> {
self.info().ok()?.channels
}
fn endianness(&self) -> Option<Endianness> {
self.info().ok()?.endianness
}
fn layout(&self) -> Option<FmtType> {
self.info().ok()?.layout
}
fn block_size(&self) -> Option<u32> {
self.info().ok()?.block_size
}
fn sample_rate(&self) -> Option<u32> {
self.info().ok()?.sample_rate
}
fn audio_length(&self) -> Option<u64> {
self.info().ok().map(|i| i.audio_length)
}
fn data_offset(&self) -> Option<u64> {
self.info().ok().map(|i| i.data_offset)
}
fn tag(&self) -> Option<id3::Tag> {
self.info().ok()?.tag
}
fn file_len(&self) -> Result<u64, DsdSourceError>;
}
pub trait DsdSourceExtensions {
const EXTENSIONS: &'static [&'static str];
}