Compare commits
4 Commits
b4d5019d83
...
b66d32c84e
Author | SHA1 | Date | |
---|---|---|---|
b66d32c84e | |||
3e5a9f32a0 | |||
2a89ddb2ca | |||
5fd2ef3902 |
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
target
|
target
|
||||||
node_modules
|
node_modules
|
||||||
|
index.node
|
||||||
|
|
55
Cargo.lock
generated
55
Cargo.lock
generated
|
@ -244,7 +244,7 @@ checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.7.4",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -693,16 +693,6 @@ version = "0.2.151"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.6.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.7.4"
|
version = "0.7.4"
|
||||||
|
@ -845,45 +835,29 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neon"
|
name = "neon"
|
||||||
version = "0.10.1"
|
version = "1.0.0-alpha.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28e15415261d880aed48122e917a45e87bb82cf0260bb6db48bbab44b7464373"
|
checksum = "8687031acf51f8b065aaf906b5a694f8d6b547c5c9430b6d636ab42422bfd0cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"neon-build",
|
"libloading",
|
||||||
"neon-macros",
|
"neon-macros",
|
||||||
"neon-runtime",
|
"once_cell",
|
||||||
"semver",
|
"semver",
|
||||||
|
"send_wrapper",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "neon-build"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8bac98a702e71804af3dacfde41edde4a16076a7bbe889ae61e56e18c5b1c811"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "neon-macros"
|
name = "neon-macros"
|
||||||
version = "0.10.1"
|
version = "1.0.0-alpha.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7288eac8b54af7913c60e0eb0e2a7683020dffa342ab3fd15e28f035ba897cf"
|
checksum = "facd664405d5140677a63d7b7c5762425dd9d4179e07d2e67da29089c50b1ddd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
"syn-mid",
|
"syn-mid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "neon-runtime"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4676720fa8bb32c64c3d9f49c47a47289239ec46b4bdb66d0913cc512cb0daca"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libloading 0.6.7",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "noisy_float"
|
name = "noisy_float"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -1373,18 +1347,15 @@ checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||||
dependencies = [
|
|
||||||
"semver-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver-parser"
|
name = "send_wrapper"
|
||||||
version = "0.7.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
|
|
|
@ -69,7 +69,7 @@ anyhow = { version = "1.0.58", optional = true }
|
||||||
indicatif = { version = "0.17.0", optional = true }
|
indicatif = { version = "0.17.0", optional = true }
|
||||||
|
|
||||||
[dependencies.neon]
|
[dependencies.neon]
|
||||||
version = "0.10.1"
|
version = "1.0.0-alpha.4"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["napi-6", "channel-api", "promise-api", "try-catch-api"]
|
features = ["napi-6", "channel-api", "promise-api", "try-catch-api"]
|
||||||
|
|
||||||
|
|
21
README.md
21
README.md
|
@ -2,7 +2,26 @@
|
||||||
[![build](https://github.com/Polochon-street/bliss-rs/workflows/Rust/badge.svg)](https://github.com/Polochon-street/bliss-rs/actions)
|
[![build](https://github.com/Polochon-street/bliss-rs/workflows/Rust/badge.svg)](https://github.com/Polochon-street/bliss-rs/actions)
|
||||||
[![doc](https://docs.rs/bliss-audio/badge.svg)](https://docs.rs/bliss-audio/)
|
[![doc](https://docs.rs/bliss-audio/badge.svg)](https://docs.rs/bliss-audio/)
|
||||||
|
|
||||||
# bliss music analyzer - Rust version
|
# Fork notice
|
||||||
|
This repo is a fork of [bliss-rs](https://github.com/Polochon-street/bliss-rs) with bindings for Node.js (using N-API and Neon).
|
||||||
|
|
||||||
|
## Example usage:
|
||||||
|
The package will be published to the Gitea registry and available for installation later.
|
||||||
|
```ts
|
||||||
|
import { analyze, analyzeSync } from 'bliss';
|
||||||
|
|
||||||
|
await analyze("/path/to/track.mp3") // returns Uint8Array
|
||||||
|
```
|
||||||
|
|
||||||
|
## Return value
|
||||||
|
The output of `bliss-rs` consists of single-precision floats, currently 20 of them. This fork contains code to convert it into an array of 80 bytes in little endian order. An additional version (also comes from `bliss-rs`, currently equal to `1`) is prepended at the start as 16 bits in platform endianness. Therefore, the total output size is 82 bytes.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
The output (without the version) is meant to be converted back into floats and used to calculate the [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance#Higher_dimensions) between two songs. Other distance algorithms are being worked on by the Bliss team.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# (Original README) bliss music analyzer - Rust version
|
||||||
bliss-rs is the Rust improvement of [bliss](https://github.com/Polochon-street/bliss), a
|
bliss-rs is the Rust improvement of [bliss](https://github.com/Polochon-street/bliss), a
|
||||||
library used to make playlists by analyzing songs, and computing distance between them.
|
library used to make playlists by analyzing songs, and computing distance between them.
|
||||||
|
|
||||||
|
|
2
index.d.ts
vendored
Normal file
2
index.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export function analyzeSync(path: string): Uint8Array;
|
||||||
|
export function analyze(path: string): Promise<Uint8Array>;
|
BIN
index.node
BIN
index.node
Binary file not shown.
|
@ -1,8 +1,9 @@
|
||||||
{
|
{
|
||||||
"name": "bliss-rs",
|
"name": "bliss-rs",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "[![crate](https://img.shields.io/crates/v/bliss-audio.svg)](https://crates.io/crates/bliss-audio) [![build](https://github.com/Polochon-street/bliss-rs/workflows/Rust/badge.svg)](https://github.com/Polochon-street/bliss-rs/actions) [![doc](https://docs.rs/bliss-audio/badge.svg)](https://docs.rs/bliss-audio/)",
|
"description": "A fork of the bliss-rs library with Node.js bindings",
|
||||||
"main": "index.js",
|
"main": "index.node",
|
||||||
|
"types": "index.d.ts",
|
||||||
"directories": {
|
"directories": {
|
||||||
"example": "examples"
|
"example": "examples"
|
||||||
},
|
},
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
"build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics"
|
"build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "antonlyap",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cargo-cp-artifact": "^0.1.8"
|
"cargo-cp-artifact": "^0.1.8"
|
||||||
|
|
|
@ -80,7 +80,10 @@ use thiserror::Error;
|
||||||
|
|
||||||
pub use crate::song::{Analysis, AnalysisIndex, Song, NUMBER_FEATURES};
|
pub use crate::song::{Analysis, AnalysisIndex, Song, NUMBER_FEATURES};
|
||||||
|
|
||||||
|
/// Target channels for ffmpeg
|
||||||
pub const CHANNELS: u16 = 1;
|
pub const CHANNELS: u16 = 1;
|
||||||
|
|
||||||
|
/// Target sample rate for ffmpeg
|
||||||
pub const SAMPLE_RATE: u32 = 22050;
|
pub const SAMPLE_RATE: u32 = 22050;
|
||||||
/// Stores the current version of bliss-rs' features.
|
/// Stores the current version of bliss-rs' features.
|
||||||
/// It is bumped every time one or more feature is added, updated or removed,
|
/// It is bumped every time one or more feature is added, updated or removed,
|
||||||
|
|
57
src/lib.rs
57
src/lib.rs
|
@ -10,15 +10,62 @@ mod temporal;
|
||||||
mod timbral;
|
mod timbral;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use neon::prelude::*;
|
use neon::{prelude::*, types::buffer::TypedArray};
|
||||||
|
use song::Song;
|
||||||
|
use bliss_lib::BlissResult;
|
||||||
|
|
||||||
#[neon::main]
|
#[neon::main]
|
||||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||||
cx.export_function("test", test)?;
|
cx.export_function("analyzeSync", analyze)?;
|
||||||
|
cx.export_function("analyze", analyze_async)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(mut cx: FunctionContext) -> JsResult<JsNumber> {
|
#[allow(deprecated)]
|
||||||
Ok(cx.number(34))
|
fn analyze_async(mut cx: FunctionContext) -> JsResult<JsPromise> {
|
||||||
|
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||||
|
let promise = cx.task(move || {
|
||||||
|
analyze_raw(&path)
|
||||||
|
}).promise(|mut cx, result| {
|
||||||
|
result
|
||||||
|
.map(|(version_bytes, analysis_bytes)| {
|
||||||
|
let mut buffer_handle = JsUint8Array::new(
|
||||||
|
&mut cx,
|
||||||
|
analysis_bytes.len() + version_bytes.len(),
|
||||||
|
).unwrap();
|
||||||
|
let buffer = buffer_handle.as_mut_slice(&mut cx);
|
||||||
|
|
||||||
|
buffer[0..version_bytes.len()].copy_from_slice(&version_bytes);
|
||||||
|
buffer[version_bytes.len()..].copy_from_slice(&analysis_bytes);
|
||||||
|
buffer_handle
|
||||||
|
})
|
||||||
|
.or_else(|e| cx.throw_error(e.to_string()))
|
||||||
|
});
|
||||||
|
Ok(promise)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a Uint8Array, with the first 2 bytes being the version in platform endianness
|
||||||
|
/// and the rest (currently 80 bytes) being the analysis data in little endian
|
||||||
|
fn analyze(mut cx: FunctionContext) -> JsResult<JsUint8Array> {
|
||||||
|
let path = cx.argument::<JsString>(0)?.value(&mut cx);
|
||||||
|
let (version_bytes, analysis_bytes) = analyze_raw(&path)
|
||||||
|
.or_else(|e| cx.throw_error(e.to_string()))?;
|
||||||
|
|
||||||
|
let mut buffer_handle = JsUint8Array::new(
|
||||||
|
&mut cx,
|
||||||
|
analysis_bytes.len() + version_bytes.len(),
|
||||||
|
)?;
|
||||||
|
let buffer = buffer_handle.as_mut_slice(&mut cx);
|
||||||
|
|
||||||
|
buffer[0..version_bytes.len()].copy_from_slice(&version_bytes);
|
||||||
|
buffer[version_bytes.len()..].copy_from_slice(&analysis_bytes);
|
||||||
|
|
||||||
|
Ok(buffer_handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn analyze_raw(path: &str) -> BlissResult<([u8; 2], [u8; 80])> {
|
||||||
|
let song = Song::from_path(path)?;
|
||||||
|
let version_bytes = song.features_version.to_ne_bytes();
|
||||||
|
let analysis_bytes = song.analysis.as_bytes();
|
||||||
|
Ok((version_bytes, analysis_bytes))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user