Compare commits
13 Commits
f446e4ade7
...
6d9489d3a6
Author | SHA1 | Date | |
---|---|---|---|
6d9489d3a6 | |||
|
44f79153ea | ||
|
6b747e224c | ||
|
8d3a3c6433 | ||
|
3fd91bbfae | ||
|
ed2dd72c6b | ||
|
dc3592147c | ||
|
bf35f643fd | ||
|
479fbc7b89 | ||
|
1445939bf8 | ||
|
daee149271 | ||
|
d10a1cf526 | ||
|
f82c98a12e |
|
@ -1,9 +1,13 @@
|
|||
#Changelog
|
||||
|
||||
## bliss 0.6.11
|
||||
* Bump rust-ffmpeg to 6.1.1 to fix build for raspberry pis.
|
||||
|
||||
## bliss 0.6.10
|
||||
* Make the `analyze` function public, for people who don't want to use
|
||||
ffmpeg
|
||||
* Run `cargo update`
|
||||
* Run `cargo update`, bump ffmpeg to 6.1
|
||||
* Fix the library module erroring when wrong UTF-8 ends up in the database.
|
||||
|
||||
## bliss 0.6.9
|
||||
* Add a feature flag for compilation on raspberry pis.
|
||||
|
|
19
Cargo.lock
generated
19
Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler32"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
|
@ -89,8 +95,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bliss-rs"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"anyhow",
|
||||
"bliss-audio-aubio-rs",
|
||||
"clap",
|
||||
|
@ -105,7 +112,6 @@ dependencies = [
|
|||
"neon",
|
||||
"noisy_float",
|
||||
"pretty_assertions",
|
||||
"ripemd",
|
||||
"rustfft",
|
||||
"serde",
|
||||
"serde_ini",
|
||||
|
@ -823,15 +829,6 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560"
|
||||
|
||||
[[package]]
|
||||
name = "ripemd"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"
|
||||
dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "bliss-rs"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
build = "build.rs"
|
||||
authors = ["Polochon-street <polochonstreet@gmx.fr>"]
|
||||
edition = "2021"
|
||||
|
@ -10,7 +10,7 @@ homepage = "https://lelele.io/bliss.html"
|
|||
repository = "https://github.com/Polochon-street/bliss-rs"
|
||||
keywords = ["audio", "analysis", "MIR", "playlist", "similarity"]
|
||||
readme = "README.md"
|
||||
exclude = ["index.node"]
|
||||
exclude = ["data/", "index.node"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["rlib", "cdylib"]
|
||||
|
@ -24,12 +24,14 @@ no-default-features = true
|
|||
# Hopefully we'll be able to use the official aubio-rs at some point.
|
||||
bliss-audio-aubio-rs = { version = "0.2.1", features = ["static"] }
|
||||
crossbeam = "0.8.2"
|
||||
ffmpeg-next = { version = "6.0.0", features = ["static"] }
|
||||
ffmpeg-next = { version = "6.1.1", features = ["static"] }
|
||||
log = "0.4.17"
|
||||
# `rayon` is used only by `par_mapv_inplace` in chroma.rs.
|
||||
# TODO: is the speed gain that substantial?
|
||||
ndarray = { version = "0.15.6", features = ["rayon"] }
|
||||
ndarray-stats = "0.5.1"
|
||||
noisy_float = "0.2.0"
|
||||
ripemd = "0.1.3"
|
||||
adler32 = "1.0.2"
|
||||
rustfft = "6.1.0"
|
||||
thiserror = "1.0.40"
|
||||
strum = "0.24.1"
|
||||
|
|
1
ci_check.sh
Executable file
1
ci_check.sh
Executable file
|
@ -0,0 +1 @@
|
|||
cargo fmt -- --check && cargo clippy --examples --features=serde -- -D warnings && cargo build --verbose && cargo test --verbose && cargo test --verbose --examples && cargo +nightly-2023-02-16 bench --verbose --features=bench --no-run && cargo build --examples --verbose --features=serde
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/picture.jpg
BIN
data/picture.jpg
Binary file not shown.
Before Width: | Height: | Size: 826 KiB |
BIN
data/picture.png
BIN
data/picture.png
Binary file not shown.
Before Width: | Height: | Size: 826 KiB After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
Binary file not shown.
BIN
data/white_noise.mp3
Normal file
BIN
data/white_noise.mp3
Normal file
Binary file not shown.
|
@ -13,8 +13,8 @@ fn main() -> Result<(), String> {
|
|||
let first_path = paths.next().ok_or("Help: ./distance <song1> <song2>")?;
|
||||
let second_path = paths.next().ok_or("Help: ./distance <song1> <song2>")?;
|
||||
|
||||
let song1 = Song::from_path(first_path).map_err(|x| x.to_string())?;
|
||||
let song2 = Song::from_path(second_path).map_err(|x| x.to_string())?;
|
||||
let song1 = Song::from_path(&first_path).map_err(|x| x.to_string())?;
|
||||
let song2 = Song::from_path(&second_path).map_err(|x| x.to_string())?;
|
||||
|
||||
let mut distance_squared: f64 = 0.0;
|
||||
let analysis1 = song1.analysis.as_bytes();
|
||||
|
@ -25,8 +25,8 @@ fn main() -> Result<(), String> {
|
|||
|
||||
println!(
|
||||
"d({:?}, {:?}) = {}",
|
||||
song1.path,
|
||||
song2.path,
|
||||
&first_path,
|
||||
&second_path,
|
||||
distance_squared.sqrt(),
|
||||
);
|
||||
Ok(())
|
||||
|
|
|
@ -437,7 +437,7 @@ mod test {
|
|||
fn test_chroma_desc() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut chroma_desc = ChromaDesc::new(SAMPLE_RATE, 12);
|
||||
chroma_desc.do_(&song.sample_array).unwrap();
|
||||
chroma_desc.do_(&song).unwrap();
|
||||
let expected_values = vec![
|
||||
-0.35661936,
|
||||
-0.63578653,
|
||||
|
@ -457,9 +457,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_chroma_stft_decode() {
|
||||
let signal = Song::decode(Path::new("data/s16_mono_22_5kHz.flac"))
|
||||
.unwrap()
|
||||
.sample_array;
|
||||
let signal = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut stft = stft(&signal, 8192, 2205);
|
||||
|
||||
let file = File::open("data/chroma.npy").unwrap();
|
||||
|
@ -490,9 +488,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_estimate_tuning_decode() {
|
||||
let signal = Song::decode(Path::new("data/s16_mono_22_5kHz.flac"))
|
||||
.unwrap()
|
||||
.sample_array;
|
||||
let signal = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let stft = stft(&signal, 8192, 2205);
|
||||
|
||||
let tuning = estimate_tuning(22050, &stft, 8192, 0.01, 12).unwrap();
|
||||
|
|
18
src/lib.rs
18
src/lib.rs
|
@ -7,8 +7,8 @@ mod timbral;
|
|||
mod utils;
|
||||
|
||||
use neon::{prelude::*, types::buffer::TypedArray};
|
||||
// use song::Song;
|
||||
// use bliss_lib::BlissResult;
|
||||
use song::Song;
|
||||
use bliss_lib::BlissResult;
|
||||
|
||||
#[neon::main]
|
||||
fn main(mut cx: ModuleContext) -> NeonResult<()> {
|
||||
|
@ -59,13 +59,9 @@ fn analyze(mut cx: FunctionContext) -> JsResult<JsUint8Array> {
|
|||
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_le_bytes();
|
||||
// let analysis_bytes = song.analysis.as_bytes();
|
||||
// Ok((version_bytes, analysis_bytes))
|
||||
// }
|
||||
|
||||
fn analyze_raw(path: &str) -> Result<([u8; 2], [u8; 80]), u8> {
|
||||
return Ok(([0; 2], [0; 80]));
|
||||
fn analyze_raw(path: &str) -> BlissResult<([u8; 2], [u8; 80])> {
|
||||
let song = Song::from_path(path)?;
|
||||
let version_bytes = song.features_version.to_le_bytes();
|
||||
let analysis_bytes = song.analysis.as_bytes();
|
||||
Ok((version_bytes, analysis_bytes))
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ mod tests {
|
|||
fn test_loudness() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut loudness_desc = LoudnessDesc::default();
|
||||
for chunk in song.sample_array.chunks_exact(LoudnessDesc::WINDOW_SIZE) {
|
||||
for chunk in song.chunks_exact(LoudnessDesc::WINDOW_SIZE) {
|
||||
loudness_desc.do_(&chunk);
|
||||
}
|
||||
let expected_values = vec![0.271263, 0.2577181];
|
||||
|
|
98
src/song.rs
98
src/song.rs
|
@ -7,7 +7,6 @@
|
|||
//! For implementation of plug-ins for already existing audio players,
|
||||
//! a look at Library is instead recommended.
|
||||
|
||||
extern crate crossbeam;
|
||||
extern crate ffmpeg_next as ffmpeg;
|
||||
extern crate ndarray;
|
||||
|
||||
|
@ -19,7 +18,6 @@ use crate::bliss_lib::{BlissError, BlissResult, SAMPLE_RATE};
|
|||
use crate::bliss_lib::{CHANNELS, FEATURES_VERSION};
|
||||
use ::log::warn;
|
||||
use core::ops::Index;
|
||||
use crossbeam::thread;
|
||||
use ffmpeg_next::codec::threading::{Config, Type as ThreadingType};
|
||||
use ffmpeg_next::util::channel_layout::ChannelLayout;
|
||||
use ffmpeg_next::util::error::Error;
|
||||
|
@ -35,7 +33,7 @@ use std::fmt;
|
|||
use std::path::Path;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::thread as std_thread;
|
||||
use std::thread;
|
||||
use strum::{EnumCount, IntoEnumIterator};
|
||||
use strum_macros::{EnumCount, EnumIter};
|
||||
|
||||
|
@ -234,16 +232,16 @@ impl Song {
|
|||
*
|
||||
* If you *do* want to use this with a song already decoded by yourself,
|
||||
* the sample format of `sample_array` should be f32le, one channel, and
|
||||
* the sampling rate 22050 Hz. Anything other thant that will yield aberrant
|
||||
* the sampling rate 22050 Hz. Anything other than that will yield aberrant
|
||||
* results.
|
||||
* To double-check that your sample array has the right format, you could run
|
||||
* `ffmpeg -i path_to_your_song.flac -ar 22050 -ac 1 -c:a pcm_f32le -f hash -hash ripemd160 -`,
|
||||
* which will give you the ripemd160 hash of the sample array if the song
|
||||
* has been decoded properly. You can then compute the ripemd160 hash of your sample
|
||||
* array (see `_test_decode` in the tests) and make sure both hashes are the same.
|
||||
* `ffmpeg -i path_to_your_song.flac -ar 22050 -ac 1 -c:a pcm_f32le -f hash -hash addler32 -`,
|
||||
* which will give you the addler32 checksum of the sample array if the song
|
||||
* has been decoded properly. You can then compute the addler32 checksum of your sample
|
||||
* array (see `_test_decode` in the tests) and make sure both are the same.
|
||||
*
|
||||
* (Running `ffmpeg -i path_to_your_song.flac -ar 22050 -ac 1 -c:a pcm_f32le` will simply give
|
||||
* you the raw sample array as it should look like, if you're not into computing hashes)
|
||||
* you the raw sample array as it should look like, if you're not into computing checksums)
|
||||
**/
|
||||
pub fn analyze(sample_array: &[f32]) -> BlissResult<Analysis> {
|
||||
let largest_window = vec![
|
||||
|
@ -261,8 +259,8 @@ impl Song {
|
|||
)));
|
||||
}
|
||||
|
||||
thread::scope(|s| {
|
||||
let child_tempo: thread::ScopedJoinHandle<'_, BlissResult<f32>> = s.spawn(|_| {
|
||||
thread::scope(|s| -> BlissResult<Analysis> {
|
||||
let child_tempo = s.spawn(|| {
|
||||
let mut tempo_desc = BPMDesc::new(SAMPLE_RATE)?;
|
||||
let windows = sample_array
|
||||
.windows(BPMDesc::WINDOW_SIZE)
|
||||
|
@ -274,17 +272,14 @@ impl Song {
|
|||
Ok(tempo_desc.get_value())
|
||||
});
|
||||
|
||||
let child_chroma: thread::ScopedJoinHandle<'_, BlissResult<Vec<f32>>> = s.spawn(|_| {
|
||||
let child_chroma = s.spawn(|| {
|
||||
let mut chroma_desc = ChromaDesc::new(SAMPLE_RATE, 12);
|
||||
chroma_desc.do_(sample_array)?;
|
||||
Ok(chroma_desc.get_values())
|
||||
});
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
let child_timbral: thread::ScopedJoinHandle<
|
||||
'_,
|
||||
BlissResult<(Vec<f32>, Vec<f32>, Vec<f32>)>,
|
||||
> = s.spawn(|_| {
|
||||
let child_timbral = s.spawn(|| {
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE)?;
|
||||
let windows = sample_array
|
||||
.windows(SpectralDesc::WINDOW_SIZE)
|
||||
|
@ -298,22 +293,21 @@ impl Song {
|
|||
Ok((centroid, rolloff, flatness))
|
||||
});
|
||||
|
||||
let child_zcr: thread::ScopedJoinHandle<'_, BlissResult<f32>> = s.spawn(|_| {
|
||||
let child_zcr = s.spawn(|| {
|
||||
let mut zcr_desc = ZeroCrossingRateDesc::default();
|
||||
zcr_desc.do_(sample_array);
|
||||
Ok(zcr_desc.get_value())
|
||||
});
|
||||
|
||||
let child_loudness: thread::ScopedJoinHandle<'_, BlissResult<Vec<f32>>> =
|
||||
s.spawn(|_| {
|
||||
let mut loudness_desc = LoudnessDesc::default();
|
||||
let windows = sample_array.chunks(LoudnessDesc::WINDOW_SIZE);
|
||||
let child_loudness = s.spawn(|| {
|
||||
let mut loudness_desc = LoudnessDesc::default();
|
||||
let windows = sample_array.chunks(LoudnessDesc::WINDOW_SIZE);
|
||||
|
||||
for window in windows {
|
||||
loudness_desc.do_(window);
|
||||
}
|
||||
Ok(loudness_desc.get_value())
|
||||
});
|
||||
for window in windows {
|
||||
loudness_desc.do_(window);
|
||||
}
|
||||
Ok(loudness_desc.get_value())
|
||||
});
|
||||
|
||||
// Non-streaming approach for that one
|
||||
let tempo = child_tempo.join().unwrap()?;
|
||||
|
@ -337,7 +331,6 @@ impl Song {
|
|||
})?;
|
||||
Ok(Analysis::new(array))
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn decode(path: &Path) -> BlissResult<Vec<f32>> {
|
||||
|
@ -412,7 +405,7 @@ impl Song {
|
|||
let (tx, rx) = mpsc::channel();
|
||||
let in_codec_format = decoder.format();
|
||||
let in_codec_rate = decoder.rate();
|
||||
let child = std_thread::spawn(move || {
|
||||
let child = thread::spawn(move || {
|
||||
resample_frame(
|
||||
rx,
|
||||
in_codec_format,
|
||||
|
@ -598,8 +591,8 @@ fn push_to_sample_array(frame: &ffmpeg::frame::Audio, sample_array: &mut Vec<f32
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use adler32::RollingAdler32;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ripemd::{Digest, Ripemd160};
|
||||
use std::path::Path;
|
||||
|
||||
#[test]
|
||||
|
@ -648,34 +641,28 @@ mod tests {
|
|||
assert_eq!(FEATURES_VERSION, song.features_version);
|
||||
}
|
||||
|
||||
fn _test_decode(path: &Path, expected_hash: &[u8]) {
|
||||
fn _test_decode(path: &Path, expected_hash: u32) {
|
||||
let samples = Song::decode(path).unwrap();
|
||||
let mut hasher = Ripemd160::new();
|
||||
let mut hasher = RollingAdler32::new();
|
||||
for sample in samples.iter() {
|
||||
hasher.update(sample.to_le_bytes().to_vec());
|
||||
hasher.update_buffer(&sample.to_le_bytes());
|
||||
}
|
||||
|
||||
assert_eq!(expected_hash, hasher.finalize().as_slice());
|
||||
assert_eq!(expected_hash, hasher.hash());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resample_multi() {
|
||||
let path = Path::new("data/s32_stereo_44_1_kHz.flac");
|
||||
let expected_hash = [
|
||||
0xc5, 0xf8, 0x23, 0xce, 0x63, 0x2c, 0xf4, 0xa0, 0x72, 0x66, 0xbb, 0x49, 0xad, 0x84,
|
||||
0xb6, 0xea, 0x48, 0x48, 0x9c, 0x50,
|
||||
];
|
||||
_test_decode(&path, &expected_hash);
|
||||
let expected_hash = 0xbbcba1cf;
|
||||
_test_decode(&path, expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resample_stereo() {
|
||||
let path = Path::new("data/s16_stereo_22_5kHz.flac");
|
||||
let expected_hash = [
|
||||
0x24, 0xed, 0x45, 0x58, 0x06, 0xbf, 0xfb, 0x05, 0x57, 0x5f, 0xdc, 0x4d, 0xb4, 0x9b,
|
||||
0xa5, 0x2b, 0x05, 0x56, 0x10, 0x4f,
|
||||
];
|
||||
_test_decode(&path, &expected_hash);
|
||||
let expected_hash = 0x1d7b2d6d;
|
||||
_test_decode(&path, expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -683,12 +670,9 @@ mod tests {
|
|||
let path = Path::new("data/s16_mono_22_5kHz.flac");
|
||||
// Obtained through
|
||||
// ffmpeg -i data/s16_mono_22_5kHz.flac -ar 22050 -ac 1 -c:a pcm_f32le
|
||||
// -f hash -hash ripemd160 -
|
||||
let expected_hash = [
|
||||
0x9d, 0x95, 0xa5, 0xf2, 0xd2, 0x9c, 0x68, 0xe8, 0x8a, 0x70, 0xcd, 0xf3, 0x54, 0x2c,
|
||||
0x5b, 0x45, 0x98, 0xb4, 0xf3, 0xb4,
|
||||
];
|
||||
_test_decode(&path, &expected_hash);
|
||||
// -f hash -hash addler32 -
|
||||
let expected_hash = 0x5e01930b;
|
||||
_test_decode(&path, expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -696,12 +680,9 @@ mod tests {
|
|||
let path = Path::new("data/s32_stereo_44_1_kHz.mp3");
|
||||
// Obtained through
|
||||
// ffmpeg -i data/s16_mono_22_5kHz.mp3 -ar 22050 -ac 1 -c:a pcm_f32le
|
||||
// -f hash -hash ripemd160 -
|
||||
let expected_hash = [
|
||||
0x28, 0x25, 0x6b, 0x7b, 0x6e, 0x37, 0x1c, 0xcf, 0xc7, 0x06, 0xdf, 0x62, 0x8c, 0x0e,
|
||||
0x91, 0xf7, 0xd6, 0x1f, 0xac, 0x5b,
|
||||
];
|
||||
_test_decode(&path, &expected_hash);
|
||||
// -f hash -hash addler32 -
|
||||
let expected_hash = 0x69ca6906;
|
||||
_test_decode(&path, expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -757,11 +738,8 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_decode_wav() {
|
||||
let expected_hash = [
|
||||
0xf0, 0xe0, 0x85, 0x4e, 0xf6, 0x53, 0x76, 0xfa, 0x7a, 0xa5, 0x65, 0x76, 0xf9, 0xe1,
|
||||
0xe8, 0xe0, 0x81, 0xc8, 0xdc, 0x61,
|
||||
];
|
||||
_test_decode(Path::new("data/piano.wav"), &expected_hash);
|
||||
let expected_hash = 0xde831e82;
|
||||
_test_decode(Path::new("data/piano.wav"), expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -101,7 +101,7 @@ mod tests {
|
|||
fn test_tempo_real() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut tempo_desc = BPMDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(BPMDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(BPMDesc::HOP_SIZE) {
|
||||
tempo_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
assert!(0.01 > (0.378605 - tempo_desc.get_value()).abs());
|
||||
|
|
|
@ -283,7 +283,7 @@ mod tests {
|
|||
fn test_zcr() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut zcr_desc = ZeroCrossingRateDesc::default();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
zcr_desc.do_(&chunk);
|
||||
}
|
||||
assert!(0.001 > (-0.85036 - zcr_desc.get_value()).abs());
|
||||
|
@ -303,13 +303,14 @@ mod tests {
|
|||
assert!(0.0000001 > (expected - actual).abs());
|
||||
}
|
||||
|
||||
let song = Song::decode(Path::new("data/white_noise.flac")).unwrap();
|
||||
let song = Song::decode(Path::new("data/white_noise.mp3")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(22050).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
println!("{:?}", spectral_desc.get_flatness());
|
||||
// White noise - as close to 1 as possible
|
||||
let expected_values = vec![0.6706717, -0.9685736];
|
||||
let expected_values = vec![0.5785303, -0.9426308];
|
||||
for (expected, actual) in expected_values
|
||||
.iter()
|
||||
.zip(spectral_desc.get_flatness().iter())
|
||||
|
@ -322,7 +323,7 @@ mod tests {
|
|||
fn test_spectral_flatness() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
// Spectral flatness mean value computed here with phase vocoder before normalization: 0.111949615
|
||||
|
@ -352,7 +353,7 @@ mod tests {
|
|||
|
||||
let song = Song::decode(Path::new("data/tone_11080Hz.flac")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
let expected_values = vec![0.9967681, -0.99615175];
|
||||
|
@ -368,7 +369,7 @@ mod tests {
|
|||
fn test_spectral_roll_off() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
let expected_values = vec![-0.6326486, -0.7260933];
|
||||
|
@ -386,7 +387,7 @@ mod tests {
|
|||
fn test_spectral_centroid() {
|
||||
let song = Song::decode(Path::new("data/s16_mono_22_5kHz.flac")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
// Spectral centroid mean value computed here with phase vocoder before normalization: 1354.2273
|
||||
|
@ -415,7 +416,7 @@ mod tests {
|
|||
}
|
||||
let song = Song::decode(Path::new("data/tone_11080Hz.flac")).unwrap();
|
||||
let mut spectral_desc = SpectralDesc::new(SAMPLE_RATE).unwrap();
|
||||
for chunk in song.sample_array.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
for chunk in song.chunks_exact(SpectralDesc::HOP_SIZE) {
|
||||
spectral_desc.do_(&chunk).unwrap();
|
||||
}
|
||||
let expected_values = vec![0.97266, -0.9609926];
|
||||
|
|
|
@ -498,7 +498,7 @@ mod tests {
|
|||
|
||||
let song = Song::decode(Path::new("data/piano.flac")).unwrap();
|
||||
|
||||
let stft = stft(&song.sample_array, 2048, 512);
|
||||
let stft = stft(&song, 2048, 512);
|
||||
|
||||
assert!(!stft.is_empty() && !expected_stft.is_empty());
|
||||
for (expected, actual) in expected_stft.iter().zip(stft.iter()) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user