From 8468a9ab8fdb9fc9454c711a3f324495ccfb0e34 Mon Sep 17 00:00:00 2001 From: Polochon-street Date: Wed, 5 Jan 2022 19:19:50 +0100 Subject: [PATCH] Add a features' version number --- CHANGELOG.md | 3 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/chroma.rs | 2 +- src/distance.rs | 2 +- src/lib.rs | 4 ++++ src/library.rs | 6 +++--- src/song.rs | 14 ++++++++++---- src/timbral.rs | 4 ++-- src/utils.rs | 4 ++-- 10 files changed, 28 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02365e9..31c9814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## bliss 0.4.3 +* Add features' version on each Song instance. + ## bliss 0.4.2 * Add a binary example to easily make playlists. diff --git a/Cargo.lock b/Cargo.lock index eace266..481f33e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bliss-audio" -version = "0.4.2" +version = "0.4.3" dependencies = [ "anyhow", "bliss-audio-aubio-rs", diff --git a/Cargo.toml b/Cargo.toml index fa3c5bd..4bc236a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bliss-audio" -version = "0.4.2" +version = "0.4.3" authors = ["Polochon-street "] edition = "2018" license = "GPL-3.0-only" diff --git a/src/chroma.rs b/src/chroma.rs index ff48e61..75bf619 100644 --- a/src/chroma.rs +++ b/src/chroma.rs @@ -321,7 +321,7 @@ fn estimate_tuning( resolution: f64, bins_per_octave: u32, ) -> BlissResult { - let (pitch, mag) = pip_track(sample_rate, &spectrum, n_fft)?; + let (pitch, mag) = pip_track(sample_rate, spectrum, n_fft)?; let (filtered_pitch, filtered_mag): (Vec, Vec) = pitch .iter() diff --git a/src/distance.rs b/src/distance.rs index 5933b7b..6e42cc3 100644 --- a/src/distance.rs +++ b/src/distance.rs @@ -107,7 +107,7 @@ pub fn dedup_playlist_custom_distance( distance: impl DistanceMetric, ) { songs.dedup_by(|s1, s2| { - n32(s1.custom_distance(&s2, &distance)) < distance_threshold.unwrap_or(0.05) + n32(s1.custom_distance(s2, &distance)) < distance_threshold.unwrap_or(0.05) || (s1.title.is_some() && s2.title.is_some() && s1.artist.is_some() diff --git a/src/lib.rs b/src/lib.rs index f87f26b..5f95a11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,6 +85,10 @@ pub use song::{Analysis, AnalysisIndex, Song, NUMBER_FEATURES}; const CHANNELS: u16 = 1; const SAMPLE_RATE: u32 = 22050; +/// Stores the current version of bliss-rs' features. +/// It is bumped every time one or more feature is added, updated or removed, +/// so plug-ins can rescan libraries when there is a major change. +const FEATURES_VERSION: u16 = 1; #[derive(Error, Clone, Debug, PartialEq)] /// Umbrella type for bliss error types diff --git a/src/library.rs b/src/library.rs index 4631fed..a719232 100644 --- a/src/library.rs +++ b/src/library.rs @@ -56,7 +56,7 @@ pub trait Library { for song in &songs { if let Some(album) = &song.album { - if let Some(analysis) = albums_analysis.get_mut(&album as &str) { + if let Some(analysis) = albums_analysis.get_mut(album as &str) { analysis .push_row(song.analysis.as_arr1().view()) .map_err(|e| { @@ -65,7 +65,7 @@ pub trait Library { } else { let mut array = Array::zeros((1, song.analysis.as_arr1().len())); array.assign(&song.analysis.as_arr1()); - albums_analysis.insert(&album, array); + albums_analysis.insert(album, array); } } } @@ -92,7 +92,7 @@ pub trait Library { albums.sort_by_key(|(_, analysis)| { n32(euclidean_distance( first_analysis.as_ref().unwrap(), - &analysis, + analysis, )) }); let albums = albums.get(..playlist_length).unwrap_or(&albums); diff --git a/src/song.rs b/src/song.rs index cd98517..319e73a 100644 --- a/src/song.rs +++ b/src/song.rs @@ -12,7 +12,7 @@ extern crate ffmpeg_next as ffmpeg; extern crate ndarray; extern crate ndarray_npy; -use super::CHANNELS; +use crate::{CHANNELS, FEATURES_VERSION}; use crate::chroma::ChromaDesc; use crate::distance::{euclidean_distance, DistanceMetric}; use crate::misc::LoudnessDesc; @@ -61,6 +61,10 @@ pub struct Song { pub genre: Option, /// bliss analysis results pub analysis: Analysis, + /// Version of the features the song was analyzed with. + /// A simple integer that is bumped every time a breaking change + /// is introduced in the features. + pub features_version: u16, } #[derive(Debug, EnumIter, EnumCount)] @@ -251,6 +255,7 @@ impl Song { track_number: raw_song.track_number, genre: raw_song.genre, analysis: Song::analyse(raw_song.sample_array)?, + features_version: FEATURES_VERSION, }) } @@ -289,7 +294,7 @@ impl Song { .step_by(BPMDesc::HOP_SIZE); for window in windows { - tempo_desc.do_(&window)?; + tempo_desc.do_(window)?; } Ok(tempo_desc.get_value()) }); @@ -310,7 +315,7 @@ impl Song { .windows(SpectralDesc::WINDOW_SIZE) .step_by(SpectralDesc::HOP_SIZE); for window in windows { - spectral_desc.do_(&window)?; + spectral_desc.do_(window)?; } let centroid = spectral_desc.get_centroid(); let rolloff = spectral_desc.get_rolloff(); @@ -330,7 +335,7 @@ impl Song { let windows = sample_array.chunks(LoudnessDesc::WINDOW_SIZE); for window in windows { - loudness_desc.do_(&window); + loudness_desc.do_(window); } Ok(loudness_desc.get_value()) }); @@ -657,6 +662,7 @@ mod tests { for (x, y) in song.analysis.as_vec().iter().zip(expected_analysis) { assert!(0.01 > (x - y).abs()); } + assert_eq!(FEATURES_VERSION, song.features_version); } fn _test_decode(path: &Path, expected_hash: &[u8]) { diff --git a/src/timbral.rs b/src/timbral.rs index a70e0c2..2624207 100644 --- a/src/timbral.rs +++ b/src/timbral.rs @@ -204,12 +204,12 @@ impl SpectralDesc { self.values_rolloff.push(freq); let cvec: CVec = fftgrain.as_slice().into(); - let geo_mean = geometric_mean(&cvec.norm()); + let geo_mean = geometric_mean(cvec.norm()); if geo_mean == 0.0 { self.values_flatness.push(0.0); return Ok(()); } - let flatness = geo_mean / mean(&cvec.norm()); + let flatness = geo_mean / mean(cvec.norm()); self.values_flatness.push(flatness); Ok(()) } diff --git a/src/utils.rs b/src/utils.rs index 4ac8181..72444ae 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -29,7 +29,7 @@ pub(crate) fn stft(signal: &[f32], window_length: usize, hop_length: usize) -> A (signal.len() as f32 / hop_length as f32).ceil() as usize, window_length / 2 + 1, )); - let signal = reflect_pad(&signal, window_length / 2); + let signal = reflect_pad(signal, window_length / 2); // Periodic, so window_size + 1 let mut hann_window = Array::zeros(window_length + 1); @@ -45,7 +45,7 @@ pub(crate) fn stft(signal: &[f32], window_length: usize, hop_length: usize) -> A .step_by(hop_length) .zip(stft.rows_mut()) { - let mut signal = (arr1(&window) * &hann_window).mapv(|x| Complex::new(x, 0.)); + let mut signal = (arr1(window) * &hann_window).mapv(|x| Complex::new(x, 0.)); match signal.as_slice_mut() { Some(s) => fft.process(s), None => {