summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjakka <jakkadoujin@gmail.com>2025-06-04 21:30:40 +0300
committerjakka <jakkadoujin@gmail.com>2025-06-04 21:30:40 +0300
commita7615b9471dfe6fe94a3ace6e4f94e9c78844b51 (patch)
tree360aee3c3c7127e9bc76611af81c0a06c3a72ab1 /src
parentf5c4e39405cada1fb8dcf3072b2f40d1590e218c (diff)
added 16 and 24 bit md5sum calculation support
Diffstat (limited to 'src')
-rw-r--r--src/flac.rs134
-rw-r--r--src/main.rs64
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);
+ }
}