diff --git a/rust/minimqa/src/main.rs b/rust/minimqa/src/main.rs index 56b4472..57520f0 100644 --- a/rust/minimqa/src/main.rs +++ b/rust/minimqa/src/main.rs @@ -5,6 +5,7 @@ use std::{ path::{Path, PathBuf}, }; +use bitstream_io::{BitRead, BitReader, LittleEndian}; use clap::Parser; use color_eyre::eyre::{self, OptionExt}; use symphonia::core::{ @@ -15,8 +16,8 @@ use symphonia::core::{ }; /// Full 40-bit synchronization, including the packet type and 36-bit magic. -/// Stored as msb-first for easy searching, though MQA packets are lsb-first -const SYNC: u64 = 0xabe0498c88; +/// Stored as lsb-first becuase all MQA types are lsb-first +const SYNC: u64 = 0x11319207d5; #[derive(Parser)] #[command(version, about)] @@ -32,6 +33,97 @@ fn main() -> eyre::Result<()> { let args = Args::parse(); let reader = MQAReader::open(&args.input)?; + let mut bit_reader = BitReader::endian(reader, LittleEndian); + + loop { + let packet_type: u8 = bit_reader.read(4)?; + match packet_type { + 5 => { + print_sync(&mut bit_reader)?; + } + other => eyre::bail!("Unknown packet type {}", other), + } + println!("ignoring checksum {}", bit_reader.read::(4)?); + } +} + +pub struct Sync { + pub magic: u64, + pub unused: bool, + pub orig_rate: u8, + pub src_rate: u8, + pub render_filter: u8, + pub unknown1: u8, + pub render_bitdepth: u8, + pub unknown: u8, + pub auth_info: u8, + pub auth_level: u8, + pub item_count: u8, + pub stream_position: Option, +} + +pub fn print_sync(reader: &mut BitReader) -> eyre::Result<()> { + println!("magic: {:#x}", reader.read::(36)?); + let stream_pos_flag = reader.read_bit()?; + println!("stream_pos_flag: {}", stream_pos_flag); + println!("unused: {}", reader.read_bit()?); + println!("orig_rate: {}", reader.read::(5)?); + println!("src_rate: {}", reader.read::(5)?); + println!("render_filter: {}", reader.read::(5)?); + println!("unknown: {}", reader.read::(2)?); + println!("renderer_bitdepth: {}", reader.read::(2)?); + println!("unknown: {}", reader.read::(4)?); + println!("auth_info: {}", reader.read::(4)?); + println!("auth_level: {}", reader.read::(4)?); + let item_count = reader.read::(7)?; + println!("item_count: {}", item_count); + + let mut item_sizes = Vec::with_capacity(item_count as usize); + for i in 0..item_count { + let item_size = reader.read::(8)?; + item_sizes.push(item_size); + println!("item_size[{}]: {}", i, item_size); + } + let mut item_types = Vec::with_capacity(item_count as usize); + for i in 0..item_count { + let item_type = reader.read::(8)?; + item_types.push(item_type); + println!("item_type[{}]: {}", i, item_type); + } + if stream_pos_flag { + println!("stream_position: {}", reader.read::(32)?); + } + + for i in 0..item_count as usize { + let item_type = item_types[i]; + let item_size = item_sizes[i]; + println!("item {} (type {}, size {}):", i, item_type, item_size); + match item_type { + 0 => { + println!(" stage2_dither: {}", reader.read::(2)?); + println!(" gain_index: {}", reader.read::(4)?); + println!(" unknown: {}", reader.read::(7)?); + println!(" unknown: {}", reader.read::(7)?); + if stream_pos_flag { + println!(" start_pos: {}", reader.read::(27)?); + reader.skip(1)?; + reader.skip(item_size as u32 - 48)?; + } + } + 1 => { + println!(" unknown: {}", reader.read::(6)?); + println!(" unknown: {}", reader.read::(2)?); + println!(" unknown: {}", reader.read::(1)?); + println!(" unknown: {}", reader.read::(2)?); + if stream_pos_flag { + println!(" unknown: {}", reader.read::(8)?); + println!(" unknown: {}", reader.read::(1)?); + println!(" offset: {}", reader.read::(12)?); + } + } + other => eyre::bail!("Unknown item type {}", other), + }; + } Ok(()) } @@ -44,8 +136,8 @@ pub struct MQAReader { shift: u32, decoded: VecDeque, - remaining_bits: u8, - num_remaining_bits: u8, + partial_byte: u8, + next_bit: u8, } impl MQAReader { @@ -72,8 +164,8 @@ impl MQAReader { track_id, shift: u32::MAX, decoded: VecDeque::new(), - remaining_bits: 0, - num_remaining_bits: 0, + partial_byte: 0, + next_bit: 0, }; let first_packet = result.read_packet_interleaved()?; @@ -109,21 +201,21 @@ impl MQAReader { fn decode_interleaved(&mut self, sample_buf: &[u32]) { self.decoded.reserve(sample_buf.len() / 16); - let mut accumulator = self.remaining_bits; - let mut num_bits_used = self.num_remaining_bits; + let mut accumulator = self.partial_byte; + let mut next_bit = self.next_bit; for pair in sample_buf.chunks_exact(2) { let bit = (((pair[0] ^ pair[1]) >> self.shift) & 1) as u8; - accumulator = accumulator << 1 | bit; - num_bits_used += 1; - if num_bits_used == 8 { + accumulator |= bit << next_bit; + next_bit += 1; + if next_bit == 8 { self.decoded.push_back(accumulator); - num_bits_used = 0; + next_bit = 0; accumulator = 0; } } - self.remaining_bits = accumulator; - self.num_remaining_bits = num_bits_used; + self.partial_byte = accumulator; + self.next_bit = next_bit; } fn find_sync(samples: &[u32]) -> Option<(u32, usize)> { @@ -131,7 +223,7 @@ impl MQAReader { let mut accumulator: u64 = 0; for (idx, pair) in samples.chunks_exact(2).enumerate() { let bit = (((pair[0] ^ pair[1]) >> shift) & 1) as u64; - accumulator = (accumulator << 1 | bit) & 0xff_ffff_ffff; + accumulator = accumulator >> 1 | bit << 39; if accumulator == SYNC { return Some((shift, idx - 39));