summaryrefslogtreecommitdiff
path: root/src/flac.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/flac.rs')
-rw-r--r--src/flac.rs245
1 files changed, 169 insertions, 76 deletions
diff --git a/src/flac.rs b/src/flac.rs
index 1c647d6..9b1b7f3 100644
--- a/src/flac.rs
+++ b/src/flac.rs
@@ -1,12 +1,13 @@
use anyhow::{Result, anyhow};
use flac_bound::{FlacEncoder, WriteWrapper};
use i24::i24;
-use md5::{Digest, Md5};
+use md5::{Digest, Md5, Md5Core, digest::core_api::CoreWrapper};
use metaflac::{Block, Tag};
use std::fs::File;
use symphonia::core::{
audio::{Audio, GenericAudioBufferRef},
- formats::{FormatOptions, TrackType, probe::Hint},
+ codecs::audio::AudioDecoder,
+ formats::{FormatOptions, FormatReader, TrackType, probe::Hint},
io::MediaSourceStream,
meta::MetadataOptions,
};
@@ -42,6 +43,164 @@ impl Bps {
}
}
+fn encode_cycle_16(
+ mut format: Box<dyn FormatReader>,
+ mut decoder: Box<dyn AudioDecoder + 'static>,
+ mut encoder: FlacEncoder,
+ hasher: &mut CoreWrapper<Md5Core>,
+) -> Result<()> {
+ let mut buffer: Vec<i32> = Vec::new();
+ let track_id = format.default_track(TrackType::Audio).unwrap().id;
+
+ loop {
+ let packet = match format.next_packet() {
+ Ok(Some(packet)) => packet,
+ Ok(None) => break,
+ Err(error) => return Err(error.into()),
+ };
+
+ if packet.track_id() != track_id {
+ continue;
+ }
+
+ match decoder.decode(&packet) {
+ Ok(audio_buf) => match audio_buf {
+ GenericAudioBufferRef::S32(buf) => {
+ let _ = buf
+ .iter_interleaved()
+ .map(|sample| {
+ let real_sample = sample >> 16;
+ hasher.update(i16::try_from(real_sample).unwrap().to_le_bytes());
+ buffer.push(real_sample);
+ })
+ .collect::<Vec<_>>();
+
+ encoder
+ .process_interleaved(
+ buffer.as_slice(),
+ u32::try_from(buf.samples_planar()).unwrap(),
+ )
+ .unwrap();
+ buffer.clear();
+ }
+ _ => return Err(anyhow!("unsupported codec")),
+ },
+ Err(err) => return Err(err.into()),
+ }
+ }
+
+ if let Err(enc) = encoder.finish() {
+ return Err(anyhow!("Encoding failed:\t{:?}", enc.state()));
+ }
+
+ Ok(())
+}
+
+fn encode_cycle_24(
+ mut format: Box<dyn FormatReader>,
+ mut decoder: Box<dyn AudioDecoder + 'static>,
+ mut encoder: FlacEncoder,
+ hasher: &mut CoreWrapper<Md5Core>,
+) -> Result<()> {
+ let mut buffer: Vec<i32> = Vec::new();
+ let track_id = format.default_track(TrackType::Audio).unwrap().id;
+
+ loop {
+ let packet = match format.next_packet() {
+ Ok(Some(packet)) => packet,
+ Ok(None) => break,
+ Err(error) => return Err(error.into()),
+ };
+
+ if packet.track_id() != track_id {
+ continue;
+ }
+
+ match decoder.decode(&packet) {
+ Ok(audio_buf) => match audio_buf {
+ GenericAudioBufferRef::S32(buf) => {
+ let _ = buf
+ .iter_interleaved()
+ .map(|sample| {
+ let real_sample = sample >> 8;
+ hasher.update(i24::try_from(real_sample).unwrap().to_le_bytes());
+ buffer.push(real_sample);
+ })
+ .collect::<Vec<_>>();
+
+ encoder
+ .process_interleaved(
+ buffer.as_slice(),
+ u32::try_from(buf.samples_planar()).unwrap(),
+ )
+ .unwrap();
+ buffer.clear();
+ }
+ _ => return Err(anyhow!("unsupported codec")),
+ },
+ Err(err) => return Err(err.into()),
+ }
+ }
+
+ if let Err(enc) = encoder.finish() {
+ return Err(anyhow!("Encoding failed:\t{:?}", enc.state()));
+ }
+
+ Ok(())
+}
+
+fn encode_cycle_32(
+ mut format: Box<dyn FormatReader>,
+ mut decoder: Box<dyn AudioDecoder + 'static>,
+ mut encoder: FlacEncoder,
+ hasher: &mut CoreWrapper<Md5Core>,
+) -> Result<()> {
+ let mut buffer: Vec<i32> = Vec::new();
+ let track_id = format.default_track(TrackType::Audio).unwrap().id;
+
+ loop {
+ let packet = match format.next_packet() {
+ Ok(Some(packet)) => packet,
+ Ok(None) => break,
+ Err(error) => return Err(error.into()),
+ };
+
+ if packet.track_id() != track_id {
+ continue;
+ }
+
+ match decoder.decode(&packet) {
+ Ok(audio_buf) => match audio_buf {
+ GenericAudioBufferRef::S32(buf) => {
+ let _ = buf
+ .iter_interleaved()
+ .map(|sample| {
+ hasher.update(sample.to_le_bytes());
+ buffer.push(sample);
+ })
+ .collect::<Vec<_>>();
+
+ encoder
+ .process_interleaved(
+ buffer.as_slice(),
+ u32::try_from(buf.samples_planar()).unwrap(),
+ )
+ .unwrap();
+ buffer.clear();
+ }
+ _ => return Err(anyhow!("unsupported codec")),
+ },
+ Err(err) => return Err(err.into()),
+ }
+ }
+
+ if let Err(enc) = encoder.finish() {
+ return Err(anyhow!("Encoding failed:\t{:?}", enc.state()));
+ }
+
+ Ok(())
+}
+
pub fn encode_file(file: &std::path::Path) -> Result<()> {
let src = std::fs::File::open(file)?;
let mss = MediaSourceStream::new(Box::new(src), Default::default());
@@ -51,21 +210,19 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> {
let format_opts: FormatOptions = Default::default();
let metadata_opts: MetadataOptions = Default::default();
- let mut format = symphonia::default::get_probe()
+ let format = symphonia::default::get_probe()
.probe(&hint, mss, format_opts, metadata_opts)
.unwrap();
let track = format.default_track(TrackType::Audio).unwrap();
- let mut decoder = symphonia::default::get_codecs()
+ let decoder = symphonia::default::get_codecs()
.make_audio_decoder(
track.codec_params.as_ref().unwrap().audio().unwrap(),
&Default::default(),
)
.unwrap();
- let track_id = track.id;
-
let params = track.codec_params.as_ref().unwrap().audio().unwrap();
let config = StreamConfig {
@@ -78,7 +235,7 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> {
let mut outf = File::create(&tempname)?;
let mut outw = WriteWrapper(&mut outf);
- let mut enc = FlacEncoder::new()
+ let enc = FlacEncoder::new()
.unwrap()
.channels(config.channels)
.bits_per_sample(config.bits_per_sample.value())
@@ -90,75 +247,11 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> {
let mut hasher = Md5::new();
- let mut sample_buf: Vec<i32> = Vec::new();
-
- loop {
- let packet = match format.next_packet() {
- Ok(Some(packet)) => packet,
- Ok(None) => break,
- Err(error) => return Err(error.into()),
- };
-
- if packet.track_id() != track_id {
- continue;
- }
-
- match decoder.decode(&packet) {
- Ok(audio_buf) => match audio_buf {
- GenericAudioBufferRef::S32(buf) => {
- match config.bits_per_sample {
- Bps::_16 => {
- let _ = buf
- .iter_interleaved()
- .map(|sample| {
- let real_sample =
- sample >> (32 - config.bits_per_sample.value());
- hasher
- .update(i16::try_from(real_sample).unwrap().to_le_bytes());
- sample_buf.push(real_sample);
- })
- .collect::<Vec<_>>();
- }
- Bps::_24 => {
- let _ = buf
- .iter_interleaved()
- .map(|sample| {
- let real_sample =
- sample >> (32 - config.bits_per_sample.value());
- hasher.update(
- i24::try_from_i32(real_sample).unwrap().to_le_bytes(),
- );
- sample_buf.push(real_sample);
- })
- .collect::<Vec<_>>();
- }
- Bps::_32 => {
- let _ = buf
- .iter_interleaved()
- .map(|sample| {
- hasher.update(sample.to_le_bytes());
- sample_buf.push(sample);
- })
- .collect::<Vec<_>>();
- }
- }
-
- enc.process_interleaved(
- sample_buf.as_slice(),
- u32::try_from(buf.samples_planar()).unwrap(),
- )
- .unwrap();
- sample_buf.clear();
- }
- _ => return Err(anyhow!("unsupported codec")),
- },
- Err(err) => return Err(err.into()),
- }
- }
-
- if let Err(enc) = enc.finish() {
- return Err(anyhow!("Encoding failed:\t{:?}", enc.state()));
- }
+ match config.bits_per_sample {
+ Bps::_16 => encode_cycle_16(format, decoder, enc, &mut hasher),
+ Bps::_24 => encode_cycle_24(format, decoder, enc, &mut hasher),
+ Bps::_32 => encode_cycle_32(format, decoder, enc, &mut hasher),
+ }?;
let tags = Tag::read_from_path(file)?;
let mut output = Tag::read_from_path(&tempname)?;