use anyhow::{Context, Error, bail};
use bitstream_io::{FromBitStream, ToBitStream};
#[derive(Debug, Clone, Copy)]
pub struct Header {
syncinfo: SyncInfo,
bsi: Bsi,
}
impl FromBitStream for Header {
type Error = Error;
fn from_reader<R: bitstream_io::BitRead + ?Sized>(r: &mut R) -> Result<Self, Self::Error>
where
Self: Sized,
{
let syncinfo = r.parse::<SyncInfo>().context("syncinfo")?;
let bsi = r.parse::<Bsi>().context("bsi")?;
Ok(Header { syncinfo, bsi })
}
}
#[derive(Debug, Clone, Copy)]
struct SyncInfo {
fscod: u8,
frmsizecod: u8,
}
impl FromBitStream for SyncInfo {
type Error = Error;
fn from_reader<R: bitstream_io::BitRead + ?Sized>(r: &mut R) -> Result<Self, Self::Error>
where
Self: Sized,
{
let _syncword = r.read_to::<u16>().context("syncword")?;
if _syncword != 0x0b77 {
bail!("Invalid syncword");
}
r.skip(16).context("crc1")?;
let fscod = r.read::<2, u8>().context("fscod")?;
let frmsizecod = r.read::<6, u8>().context("frmsizecod")?;
Ok(SyncInfo { fscod, frmsizecod })
}
}
#[derive(Debug, Clone, Copy)]
struct Bsi {
bsid: u8,
bsmod: u8,
acmod: u8,
lfeon: bool,
}
impl FromBitStream for Bsi {
type Error = Error;
fn from_reader<R: bitstream_io::BitRead + ?Sized>(r: &mut R) -> Result<Self, Self::Error>
where
Self: Sized,
{
let bsid = r.read::<5, u8>().context("bsid")?;
let bsmod = r.read::<3, u8>().context("bsmod")?;
let acmod = r.read::<3, u8>().context("acmod")?;
if acmod & 0x01 != 0 && acmod != 0x01 {
r.skip(2).context("cmixlev")?;
}
if acmod & 0x04 != 0 {
r.skip(2).context("surmixlev")?;
}
if acmod == 0x02 {
r.skip(2).context("dsurmod")?;
}
let lfeon = r.read_bit().context("lfeon")?;
Ok(Bsi {
bsid,
bsmod,
acmod,
lfeon,
})
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Dac3 {
pub header: Header,
}
impl ToBitStream for Dac3 {
type Error = Error;
fn to_writer<W: bitstream_io::BitWrite + ?Sized>(&self, w: &mut W) -> Result<(), Self::Error>
where
Self: Sized,
{
w.write_from::<u32>(11).context("size")?;
w.write_bytes(b"dac3").context("type")?;
w.write::<2, u8>(self.header.syncinfo.fscod)
.context("fscod")?;
w.write::<5, u8>(self.header.bsi.bsid).context("bsid")?;
w.write::<3, u8>(self.header.bsi.bsmod).context("bsmod")?;
w.write::<3, u8>(self.header.bsi.acmod).context("acmod")?;
w.write_bit(self.header.bsi.lfeon).context("lfeon")?;
w.write::<5, u8>(self.header.syncinfo.frmsizecod >> 1)
.context("bit_rate_code")?;
w.write::<5, u8>(0).context("reserved")?;
assert!(w.byte_aligned());
Ok(())
}
}