diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/flac.rs | 134 | ||||
| -rw-r--r-- | src/main.rs | 64 |
2 files changed, 167 insertions, 31 deletions
diff --git a/src/flac.rs b/src/flac.rs index 92c4b77..8653881 100644 --- a/src/flac.rs +++ b/src/flac.rs @@ -1,32 +1,126 @@ use anyhow::{Result, anyhow}; +use claxon::FlacReader; use flac_bound::{FlacEncoder, WriteWrapper}; +use i24::i24; use md5::{Digest, Md5}; use metaflac::Tag; use std::fs::File; -#[derive(Debug)] struct StreamConfig { channels: u32, - bits_per_sample: u32, + bits_per_sample: Bps, sample_rate: u32, total_samples_estimate: u64, } +enum Bps { + _16, + _24, + _32, +} + +impl Bps { + fn new(num: u32) -> Result<Self> { + match num { + 16 => Ok(Bps::_16), + 24 => Ok(Bps::_24), + 32 => Ok(Bps::_32), + _ => Err(anyhow!("Invalid BPS")), + } + } + + fn value(&self) -> u32 { + match self { + Bps::_16 => 16, + Bps::_24 => 24, + Bps::_32 => 32, + } + } +} + +fn process_samples_i16( + hasher: &mut impl Digest, + mut reader: FlacReader<File>, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::<Vec<_>>() + .chunks(4096) + { + enc.process_interleaved(samples, 4096 / config.channels) + .unwrap(); + let _ = samples + .iter() + .map(|sample| hasher.update((i16::try_from(*sample)).unwrap().to_le_bytes())) + .collect::<Vec<_>>(); + } + Ok(()) +} + +fn process_samples_i24( + hasher: &mut impl Digest, + mut reader: FlacReader<File>, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::<Vec<_>>() + .chunks(4096) + { + enc.process_interleaved(samples, 4096 / config.channels) + .unwrap(); + let _ = samples + .iter() + .map(|sample| hasher.update((i24::try_from(*sample)).unwrap().to_le_bytes())) + .collect::<Vec<_>>(); + } + Ok(()) +} + +fn process_samples_i32( + hasher: &mut impl Digest, + mut reader: FlacReader<File>, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::<Vec<_>>() + .chunks(4096) + { + enc.process_interleaved(samples, 4096 / config.channels) + .unwrap(); + let _ = samples + .iter() + .map(|sample| hasher.update(sample.to_le_bytes())) + .collect::<Vec<_>>(); + } + Ok(()) +} + pub fn encode_file(file: &std::path::Path) -> Result<()> { - let mut reader = claxon::FlacReader::open(file)?; + let reader = claxon::FlacReader::open(file)?; let config = StreamConfig { channels: reader.streaminfo().channels, - bits_per_sample: reader.streaminfo().bits_per_sample, + bits_per_sample: Bps::new(reader.streaminfo().bits_per_sample)?, sample_rate: reader.streaminfo().sample_rate, total_samples_estimate: reader.streaminfo().samples.unwrap(), }; + let tempname = format!("{}.{}", file.display(), "tmp"); + let mut outf = File::create(&tempname)?; let mut outw = WriteWrapper(&mut outf); let mut enc = FlacEncoder::new() .unwrap() .channels(config.channels) - .bits_per_sample(config.bits_per_sample) + .bits_per_sample(config.bits_per_sample.value()) .sample_rate(config.sample_rate) .total_samples_estimate(config.total_samples_estimate) .compression_level(8) @@ -35,30 +129,15 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> { .unwrap(); let mut hasher = Md5::new(); - let mut bytes = Vec::new(); - for samples in reader - .samples() - .map(|sample| sample.unwrap()) - .collect::<Vec<_>>() - .chunks(4096) - { - enc.process_interleaved(samples, 4096 / config.channels).unwrap(); - let _ = samples - .iter() - .map(|sample| { - for byte in sample.to_le_bytes() { - bytes.push(byte) - } - }) - .collect::<Vec<_>>(); - hasher.update(&bytes); - bytes.clear(); - } + match config.bits_per_sample { + Bps::_16 => process_samples_i16(&mut hasher, reader, &mut enc, &config)?, + Bps::_24 => process_samples_i24(&mut hasher, reader, &mut enc, &config)?, + Bps::_32 => process_samples_i32(&mut hasher, reader, &mut enc, &config)?, + }; - match enc.finish() { - Ok(_) => {} - Err(enc) => return Err(anyhow!("Encoding failed:\t{:?}", enc.state())), + if let Err(enc) = enc.finish() { + return Err(anyhow!("Encoding failed:\t{:?}", enc.state())); } /* let source_tags = Tag::read_from_path(file)?; @@ -68,7 +147,6 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> { for block in source_tags.blocks() { todo!() } */ - let mut tags = Tag::read_from_path(tempname)?; let mut streaminfo = tags.get_streaminfo().unwrap().clone(); streaminfo.md5 = hasher.finalize()[..].to_vec(); diff --git a/src/main.rs b/src/main.rs index ba95650..89343f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,65 @@ mod flac; fn main() { - if let Err(error) = flac::encode_file(std::path::Path::new("./1.flac")) { - println!("{}", error) - }; + todo!() +} + +#[cfg(test)] +mod tests { + use super::*; + use metaflac::Tag; + #[test] + fn bit16() { + flac::encode_file(std::path::Path::new("16bit.flac")).unwrap(); + let target_md5 = Tag::read_from_path("16bit.flac.tmp") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + let source_md5 = Tag::read_from_path("16bit.flac") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + std::fs::remove_file(std::path::Path::new("16bit.flac.tmp")).unwrap(); + assert_eq!(target_md5, source_md5); + } + #[test] + fn bit24() { + flac::encode_file(std::path::Path::new("24bit.flac")).unwrap(); + let target_md5 = Tag::read_from_path("24bit.flac.tmp") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + let source_md5 = Tag::read_from_path("24bit.flac") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + std::fs::remove_file(std::path::Path::new("24bit.flac.tmp")).unwrap(); + assert_eq!(target_md5, source_md5); + } + #[test] + fn bit32() { + flac::encode_file(std::path::Path::new("32bit.flac")).unwrap(); + let target_md5 = Tag::read_from_path("32bit.flac.tmp") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + let source_md5 = Tag::read_from_path("32bit.flac") + .unwrap() + .get_streaminfo() + .unwrap() + .md5 + .clone(); + std::fs::remove_file(std::path::Path::new("32bit.flac.tmp")).unwrap(); + assert_eq!(target_md5, source_md5); + } } |
