use std::io::{BufRead, BufReader, Cursor, Read}; /// Destroy an MP3, ripping it's frames apart. Also removes any ID3v2 tags /// because who needs metadata? pub struct Breaker { frames: Vec, } impl Breaker { pub fn new() -> Self { Self { frames: vec![] } } pub fn split(&mut self, mut data: Vec) -> Result<(), std::io::Error> { let cursor = Cursor::new(data); let mut reader = BufReader::new(cursor); let mut consumed = 0; loop { let mut three = [0x00, 0x00, 0x00]; reader.read_exact(&mut three)?; consumed += 3; if &three == b"ID3" { println!("ID3v2 offset {:X}", consumed); Self::skip_id3v2(&mut reader)? } else if three[0] == 0xFF && three[2] & 0b1110_0000 == 0b1110_0000 { let mut one_more = [0x00]; reader.read_exact(&mut one_more)?; } } todo!() } /// Assumes the ident "TAG" was already consumed fn skip_id3v2(reader: &mut R) -> Result<(), std::io::Error> { // We don't actually want this, but want to get rid of it. let mut version_and_flags = [0x00, 0x00, 0x00]; reader.read_exact(&mut version_and_flags)?; println!( "Version {} Revision {}", version_and_flags[0], version_and_flags[1] ); let mut syncsafe_size = [0x00, 0x00, 0x00, 0x00]; reader.read_exact(&mut syncsafe_size)?; // Size is MSB let mut size = syncsafe_size[3] as u32; // Shift right eight, but back one because most significant bit is 0 due to syncsafe size |= (syncsafe_size[2] as u32) << 7; size |= (syncsafe_size[1] as u32) << 14; size |= (syncsafe_size[0] as u32) << 21; let human = if size > 1024 * 1024 { format!("{:.2}MiB", size as f32 / (1024.0 * 1024.0)) } else if size > 1024 { format!("{:.2}KiB", size as f32 / 1024.0) } else { format!("{size}B") }; println!("ID3v2 size is {human} bytes"); // Make a vec size big. We're not here to be efficient, sorry if this dissapoint you. let mut skip = vec![0x00; size as usize]; reader.read_exact(&mut skip) } } pub struct Frame { header: Header, data: Vec, } pub struct Header { version: Version, layer: Layer, crc: bool, } impl Header { pub fn from_bytes(raw: [u8; 4]) -> Result { if raw[0] != 0xFF || raw[1] & 0b1110_0000 != 0b1110_0000 { return Err(Error::HeaderUnsync); } let version = Version::from(raw[1]); let layer = Layer::from(raw[1]); let crc = raw[1] & 1 == 0; let bitrate = Bitrate::resolve(raw[2], version, layer); todo!() } // Algorithm taken from: // http://www.multiweb.cz/twoinches/mp3inside.htm /// The length of the header and data pub fn length(&self) -> usize { todo!() } /// The length of the audio data. This is just the length - 4 pub fn data_length(&self) -> usize { self.length() - 4 } } #[derive(Debug, thiserror::Error)] pub enum Error { #[error("tried to parse header, but first 11 bits were not 1; not synced!")] HeaderUnsync, #[error("The version or the layer was a reserved value")] CannotResolveBitrate, #[error("Bitrate bits were all 1")] BitrateBad, } #[derive(Copy, Clone, Debug)] pub enum Version { Mpeg2_5, Reserved, Mpeg2, Mpeg1, } impl From for Version { fn from(byte: u8) -> Self { match byte & 0b000_11_000 { 0b000_00_000 => Version::Mpeg2_5, 0b000_01_000 => Version::Reserved, 0b000_10_000 => Version::Mpeg2, 0b000_11_000 => Version::Mpeg1, _ => unreachable!(), } } } #[derive(Copy, Clone, Debug)] pub enum Layer { Reserved, Layer3, Layer2, Layer1, } impl From for Layer { fn from(byte: u8) -> Self { match byte & 0b000_00_110 { 0b000_00_000 => Layer::Reserved, 0b000_00_010 => Layer::Layer3, 0b000_00_100 => Layer::Layer2, 0b000_00_110 => Layer::Layer1, _ => unreachable!(), } } } /// What do you want from me it's hard to name a thing that's just number. #[derive(Copy, Clone, Debug, PartialEq)] pub enum Bitrate { RateFree, Rate8, Rate16, Rate24, Rate32, Rate40, Rate48, Rate56, Rate64, Rate80, Rate96, Rate112, Rate128, Rate144, Rate160, Rate176, Rate192, Rate224, Rate256, Rate288, Rate320, Rate352, Rate384, Rate416, Rate448, } impl Bitrate { /// Takes the third byte of the header and other neccesary information pub fn resolve(third: u8, version: Version, layer: Layer) -> Result { #[rustfmt::skip] macro_rules! v { (Any) => { _ }; (v1) => { Version::Mpeg1 }; (v2) => { Version::Mpeg2 | Version::Mpeg2_5 }; } #[rustfmt::skip] macro_rules! l { (Any) => { _ }; (l1) => { Layer::Layer1 }; (l2) => { Layer::Layer2 }; (l3) => { Layer::Layer3 }; (l23) => { Layer::Layer2 | Layer::Layer3 }; } #[rustfmt::skip] macro_rules! br { (b0000) => { Fourbit::Zero }; (b0001) => { Fourbit::One }; (b0010) => { Fourbit::Two }; (b0011) => { Fourbit::Three }; (b0100) => { Fourbit::Four }; (b0101) => { Fourbit::Five }; (b0110) => { Fourbit::Six }; (b0111) => { Fourbit::Seven }; (b1000) => { Fourbit::Eight }; (b1001) => { Fourbit::Nine }; (b1010) => { Fourbit::Ten }; (b1011) => { Fourbit::Eleven }; (b1100) => { Fourbit::Twelve }; (b1101) => { Fourbit::Thirteen }; (b1110) => { Fourbit::Fourteen }; (b1111) => { Fourbit::Fifteen }; (down1 b0010) => {br!(b0011)}; (down1 b0011) => {br!(b0100)}; (down1 b0100) => {br!(b0101)}; (down1 b0101) => {br!(b0110)}; (down1 b0110) => {br!(b0111)}; (down1 b0111) => {br!(b1000)}; (down1 b1000) => {br!(b1001)}; (down4 b0010) => {br!(b0110)}; (down4 b0011) => {br!(b0111)}; (down4 b0100) => {br!(b1000)}; (down4 b0101) => {br!(b1001)}; (down4 b0110) => {br!(b1010)}; (down4 b0111) => {br!(b1011)}; (down4 b1000) => {br!(b1100)}; (down5 b0110) => {br!(b1011)}; (down5 b0111) => {br!(b1100)}; (down5 b1000) => {br!(b1101)}; (down6 b0110) => {br!(b1100)}; (down6 b0111) => {br!(b1101)}; (down6 b1000) => {br!(b1110)}; } macro_rules! vl1 { ($br:ident) => { brvl!($br v1 l1) }; } macro_rules! v2_l23 { ($br:ident) => { brvl!($br v2 l23) }; } macro_rules! brvl { ($br:ident $v:ident $l:ident) => { (br!($br), v!($v), l!($l)) }; (down1 $br:ident $v:ident $l:ident) => { (br!(down1 $br), v!($v), l!($l)) }; (down4 $br:ident $v:ident $l:ident) => { (br!(down4 $br), v!($v), l!($l)) }; (down5 $br:ident $v:ident $l:ident) => { (br!(down5 $br), v!($v), l!($l)) }; (down6 $br:ident $v:ident $l:ident) => { (br!(down6 $br), v!($v), l!($l)) }; } macro_rules! heartbeat_bird { ($col_v1_l2:ident) => { brvl!($col_v1_l2 v1 l2) | brvl!($col_v1_l2 v2 l1) | brvl!(down1 $col_v1_l2 v1 l3) | brvl!(down4 $col_v1_l2 v2 l23) }; } // rustc was apparently unhappy about my brvl!(down4) calls. And down5, down6 :( macro_rules! crooked_down { ($col_v1_l1:ident) => { brvl!($col_v1_l1 v1 l1) | (br!(down4 $col_v1_l1), v!(v1), l!(l2)) | (br!(down5 $col_v1_l1), v!(v1), l!(l3)) | (br!(down6 $col_v1_l1), v!(v2), l!(l1)) }; } let br_4bit = Fourbit::from_u8((third & 0b1111_0000) >> 4).expect("this can't happen"); let tuple = (br_4bit, version, layer); match tuple { // These patterns cover a very large surface area heartbeat_bird!(b0010) => Ok(Bitrate::Rate48), heartbeat_bird!(b0011) => Ok(Bitrate::Rate56), heartbeat_bird!(b0100) => Ok(Bitrate::Rate64), heartbeat_bird!(b0101) => Ok(Bitrate::Rate80), heartbeat_bird!(b0110) => Ok(Bitrate::Rate96), heartbeat_bird!(b0111) => Ok(Bitrate::Rate112), heartbeat_bird!(b1000) => Ok(Bitrate::Rate128), crooked_down!(b0110) => Ok(Bitrate::Rate192), crooked_down!(b0111) => Ok(Bitrate::Rate224), crooked_down!(b1000) => Ok(Bitrate::Rate256), // Then we start at the top and work our way down, // row by row as long as there are still values we have to match there brvl!(b0000 Any Any) => Ok(Bitrate::RateFree), brvl!(b0001 v1 Any) => Ok(Bitrate::Rate32), brvl!(b0001 v2 l1) => Ok(Bitrate::Rate32), brvl!(b0001 v2 l23) => Ok(Bitrate::Rate8), vl1!(b0010) => Ok(Bitrate::Rate64), brvl!(b0010 v1 l3) => Ok(Bitrate::Rate40), v2_l23!(b0010) => Ok(Bitrate::Rate16), vl1!(b0011) => Ok(Bitrate::Rate96), v2_l23!(b0011) => Ok(Bitrate::Rate24), vl1!(b0100) => Ok(Bitrate::Rate128), v2_l23!(b0100) => Ok(Bitrate::Rate32), vl1!(b0101) => Ok(Bitrate::Rate160), v2_l23!(b0101) => Ok(Bitrate::Rate40), // 0110, 0111, and 1000 are entirely covered by the patterns :D vl1!(b1001) => Ok(Bitrate::Rate288), brvl!(b1001 v1 l2) => Ok(Bitrate::Rate160), brvl!(b1001 v2 l1) => Ok(Bitrate::Rate144), brvl!(b1010 v1 l1) => Ok(Bitrate::Rate320), brvl!(b1010 v1 l3) => Ok(Bitrate::Rate160), brvl!(b1010 v2 l1) => Ok(Bitrate::Rate160), vl1!(b1011) => Ok(Bitrate::Rate352), brvl!(b1011 v2 l1) => Ok(Bitrate::Rate176), vl1!(b1100) => Ok(Bitrate::Rate384), vl1!(b1101) => Ok(Bitrate::Rate416), brvl!(b1101 v1 l2) => Ok(Bitrate::Rate320), v2_l23!(b1101) => Ok(Bitrate::Rate144), vl1!(b1110) => Ok(Bitrate::Rate448), brvl!(b1110 v1 l2) => Ok(Bitrate::Rate384), brvl!(b1110 v1 l3) => Ok(Bitrate::Rate320), v2_l23!(b1110) => Ok(Bitrate::Rate160), (br!(b1111), _, _) => Err(Error::BitrateBad), (_, Version::Reserved, _) | (_, _, Layer::Reserved) => Err(Error::CannotResolveBitrate), } } pub fn from_kbps(kbps: usize) -> Option { println!("{kbps}"); match kbps { 8 => Some(Bitrate::Rate8), 16 => Some(Bitrate::Rate16), 24 => Some(Bitrate::Rate24), 32 => Some(Bitrate::Rate32), 40 => Some(Bitrate::Rate40), 48 => Some(Bitrate::Rate48), 56 => Some(Bitrate::Rate56), 64 => Some(Bitrate::Rate64), 80 => Some(Bitrate::Rate80), 96 => Some(Bitrate::Rate96), 112 => Some(Bitrate::Rate112), 128 => Some(Bitrate::Rate128), 144 => Some(Bitrate::Rate144), 160 => Some(Bitrate::Rate160), 176 => Some(Bitrate::Rate176), 192 => Some(Bitrate::Rate192), 224 => Some(Bitrate::Rate224), 256 => Some(Bitrate::Rate256), 288 => Some(Bitrate::Rate288), 320 => Some(Bitrate::Rate320), 352 => Some(Bitrate::Rate352), 384 => Some(Bitrate::Rate384), 416 => Some(Bitrate::Rate416), 448 => Some(Bitrate::Rate448), _ => None, } } pub const fn kbps(&self) -> Option { match self { Bitrate::RateFree => None, Bitrate::Rate8 => Some(8), Bitrate::Rate16 => Some(16), Bitrate::Rate24 => Some(24), Bitrate::Rate32 => Some(32), Bitrate::Rate40 => Some(40), Bitrate::Rate48 => Some(48), Bitrate::Rate56 => Some(56), Bitrate::Rate64 => Some(64), Bitrate::Rate80 => Some(80), Bitrate::Rate96 => Some(96), Bitrate::Rate112 => Some(112), Bitrate::Rate128 => Some(128), Bitrate::Rate144 => Some(144), Bitrate::Rate160 => Some(160), Bitrate::Rate176 => Some(176), Bitrate::Rate192 => Some(192), Bitrate::Rate224 => Some(224), Bitrate::Rate256 => Some(256), Bitrate::Rate288 => Some(288), Bitrate::Rate320 => Some(320), Bitrate::Rate352 => Some(352), Bitrate::Rate384 => Some(384), Bitrate::Rate416 => Some(416), Bitrate::Rate448 => Some(448), } } pub const fn bitrate(&self) -> Option { match self.kbps() { None => None, Some(kbr) => Some(kbr * 1000), } } } pub enum Fourbit { Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Eleven, Twelve, Thirteen, Fourteen, Fifteen, } impl Fourbit { pub fn from_u8(value: u8) -> Option { if value > 15 { return None; } Some(match value { 0 => Fourbit::Zero, 1 => Fourbit::One, 2 => Fourbit::Two, 3 => Fourbit::Three, 4 => Fourbit::Four, 5 => Fourbit::Five, 6 => Fourbit::Six, 7 => Fourbit::Seven, 8 => Fourbit::Eight, 9 => Fourbit::Nine, 10 => Fourbit::Ten, 11 => Fourbit::Eleven, 12 => Fourbit::Twelve, 13 => Fourbit::Thirteen, 14 => Fourbit::Fourteen, 15 => Fourbit::Fifteen, _ => unreachable!(), }) } } #[cfg(test)] mod test { use super::{Bitrate, Layer, Version}; // Lookup table of bitrates excluding 0000 and 1111. The former is Free, the latter is Bad #[rustfmt::skip] const BR_LUT: [usize; 5 * 14] = [ 32, 32, 32, 32, 8, 64, 48, 40, 48, 16, 96, 56, 48, 56, 24, 128, 64, 56, 64, 32, 160, 80, 64, 80, 40, 192, 96, 80, 96, 48, 224, 112, 96, 112, 56, 256, 128, 112, 128, 64, 288, 160, 128, 144, 80, 320, 192, 160, 160, 96, 352, 224, 192, 176, 112, 384, 256, 224, 192, 128, 416, 320, 256, 224, 144, 448, 384, 320, 256, 160 ]; fn bitrate_lut() -> Vec { BR_LUT .into_iter() .map(|kbps| Bitrate::from_kbps(kbps).unwrap()) .collect() } #[test] fn correctly_resolves_bitrates() { let lut = bitrate_lut(); for index in 0..75 { let br = (index as u8 / 5) << 4; let (version, layer) = match index % 5 { 0 => (Version::Mpeg1, Layer::Layer1), 1 => (Version::Mpeg1, Layer::Layer2), 2 => (Version::Mpeg1, Layer::Layer3), 3 => (Version::Mpeg2, Layer::Layer1), 4 => (Version::Mpeg2, Layer::Layer2), _ => unreachable!(), }; let resolved_bitrate = Bitrate::resolve(br, version, layer).unwrap(); let bre = match index { 0 | 1 | 2 | 3 | 4 => Bitrate::RateFree, _ => lut[index - 5], }; if resolved_bitrate != bre { panic!("Failed on {:04b}, {version:?}, {layer:?}", br >> 4); } assert_eq!(bre, resolved_bitrate) } } }