Skip to content

Commit

Permalink
Added unit tests to basic DSP units
Browse files Browse the repository at this point in the history
  • Loading branch information
maxmarsc committed May 2, 2022
1 parent eadd352 commit 2186063
Show file tree
Hide file tree
Showing 10 changed files with 799 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.wav filter=lfs diff=lfs merge=lfs -text
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ image = "0.24.1"
apodize = "1.0.0"
audiotags = "0.2.7182"
num-traits = "0.2.14"
num-integer = "0.1.44"
num-integer = "0.1.44"
assert_cmd = "2.0.4"
predicates = "2.1.1"
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ Milestone
- [x] Channel naming (stereo, 2.1, 5.1, 7.1 ...)
- [x] Zoom in/out
- [x] Metadata view
- [ ] Optionnal labels on graphs
- [x] RMS and Peak in waveform view
- [x] Option : normalize
- [x] Option : FFT windows size and overlap
- [x] Option : FFT dB threshold
- [x] Option : FFT window type
- [x] Option : FFT side smoothing
- [ ] Tests
- [ ] Optionnal labels on graphs
- [ ] Option : FFT logarithmic scale
- [ ] Option : Waveform envelope ?
- [ ] More audio format support (mp3, flac, ogg...)
5 changes: 3 additions & 2 deletions src/dsp/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::sndfile::SndFile;

use super::normalization::compute_norm;

#[derive(Debug)]
pub struct DspErr {
msg: String
}
Expand All @@ -31,7 +32,7 @@ pub trait DspData<P> {
}


#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AsyncDspDataState {
Created,
Normalizing,
Expand Down Expand Up @@ -147,4 +148,4 @@ impl<T : DspData<P> + Send + 'static, P : Send + 'static> AsyncDspData<T, P> {
phantom: PhantomData::default()
}
}
}
}
163 changes: 162 additions & 1 deletion src/dsp/spectrogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::utils::Zoom;
#[inline(always)]
fn db_to_u8(db: f64, threshold: f64) -> u8 {
if db > 0f64 {
panic!();
return u8::MAX;
}
if db < threshold {
0u8
Expand Down Expand Up @@ -164,3 +164,164 @@ impl Spectrogram {
self.num_bands
}
}

#[cfg(test)]
mod tests {
use crate::dsp::{SidePaddingType, WindowType, Spectrogram, SpectrogramParameters, DspData, AsyncDspData, AsyncDspDataState};
use sndfile;
use std::path::{Path, PathBuf};
use crate::Zoom;
use std::time::Duration;
use std::thread::sleep;

fn get_test_files_location() -> PathBuf {
return Path::new(&env!("CARGO_MANIFEST_DIR").to_string())
.join("tests")
.join("files");
}

#[test]
fn build() {
let overlaps = [0.25f64, 0.5f64, 0.75f64];
let windows = [512usize, 1024, 2048, 4096];
let window_types = [WindowType::Hamming, WindowType::Blackman, WindowType::Hanning, WindowType::Uniform];
let db_thresholds = [-130f64, -80f64, -30f64];
let side_paddings = [SidePaddingType::Loop, SidePaddingType::SmoothRamp, SidePaddingType::Zeros];

for overlap in overlaps {
for window_size in windows {
for wtype in window_types {
for db_th in db_thresholds {
for padding_type in side_paddings {
for norm in [None, Some(1.1f64)] {
let parameters = SpectrogramParameters {
window_size,
overlap_rate: overlap,
window_type: wtype,
db_threshold: db_th,
side_padding_type: padding_type
};

let snd = sndfile::OpenOptions::ReadOnly(sndfile::ReadOptions::Auto)
.from_path(get_test_files_location().join("rock_1s.wav")).unwrap();
Spectrogram::new(snd, parameters, norm).unwrap();
}
}
}
}
}
}
}

#[test]
fn async_build() {
const OVERLAP: f64 = 0.25f64;
const WINDOW_SIZE: usize = 4096;
const DB_THRESHOLD: f64 = -130f64;
let sleep_interval = Duration::new(1, 0);

let parameters = SpectrogramParameters {
window_size: WINDOW_SIZE,
overlap_rate: OVERLAP,
window_type: WindowType::Hanning,
db_threshold: DB_THRESHOLD,
side_padding_type: SidePaddingType::Zeros
};
let path = get_test_files_location().join("rock_1s.wav");

let mut async_data: AsyncDspData<Spectrogram, SpectrogramParameters> = AsyncDspData::new(&path, parameters, false);
let mut attempts = 0;

loop {
sleep(sleep_interval);
async_data.update_status();
let state = async_data.state();

assert_ne!(state, AsyncDspDataState::Failed);
assert!(attempts < 90);

if state == AsyncDspDataState::Finished {
break;
}
attempts += 1;
}
}

#[test]
fn async_build_normalize() {
const OVERLAP: f64 = 0.25f64;
const WINDOW_SIZE: usize = 4096;
const DB_THRESHOLD: f64 = -130f64;
let sleep_interval = Duration::new(1, 0);

let parameters = SpectrogramParameters {
window_size: WINDOW_SIZE,
overlap_rate: OVERLAP,
window_type: WindowType::Hanning,
db_threshold: DB_THRESHOLD,
side_padding_type: SidePaddingType::Zeros
};
let path = get_test_files_location().join("rock_1s.wav");

let mut async_data: AsyncDspData<Spectrogram, SpectrogramParameters> = AsyncDspData::new(&path, parameters, true);
let mut attempts = 0;

loop {
sleep(sleep_interval);
async_data.update_status();
let state = async_data.state();

assert_ne!(state, AsyncDspDataState::Failed);
assert!(attempts < 90);

if state == AsyncDspDataState::Finished {
break;
}
attempts += 1;
}
}

#[test]
fn get_data() {
const OVERLAP: f64 = 0.25f64;
const WINDOW_SIZE: usize = 4096;
const DB_THRESHOLD: f64 = -130f64;

let parameters = SpectrogramParameters {
window_size: WINDOW_SIZE,
overlap_rate: OVERLAP,
window_type: WindowType::Hanning,
db_threshold: DB_THRESHOLD,
side_padding_type: SidePaddingType::Zeros
};

let snd = sndfile::OpenOptions::ReadOnly(sndfile::ReadOptions::Auto)
.from_path(get_test_files_location().join("rock_1s.wav")).unwrap();
let channels = snd.get_channels();
let mut spectro = Spectrogram::new(snd, parameters, None).unwrap();
let num_bins = spectro.num_bins();

let mut zoom = Zoom::new(0.5f64).unwrap();

// No zoom
for ch_idx in 0..channels {
let (no_zoom_data, num_bands) = spectro.data(ch_idx, &mut zoom);

assert_ne!(no_zoom_data.len(), 0usize);
assert_eq!(num_bins * num_bands, no_zoom_data.len());
}

// Zoom in and move
for _ in 0..10 {
zoom.zoom_in();
zoom.move_right();

for ch_idx in 0..channels {
let (no_zoom_data, num_bands) = spectro.data(ch_idx, &mut zoom);

assert_ne!(no_zoom_data.len(), 0usize);
assert_eq!(num_bins * num_bands, no_zoom_data.len());
}
}
}
}
Loading

0 comments on commit 2186063

Please sign in to comment.