A song analysis library for making playlists
Go to file
2021-06-06 13:51:08 +02:00
.github/workflows Vendor aubio + build ffmpeg all the time 2021-05-15 18:39:54 +02:00
data Just unpacked here 📦 2021-05-14 17:03:44 +02:00
examples Change analysis from Vec<f32> to Analysis 2021-06-05 15:20:57 +02:00
src Make NUMBER_FEATURES public 2021-06-06 13:51:08 +02:00
.gitmodules Vendor aubio-rs pt.2 2021-05-16 14:47:42 +02:00
Cargo.lock Make NUMBER_FEATURES public 2021-06-06 13:51:08 +02:00
Cargo.toml Make Analysis::new public 2021-06-05 23:56:01 +02:00
CHANGELOG.md Make NUMBER_FEATURES public 2021-06-06 13:51:08 +02:00
README.md Merge pull request #6 from Polochon-street/bliss-python-support 2021-05-20 23:17:19 +02:00

crate build doc

bliss music analyser - Rust version

bliss-rs is the Rust improvement of bliss, a library used to make playlists by analyzing songs, and computing distance between them.

Like bliss, it eases the creation of « intelligent » playlists and/or continuous play, à la Spotify/Grooveshark Radio, as well as easing creating plug-ins for existing audio players.

For now (and if you're looking for an easy-to use smooth play experience), blissify implements bliss for MPD.

There are also python bindings.

Note 1: the features bliss-rs outputs is not compatible with the ones used by C-bliss, since it uses different, more accurate values, based on actual literature. It is also faster.

Note 2: The bliss-rs crate is outdated. You should use bliss-audio (this crate) instead.

Examples

For simple analysis / distance computing, a look at examples/distance.rs and examples/analyse.rs.

Ready to use examples:

Compute the distance between two songs

use bliss_audio::Song;

fn main() {
        let song1 = Song::new("/path/to/song1");
        let song2 = Song::new("/path/to/song2");

        println!("Distance between song1 and song2 is {}", song1.distance(song2));
}

Make a playlist from a song

use bliss_rs::{BlissError, Song};
use ndarray::{arr1, Array};
use noisy_float::prelude::n32;

fn main() -> Result<(), BlissError> {
    let paths = vec!["/path/to/song1", "/path/to/song2", "/path/to/song3"];
    let mut songs: Vec<Song> = paths
        .iter()
        .map(|path| Song::new(path))
        .collect::<Result<Vec<Song>, BlissError>>()?;

    // Assuming there is a first song
    let analysis_first_song = arr1(&songs[0].analysis);

    // Identity matrix used to compute the distance.
    // Note that it can be changed to alter feature ponderation, which
    // may yield to better playlists (subjectively).
    let m = Array::eye(analysis_first_song.len());

    songs.sort_by_cached_key(|song| {
        n32((arr1(&song.analysis) - &analysis_first_song)
            .dot(&m)
            .dot(&(arr1(&song.analysis) - &analysis_first_song)))
    });
    println!(
        "Playlist is: {:?}",
        songs
            .iter()
            .map(|song| &song.path)
            .collect::<Vec<&String>>()
    );
    Ok(())
}

Further use

Instead of reinventing ways to fetch a user library, play songs, etc, and embed that into bliss, it is easier to look at the Library trait.

By implementing a few functions to get songs from a media library, and store the resulting analysis, you get access to functions to analyze an entire library (with multithreading), and to make playlists easily.

See blissify for a reference implementation.

Acknowledgements

  • This library relies heavily on aubio's Rust bindings for the spectral / timbral analysis, so a big thanks to both the creators and contributors of librosa, and to @katyo for making aubio bindings for Rust.
  • The first part of the chroma extraction is basically a rewrite of librosa's chroma feature extraction from python to Rust, with just as little features as needed. Thanks to both creators and contributors as well.
  • Finally, a big thanks to Christof Weiss for pointing me in the right direction for the chroma feature summarization, which are basically also a rewrite from Python to Rust of some of the awesome notebooks by AudioLabs Erlangen, that you can find here.