audio_processor_analysis/window_functions/
mod.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
24use audio_processor_traits::num::traits::FloatConst;
25use audio_processor_traits::Float;
26
27pub type WindowFunction<F> = fn(n: F, size: F) -> F;
28
29pub enum WindowFunctionType {
30    Hann,
31    BlackmanHarris,
32    Blackman,
33    Rectangular,
34    Triangular,
35    Parzen,
36    Welch,
37    Sine,
38}
39
40pub fn make_window_vec<F: Float + FloatConst>(size: usize, fn_type: WindowFunctionType) -> Vec<F> {
41    match fn_type {
42        WindowFunctionType::Hann => make_hann_vec(size),
43        WindowFunctionType::BlackmanHarris => make_blackman_harris_vec(size),
44        WindowFunctionType::Blackman => make_blackman_vec(size),
45        WindowFunctionType::Rectangular => make_rectangular_vec(size),
46        WindowFunctionType::Triangular => make_triangular_vec(size),
47        WindowFunctionType::Parzen => make_parzen_vec(size),
48        WindowFunctionType::Welch => make_welch_vec(size),
49        WindowFunctionType::Sine => make_sine_vec(size),
50    }
51}
52
53#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
54pub fn hann<F>(n: F, size: F) -> F
55where
56    F: Float + FloatConst,
57{
58    0.5 * (1.0 - (2.0 * F::PI() * (n / size)).cos())
59}
60
61#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
62pub fn blackman_harris<F>(n: F, size: F) -> F
63where
64    F: Float + FloatConst,
65{
66    let pi = F::PI();
67    let a0 = 0.35875;
68    let a1 = 0.48829;
69    let a2 = 0.14128;
70    let a3 = 0.01168;
71    a0 - a1 * ((2.0 * pi * n) / size).cos() + a2 * ((4.0 * pi * n) / size).cos()
72        - a3 * ((6.0 * pi * n) / size).cos()
73}
74
75#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
76pub fn blackman<F>(n: F, size: F) -> F
77where
78    F: Float + FloatConst,
79{
80    // let alpha = 0.16;
81    let pi = F::PI();
82    let a0 = 0.42; // (1.0 - alpha) / 2.0;
83    let a1 = 0.5; // 1.0 / 2.0;
84    let a2 = 0.08; // alpha / 2.0;
85    a0 - a1 * ((2.0 * pi * n) / size).cos() + a2 * ((4.0 * pi * n) / size).cos()
86}
87
88#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
89pub fn triangular<F>(n: F, size: F) -> F
90where
91    F: Float,
92{
93    let l_value = size;
94    1.0 - ((n - size / 2.0) / (l_value)).abs()
95}
96
97#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
98pub fn parzen<F>(n: F, size: F) -> F
99where
100    F: Float,
101{
102    let l = size + 1.0;
103    let w0 = |n: F| {
104        let mn = n.abs();
105        if mn <= l / 4.0 {
106            1.0f64 - 6.0f64 * (n / (l / 2.0)).powi(2) * (1.0 - mn / (l / 2.0))
107        } else if mn <= l / 2.0 {
108            2.0f64 * (1.0 - mn / (l / 2.0)).powi(3)
109        } else {
110            1.0
111        }
112    };
113    w0(n - size / 2.0)
114}
115
116#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
117pub fn welch<F>(n: F, size: F) -> F
118where
119    F: Float,
120{
121    1.0f64 - ((n - size / 2.0) / (size / 2.0)).powi(2)
122}
123
124pub fn sine<F>(n: F, size: F) -> F
125where
126    F: Float + FloatConst,
127{
128    (F::PI() * (n / size)).sin()
129}
130
131fn make_vec<F>(size: usize, window_fn: WindowFunction<F>) -> Vec<F>
132where
133    F: Float,
134{
135    (0..size)
136        .map(|n| window_fn(F::from(n).unwrap(), F::from(size).unwrap()))
137        .collect()
138}
139
140pub fn make_hann_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
141    make_vec(size, hann)
142}
143
144pub fn make_blackman_harris_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
145    make_vec(size, blackman_harris)
146}
147
148pub fn make_blackman_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
149    make_vec(size, blackman)
150}
151
152pub fn make_rectangular_vec<F: Float>(size: usize) -> Vec<F> {
153    (0..size).map(|_| F::from(1.0).unwrap()).collect()
154}
155
156pub fn make_triangular_vec<F: Float>(size: usize) -> Vec<F> {
157    make_vec(size, triangular)
158}
159
160pub fn make_parzen_vec<F: Float>(size: usize) -> Vec<F> {
161    make_vec(size, parzen)
162}
163
164pub fn make_welch_vec<F: Float>(size: usize) -> Vec<F> {
165    make_vec(size, welch)
166}
167
168pub fn make_sine_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
169    make_vec(size, sine)
170}
171
172#[cfg(test)]
173mod test {
174    use audio_processor_testing_helpers::{charts::draw_vec_chart, relative_path};
175
176    use super::*;
177
178    type WindowFunction = fn(usize) -> Vec<f32>;
179    fn window_functions() -> Vec<(&'static str, WindowFunction)> {
180        vec![
181            ("RectangularWindow", make_rectangular_vec),
182            ("TriangularWindow", make_triangular_vec),
183            ("HannWindow", make_hann_vec),
184            ("ParzenWindow", make_parzen_vec),
185            ("WelchWindow", make_welch_vec),
186            ("SineWindow", make_sine_vec),
187            ("BlackmanWindow", make_blackman_vec),
188            ("BlackmanHarrisWindow", make_blackman_harris_vec),
189        ]
190    }
191
192    fn draw_window(label: &str, window_fn: WindowFunction) {
193        let window = window_fn(1000);
194        draw_vec_chart(
195            &relative_path!("src/window_functions/windows"),
196            label,
197            window,
198        );
199    }
200
201    #[test]
202    fn test_draw_windows() {
203        for (label, window_fn) in window_functions() {
204            draw_window(label, window_fn);
205        }
206    }
207}