Commit Diff


commit - 9876be8bdab1540cabcb8f42dcb02859b07d6d6d
commit + 51ec796bc07ae3316c9f9cbfc51308b778e47056
blob - 26b5ae38f83806f1db264ca3b268ff8626f1e967
blob + fc922f8701396116387c17d046553d3473839865
--- README.md
+++ README.md
@@ -2,7 +2,7 @@
 [![builds.sr.ht status](https://builds.sr.ht/~mtmn/virittaa.svg)](https://builds.sr.ht/~mtmn/virittaa?)
 
 Command-line BPM and key detection for audio files, backed by
-[Essentia](https://github.com/MTG/essentia): tempo from `RhythmExtractor2013`
+[Essentia](https://essentia.upf.edu/): tempo from `RhythmExtractor2013`
 (multifeature), key from `KeyExtractor` (EDMA profile). The reported BPM is
 Essentia's tempo estimate, not folded into a fixed octave range.
 
blob - 311b515d8803c3d76dec78dca970f3426df5f8fd
blob + 4d3c9b3c15e836787259a020586c378f460e2109
--- flake.nix
+++ flake.nix
@@ -138,8 +138,11 @@
         };
 
         devShells.default = pkgs.mkShell {
-          inherit (commonArgs) USE_TENSORFLOW LIBCLANG_PATH BINDGEN_EXTRA_CLANG_ARGS;
+          inherit (commonArgs) USE_TENSORFLOW LIBCLANG_PATH;
 
+          NIX_CFLAGS_COMPILE = "-isystem ${pkgs.eigen}/include/eigen3";
+          BINDGEN_EXTRA_CLANG_ARGS = "${commonArgs.BINDGEN_EXTRA_CLANG_ARGS} -isystem ${pkgs.eigen}/include/eigen3";
+
           LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs;
           nativeBuildInputs =
             [
blob - 3950f683f9d47dbfa23f5facb38b79ad33f2c251
blob + 137726ca6b40f7b5702c2637008f55d5e75ce63a
--- src/audio_processing.rs
+++ src/audio_processing.rs
@@ -1,4 +1,4 @@
-//! BPM and key detection, backed by Essentia (https://github.com/MTG/essentia)
+//! BPM and key detection, backed by Essentia (<https://essentia.upf.edu/>)
 //! via the `essentia` bindings crate (essentia-rs).
 //!
 //! `MonoLoader` decodes and downmixes to mono at 44.1 kHz, `RhythmExtractor2013`
blob - b7561f41ce77e6d5135cc8bc7bba22c53990b1ad
blob + 7a6afa54673ae435d010952f53e26ee3cb896004
--- src/file_io.rs
+++ src/file_io.rs
@@ -144,17 +144,17 @@ fn read_tags(path: &Path) -> (FileMetadata, Option<(f3
 }
 
 /// Write BPM and key metadata to a file.
+///
+/// # Errors
+///
+/// Returns an error if the file cannot be read, parsed, or written back.
 pub fn write_metadata(path: &Path, bpm: f32, key: &str) -> Result<()> {
-    let is_aiff = path
-        .extension()
-        .and_then(|e| e.to_str())
-        .map(|e| {
-            matches!(
-                e.to_ascii_lowercase().as_str(),
-                "aiff" | "aif" | "aifc" | "afc"
-            )
-        })
-        .unwrap_or(false);
+    let is_aiff = path.extension().and_then(|e| e.to_str()).is_some_and(|e| {
+        matches!(
+            e.to_ascii_lowercase().as_str(),
+            "aiff" | "aif" | "aifc" | "afc"
+        )
+    });
 
     if is_aiff {
         write_aiff_id3(path, bpm, key)
@@ -198,7 +198,7 @@ fn write_aiff_id3(path: &Path, bpm: f32, key: &str) ->
         anyhow::bail!("not a valid IFF/AIFF file");
     }
 
-    for fourcc in [b"ID3 ", b"id3 "] {
+    for fourcc in [*b"ID3 ", *b"id3 "] {
         strip_chunks(&mut file_bytes, fourcc);
     }
 
@@ -242,7 +242,8 @@ fn id3_tag(bpm: &str, key: &str) -> Vec<u8> {
 
     let bpm_frame = text_frame("TBPM", bpm);
     let key_frame = text_frame("TKEY", key);
-    let size = syncsafe(bpm_frame.len() + key_frame.len());
+    let size =
+        syncsafe(u32::try_from(bpm_frame.len() + key_frame.len()).expect("ID3 tag too large"));
 
     let mut tag = Vec::with_capacity(10 + bpm_frame.len() + key_frame.len());
     tag.extend_from_slice(b"ID3");
@@ -261,16 +262,22 @@ fn text_frame(id: &str, value: &str) -> Vec<u8> {
 
     let mut frame = Vec::with_capacity(10 + value.len());
     frame.extend_from_slice(id.as_bytes());
-    frame.extend_from_slice(&((1 + value.len()) as u32).to_be_bytes());
+    frame.extend_from_slice(
+        &u32::try_from(1 + value.len())
+            .expect("frame too large")
+            .to_be_bytes(),
+    );
     frame.extend_from_slice(&TEXT_FLAGS);
     frame.push(TEXT_ENCODING_LATIN1);
     frame.extend_from_slice(value.as_bytes());
     frame
 }
 
-fn syncsafe(n: usize) -> u32 {
-    (((n & 0x0FE00000) << 3) | ((n & 0x001FC000) << 2) | ((n & 0x00003F80) << 1) | (n & 0x0000007F))
-        as u32
+fn syncsafe(n: u32) -> u32 {
+    ((n & 0x0FE0_0000) << 3)
+        | ((n & 0x001F_C000) << 2)
+        | ((n & 0x0000_3F80) << 1)
+        | (n & 0x0000_007F)
 }
 
 fn comm_end(bytes: &[u8]) -> Option<usize> {
@@ -282,9 +289,9 @@ fn comm_end(bytes: &[u8]) -> Option<usize> {
     None
 }
 
-fn strip_chunks(bytes: &mut Vec<u8>, fourcc: &[u8; 4]) {
+fn strip_chunks(bytes: &mut Vec<u8>, fourcc: [u8; 4]) {
     let ranges: Vec<_> = iff_chunks(bytes)
-        .filter(|(_, id, _)| *id == fourcc)
+        .filter(|&(_, id, _)| *id == fourcc)
         .map(|(off, _, size)| (off, off + IFF_HEADER_LEN + pad(size)))
         .collect();
     for (s, e) in ranges.into_iter().rev() {