Skip to content

Commit

Permalink
Playlists from multiple tracks (#72)
Browse files Browse the repository at this point in the history
* Enable playlists based on multiple songs

This commit introduces functionality for generating playlist based on a
set of songs.

For good performance, I also introduce a new distance measure, extended
isolation distance.

While the previous distance metrics, euclidean distance and cosine
distance, could be made to measure distance to a set of songs, the
performance will not be as good.

* Remove *_by_key family of functions

Remove code duplication by making these functions generic over
AsRef<Song> instead of having separate versions.

* Get rid of circular dependency between playlist and song

The playlist module depends on the song module, which in turn depends on
the playlist module. This is confusing, and in this case also completely
unecessary.

* Unify distance metrics

Allow euclidean distance and cosine distance to handle a set of songs as
input. In doing so, we can also remove the ability to generate playlists
from a single song, as that is just a special case of generating a
playlist from many songs anyway.

* Review comment: Improve documentation for single song use case

* Add test for ForestOption as DistanceMetricBuilder.

* Remove unecessary double-reference

* Add missing test assertion.

* Remove comment that is no longer relevant.

* Fix extended isolation forest test case

* Document suggestions and limitations for distance metric

* cargo fmt
  • Loading branch information
SimonTeixidor authored and Polochon-street committed Apr 3, 2024
1 parent 9df0f12 commit ec968ff
Show file tree
Hide file tree
Showing 11 changed files with 654 additions and 643 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#Changelog
# Changelog

## bliss 0.7.0
* Add the possibility to make playlists based on multiple songs using extended
isolation forest (Thanks @SimonTeixidor!)
* Remove *_by_key family of functions (Thanks @SimonTeixidor!)
* Remove circular dependency between playlist and song by removing distances
from the `Song` struct (Thanks @SimonTeixidor!)

## bliss 0.6.11
* Bump rust-ffmpeg to 6.1.1 to fix build for raspberry pis.
Expand Down
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ library = [
"dep:anyhow", "dep:serde_ini", "dep:serde_json",
"dep:indicatif",
]
serde = ["dep:serde"]
serde = ["dep:serde", "extended-isolation-forest/serde"]

[dependencies]
# Until https://github.com/aubio/aubio/issues/336 is somehow solved
Expand All @@ -54,6 +54,7 @@ thiserror = "1.0.40"
strum = "0.24.1"
strum_macros = "0.24.3"
rcue = "0.1.3"
extended-isolation-forest = { version = "0.2.3", default-features = false }

# Deps for the library feature
serde = { version = "1.0", optional = true, features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions examples/distance.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bliss_audio::Song;
use bliss_audio::{playlist::euclidean_distance, Song};
use std::env;

/**
Expand All @@ -20,7 +20,7 @@ fn main() -> Result<(), String> {
"d({:?}, {:?}) = {}",
song1.path,
song2.path,
song1.distance(&song2)
euclidean_distance(&song1.analysis.as_arr1(), &song2.analysis.as_arr1())
);
Ok(())
}
2 changes: 1 addition & 1 deletion examples/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ fn main() -> Result<()> {
.unwrap_or("20")
.parse::<usize>()?;
let library: Library<Config> = Library::from_config_path(config_path)?;
let songs = library.playlist_from::<()>(song_path, playlist_length)?;
let songs = library.playlist_from::<()>(&[song_path], playlist_length)?;
let song_paths = songs
.into_iter()
.map(|s| s.bliss_song.path.to_string_lossy().to_string())
Expand Down
2 changes: 1 addition & 1 deletion examples/library_extra_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ fn main() -> Result<()> {
.unwrap_or("20")
.parse::<usize>()?;
let library: Library<Config> = Library::from_config_path(config_path)?;
let songs = library.playlist_from::<ExtraInfo>(song_path, playlist_length)?;
let songs = library.playlist_from::<ExtraInfo>(&[song_path], playlist_length)?;
let playlist = songs
.into_iter()
.map(|s| {
Expand Down
4 changes: 2 additions & 2 deletions examples/playlist.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::Result;
use bliss_audio::playlist::{closest_to_first_song, dedup_playlist, euclidean_distance};
use bliss_audio::playlist::{closest_to_songs, dedup_playlist, euclidean_distance};
use bliss_audio::{analyze_paths, Song};
use clap::{App, Arg};
use glob::glob;
Expand Down Expand Up @@ -77,7 +77,7 @@ fn main() -> Result<()> {
.into_iter()
.filter(|x| x == &first_song || paths.contains(&x.path.to_string_lossy().to_string()))
.collect();
closest_to_first_song(&first_song, &mut songs_to_chose_from, euclidean_distance);
closest_to_songs(&[first_song], &mut songs_to_chose_from, &euclidean_distance);
dedup_playlist(&mut songs_to_chose_from, None);

fs::write(analysis_path, serialized)?;
Expand Down
11 changes: 7 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@
//!
//! ### Analyze & compute the distance between two songs
//! ```no_run
//! use bliss_audio::{BlissResult, Song};
//! use bliss_audio::{BlissResult, Song, playlist::euclidean_distance};
//!
//! fn main() -> BlissResult<()> {
//! let song1 = Song::from_path("/path/to/song1")?;
//! let song2 = Song::from_path("/path/to/song2")?;
//!
//! println!("Distance between song1 and song2 is {}", song1.distance(&song2));
//! println!(
//! "Distance between song1 and song2 is {}",
//! euclidean_distance(&song1.analysis.as_arr1(), &song2.analysis.as_arr1())
//! );
//! Ok(())
//! }
//! ```
Expand All @@ -42,7 +45,7 @@
//! ```no_run
//! use bliss_audio::{
//! analyze_paths,
//! playlist::{closest_to_first_song, euclidean_distance},
//! playlist::{closest_to_songs, euclidean_distance},
//! BlissResult, Song,
//! };
//!
Expand All @@ -53,7 +56,7 @@
//! // Assuming there is a first song
//! let first_song = songs.first().unwrap().to_owned();
//!
//! closest_to_first_song(&first_song, &mut songs, euclidean_distance);
//! closest_to_songs(&[first_song], &mut songs, &euclidean_distance);
//!
//! println!("Playlist is:");
//! for song in songs {
Expand Down
Loading

0 comments on commit ec968ff

Please sign in to comment.