summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock105
-rw-r--r--Cargo.toml2
-rw-r--r--src/flac.rs101
3 files changed, 177 insertions, 31 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4ed4816..ed7bae4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -59,6 +59,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -71,6 +77,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
+name = "bytemuck"
+version = "1.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
+
+[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -134,11 +146,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
-name = "claxon"
-version = "0.4.3"
-source = "git+https://github.com/justjakka/claxon.git#919a0fe9902f2b4f2bd1152772cca746eb0df7d2"
-
-[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -231,7 +238,6 @@ dependencies = [
"anyhow",
"clap",
"clap_complete",
- "claxon",
"console",
"ctrlc",
"directories",
@@ -239,6 +245,7 @@ dependencies = [
"indicatif",
"metaflac",
"rusqlite",
+ "symphonia",
"walkdir",
]
@@ -314,6 +321,12 @@ dependencies = [
]
[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -379,6 +392,24 @@ dependencies = [
]
[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -438,6 +469,12 @@ dependencies = [
]
[[package]]
+name = "regex-lite"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
+
+[[package]]
name = "rusqlite"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -479,6 +516,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
+name = "symphonia"
+version = "0.5.4"
+source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#ecefdd0b796207eae7d18e8c26ce59c46c5cb5f6"
+dependencies = [
+ "lazy_static",
+ "symphonia-bundle-flac",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-bundle-flac"
+version = "0.5.4"
+source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#ecefdd0b796207eae7d18e8c26ce59c46c5cb5f6"
+dependencies = [
+ "log",
+ "symphonia-common",
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-common"
+version = "0.5.4"
+source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#ecefdd0b796207eae7d18e8c26ce59c46c5cb5f6"
+dependencies = [
+ "symphonia-core",
+ "symphonia-metadata",
+]
+
+[[package]]
+name = "symphonia-core"
+version = "0.5.4"
+source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#ecefdd0b796207eae7d18e8c26ce59c46c5cb5f6"
+dependencies = [
+ "bitflags",
+ "bytemuck",
+ "lazy_static",
+ "log",
+ "num-complex",
+ "smallvec",
+]
+
+[[package]]
+name = "symphonia-metadata"
+version = "0.5.4"
+source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#ecefdd0b796207eae7d18e8c26ce59c46c5cb5f6"
+dependencies = [
+ "lazy_static",
+ "log",
+ "regex-lite",
+ "smallvec",
+ "symphonia-core",
+]
+
+[[package]]
name = "syn"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index d759241..bef2c9f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,12 +18,12 @@ flac-bound = { version = "0.5.0", default-features = false }
indicatif = { version = "0.18.0", features = ["improved_unicode"] }
walkdir = "2.5.0"
console = { version = "0.16.0", features = ["windows-console-colors"] }
-claxon = { git = "https://github.com/justjakka/claxon.git" }
metaflac = "0.2.8"
rusqlite = { version = "0.36.0", default-features = false, features = [
"modern_sqlite",
] }
ctrlc = "3.4.7"
+symphonia = { git = "https://github.com/pdeljanov/Symphonia.git", branch = "dev-0.6", version = "0.5.4", default-features = false, features = ["flac"] }
[features]
default = ["bundled"]
diff --git a/src/flac.rs b/src/flac.rs
index 7b542ac..f82c29f 100644
--- a/src/flac.rs
+++ b/src/flac.rs
@@ -1,14 +1,30 @@
use anyhow::{Result, anyhow};
-use claxon::{FlacReader, FlacReaderOptions};
use flac_bound::FlacEncoder;
use metaflac::{Block, Tag};
use std::{
- path::Path,
+ fs::File,
+ path::{Path, PathBuf},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
};
+use symphonia::core::{
+ audio::{
+ Audio, AudioBuffer, AudioBytes,
+ sample::{Sample, SampleFormat},
+ },
+ codecs::audio::{AudioDecoder, AudioDecoderOptions},
+ formats::{FormatOptions, FormatReader, TrackType, probe::Hint},
+ io::MediaSourceStream,
+ meta::MetadataOptions,
+};
+
+struct StreamInfo {
+ channels: u32,
+ bps: u32,
+ sample_rate: u32,
+}
pub const CURRENT_VENDOR: &str = "reference libFLAC 1.5.0 20250211";
@@ -37,20 +53,54 @@ fn write_tags(filename: impl AsRef<Path>) -> Result<()> {
Ok(())
}
+fn init_decoder(
+ file: Box<File>,
+) -> Result<(
+ u32,
+ Box<dyn AudioDecoder>,
+ StreamInfo,
+ Box<dyn FormatReader>,
+)> {
+ let mut hint = Hint::new();
+ hint.with_extension("flac");
+ let mss = MediaSourceStream::new(file, Default::default());
+ let fmt_opts = FormatOptions::default();
+ let meta_opts: MetadataOptions = Default::default();
+ let dec_opts: AudioDecoderOptions = Default::default();
+
+ let probed = symphonia::default::get_probe().probe(&hint, mss, fmt_opts, meta_opts)?;
+
+ let track = probed.default_track(TrackType::Audio).unwrap();
+
+ let codec_params = track.codec_params.as_ref().unwrap().audio().unwrap();
+
+ let decoder = symphonia::default::get_codecs().make_audio_decoder(&codec_params, &dec_opts)?;
+
+ let track_id = track.id;
+
+ let streaminfo = StreamInfo {
+ channels: u32::try_from(codec_params.channels.clone().unwrap().count())?,
+ bps: codec_params.bits_per_sample.unwrap(),
+ sample_rate: codec_params.sample_rate.unwrap(),
+ };
+
+ Ok((track_id, decoder, streaminfo, probed))
+}
+
fn encode_file(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<bool> {
let temp_name = filename.as_ref().with_extension("tmp");
if temp_name.exists() {
std::fs::remove_file(&temp_name)?;
}
- let mut decoder = FlacReader::open(&filename)?;
- let streaminfo = decoder.streaminfo();
- let num_channels: usize = streaminfo.channels.try_into()?;
+ let file = Box::new(File::open(&filename)?);
+
+ let (id, mut decoder, streaminfo, mut probe) = init_decoder(file)?;
let mut encoder = if let Some(encoder) = FlacEncoder::new() {
if let Ok(encoder) = encoder
.channels(streaminfo.channels)
- .bits_per_sample(streaminfo.bits_per_sample)
+ .bits_per_sample(streaminfo.bps)
.sample_rate(streaminfo.sample_rate)
.compression_level(8)
.verify(false)
@@ -64,29 +114,32 @@ fn encode_file(filename: impl AsRef<Path>, handler: Arc<AtomicBool>) -> Result<b
return Err(anyhow!("failed to create encoder"));
};
- let mut frame_reader = decoder.blocks();
- let mut buffer = Vec::new();
- let mut block_buffer = Vec::with_capacity(streaminfo.max_block_size as usize * num_channels);
+ let mut sample_buf: Option<AudioBuffer<i32>> = None;
while handler.load(Ordering::SeqCst) {
- match frame_reader.read_next_or_eof(block_buffer) {
- Ok(Some(block)) => {
- for ch in 0..block.channels() {
- buffer.push(block.channel(ch));
+ let packet = if let Some(packet) = probe.next_packet()? {
+ packet
+ } else {
+ break;
+ };
+
+ if packet.track_id() != id {
+ continue;
+ }
+
+ match decoder.decode(&packet) {
+ Ok(audio_buf) => {
+ if sample_buf.is_none() {
+ let spec = *audio_buf.spec();
+
+ sample_buf = Some(AudioBuffer::new(spec, audio_buf.capacity()));
}
- if encoder.process(&buffer).is_err() {
- return Err(anyhow!(
- "Error while processing samples:\t{:?}",
- encoder.state()
- ));
- };
- buffer.clear();
- buffer = buffer.into_iter().map(|_| unreachable!()).collect();
- block_buffer = block.into_buffer();
+ if let Some(buf) = &mut sample_buf {
+ todo!()
+ }
}
- Ok(None) => break,
- Err(error) => return Err(error.into()),
+ Err(err) => return Err(err.into()),
}
}