use audio_processor_traits::num::traits::FloatConst;
use audio_processor_traits::Float;
pub type WindowFunction<F> = fn(n: F, size: F) -> F;
pub enum WindowFunctionType {
Hann,
BlackmanHarris,
Blackman,
Rectangular,
Triangular,
Parzen,
Welch,
Sine,
}
pub fn make_window_vec<F: Float + FloatConst>(size: usize, fn_type: WindowFunctionType) -> Vec<F> {
match fn_type {
WindowFunctionType::Hann => make_hann_vec(size),
WindowFunctionType::BlackmanHarris => make_blackman_harris_vec(size),
WindowFunctionType::Blackman => make_blackman_vec(size),
WindowFunctionType::Rectangular => make_rectangular_vec(size),
WindowFunctionType::Triangular => make_triangular_vec(size),
WindowFunctionType::Parzen => make_parzen_vec(size),
WindowFunctionType::Welch => make_welch_vec(size),
WindowFunctionType::Sine => make_sine_vec(size),
}
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn hann<F>(n: F, size: F) -> F
where
F: Float + FloatConst,
{
0.5 * (1.0 - (2.0 * F::PI() * (n / size)).cos())
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn blackman_harris<F>(n: F, size: F) -> F
where
F: Float + FloatConst,
{
let pi = F::PI();
let a0 = 0.35875;
let a1 = 0.48829;
let a2 = 0.14128;
let a3 = 0.01168;
a0 - a1 * ((2.0 * pi * n) / size).cos() + a2 * ((4.0 * pi * n) / size).cos()
- a3 * ((6.0 * pi * n) / size).cos()
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn blackman<F>(n: F, size: F) -> F
where
F: Float + FloatConst,
{
let pi = F::PI();
let a0 = 0.42; let a1 = 0.5; let a2 = 0.08; a0 - a1 * ((2.0 * pi * n) / size).cos() + a2 * ((4.0 * pi * n) / size).cos()
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn triangular<F>(n: F, size: F) -> F
where
F: Float,
{
let l_value = size;
1.0 - ((n - size / 2.0) / (l_value)).abs()
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn parzen<F>(n: F, size: F) -> F
where
F: Float,
{
let l = size + 1.0;
let w0 = |n: F| {
let mn = n.abs();
if mn <= l / 4.0 {
1.0f64 - 6.0f64 * (n / (l / 2.0)).powi(2) * (1.0 - mn / (l / 2.0))
} else if mn <= l / 2.0 {
2.0f64 * (1.0 - mn / (l / 2.0)).powi(3)
} else {
1.0
}
};
w0(n - size / 2.0)
}
#[numeric_literals::replace_float_literals(F::from(literal).unwrap())]
pub fn welch<F>(n: F, size: F) -> F
where
F: Float,
{
1.0f64 - ((n - size / 2.0) / (size / 2.0)).powi(2)
}
pub fn sine<F>(n: F, size: F) -> F
where
F: Float + FloatConst,
{
(F::PI() * (n / size)).sin()
}
fn make_vec<F>(size: usize, window_fn: WindowFunction<F>) -> Vec<F>
where
F: Float,
{
(0..size)
.map(|n| window_fn(F::from(n).unwrap(), F::from(size).unwrap()))
.collect()
}
pub fn make_hann_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
make_vec(size, hann)
}
pub fn make_blackman_harris_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
make_vec(size, blackman_harris)
}
pub fn make_blackman_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
make_vec(size, blackman)
}
pub fn make_rectangular_vec<F: Float>(size: usize) -> Vec<F> {
(0..size).map(|_| F::from(1.0).unwrap()).collect()
}
pub fn make_triangular_vec<F: Float>(size: usize) -> Vec<F> {
make_vec(size, triangular)
}
pub fn make_parzen_vec<F: Float>(size: usize) -> Vec<F> {
make_vec(size, parzen)
}
pub fn make_welch_vec<F: Float>(size: usize) -> Vec<F> {
make_vec(size, welch)
}
pub fn make_sine_vec<F: Float + FloatConst>(size: usize) -> Vec<F> {
make_vec(size, sine)
}
#[cfg(test)]
mod test {
use audio_processor_testing_helpers::{charts::draw_vec_chart, relative_path};
use super::*;
type WindowFunction = fn(usize) -> Vec<f32>;
fn window_functions() -> Vec<(&'static str, WindowFunction)> {
vec![
("RectangularWindow", make_rectangular_vec),
("TriangularWindow", make_triangular_vec),
("HannWindow", make_hann_vec),
("ParzenWindow", make_parzen_vec),
("WelchWindow", make_welch_vec),
("SineWindow", make_sine_vec),
("BlackmanWindow", make_blackman_vec),
("BlackmanHarrisWindow", make_blackman_harris_vec),
]
}
fn draw_window(label: &str, window_fn: WindowFunction) {
let window = window_fn(1000);
draw_vec_chart(
&relative_path!("src/window_functions/windows"),
label,
window,
);
}
#[test]
fn test_draw_windows() {
for (label, window_fn) in window_functions() {
draw_window(label, window_fn);
}
}
}