From a7615b9471dfe6fe94a3ace6e4f94e9c78844b51 Mon Sep 17 00:00:00 2001 From: jakka Date: Wed, 4 Jun 2025 21:30:40 +0300 Subject: added 16 and 24 bit md5sum calculation support --- src/flac.rs | 134 +++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 28 deletions(-) (limited to 'src/flac.rs') 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 { + 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, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::>() + .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::>(); + } + Ok(()) +} + +fn process_samples_i24( + hasher: &mut impl Digest, + mut reader: FlacReader, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::>() + .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::>(); + } + Ok(()) +} + +fn process_samples_i32( + hasher: &mut impl Digest, + mut reader: FlacReader, + enc: &mut FlacEncoder, + config: &StreamConfig, +) -> Result<()> { + for samples in reader + .samples() + .map(|sample| sample.unwrap()) + .collect::>() + .chunks(4096) + { + enc.process_interleaved(samples, 4096 / config.channels) + .unwrap(); + let _ = samples + .iter() + .map(|sample| hasher.update(sample.to_le_bytes())) + .collect::>(); + } + 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::>() - .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::>(); - 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(); -- cgit v1.3.1