audio_processor_testing_helpers/
lib.rs

1// Augmented Audio: Audio libraries and applications
2// Copyright (c) 2022 Pedro Tacla Yamada
3//
4// The MIT License (MIT)
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22// THE SOFTWARE.
23
24//! Provides helpers for testing audio processors.
25//!
26//! * Drawing charts from a vector with `plotters` - `charts`
27//! * Getting asset paths relative to the crate being tested - `relative_path!`
28//! * Comparing floats - `assert_f_eq`
29//! * Calculating RMS - `rms_level`
30//! * Generating sine buffers - `sine_buffer`
31//! * Generating frequency response charts - `charts`
32
33pub use generators::*;
34pub use util::rms_level;
35
36pub mod charts;
37mod generators;
38mod util;
39
40/// Compare two floats are equal using `f32::EPSILON`
41#[macro_export]
42macro_rules! assert_f_eq {
43    ($left:expr, $right:expr) => {{
44        match (&$left, &$right) {
45            (left_val, right_val) => {
46                assert!(
47                    ((left_val - right_val).abs() as f32) < f32::EPSILON,
48                    "left: {:?} not equal right: {:?}",
49                    left_val,
50                    right_val
51                );
52            }
53        }
54    }};
55}
56
57/// Get a path relative to the root directory (the one with `Cargo.toml`) of the current crate.
58///
59/// Use in unit-tests to get test asset paths.
60#[macro_export]
61macro_rules! relative_path {
62    ($path: expr) => {
63        format!("{}/./{}", env!("CARGO_MANIFEST_DIR"), $path)
64    };
65}
66
67/// Test two buffers have equivalent RMS levels
68pub fn test_level_equivalence(
69    input_buffer: &[f32],
70    output_buffer: &[f32],
71    input_window_size: usize,
72    output_window_size: usize,
73    threshold: f32,
74) {
75    let input_chunks = input_buffer.chunks(input_window_size);
76    let output_chunks = output_buffer.chunks(output_window_size);
77    assert!(!input_buffer.is_empty());
78    assert!(!output_buffer.is_empty());
79    // assert!((input_chunks.len() as i32 - output_chunks.len() as i32).abs() < 2);
80    for (input_chunk, output_chunk) in input_chunks.zip(output_chunks) {
81        let input_level = rms_level(input_chunk);
82        let output_level = rms_level(output_chunk);
83        let diff = (input_level - output_level).abs();
84
85        assert!(
86            diff < threshold,
87            "diff={} threshold={} input_level={} output_level={}",
88            diff,
89            threshold,
90            input_level,
91            output_level
92        );
93    }
94}
95
96#[cfg(test)]
97mod test {
98    #[test]
99    fn test_relative_path() {
100        assert!(std::fs::read_to_string(relative_path!("src/lib.rs"))
101            .unwrap()
102            .contains("fn test_relative_path()"));
103    }
104}