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}