use crate::{
error::{InvalidResponse, Result},
types::{Band, Symmetry},
};
use num_traits::{Float, FloatConst};
pub fn adjust_desired<'a, T, D>(
desired: D,
symmetry: Symmetry,
odd_length: bool,
) -> impl Fn(T) -> T + 'a
where
T: Float + FloatConst,
D: Fn(T) -> T + 'a,
{
move |f| {
let d = (desired)(f / T::TAU());
match (symmetry, odd_length) {
(Symmetry::Even, true) => d,
(Symmetry::Even, false) => d / (T::from(0.5).unwrap() * f).cos(),
(Symmetry::Odd, false) => d / (T::from(0.5).unwrap() * f).sin(),
(Symmetry::Odd, true) => d / f.sin(),
}
}
}
pub fn adjust_weights<'a, T, W>(
weights: W,
symmetry: Symmetry,
odd_length: bool,
) -> impl Fn(T) -> T + 'a
where
T: Float + FloatConst,
W: Fn(T) -> T + 'a,
{
move |f| {
let weight = (weights)(f / T::TAU());
match (symmetry, odd_length) {
(Symmetry::Even, true) => weight,
(Symmetry::Even, false) => weight * (T::from(0.5).unwrap() * f).cos(),
(Symmetry::Odd, false) => weight * (T::from(0.5).unwrap() * f).sin(),
(Symmetry::Odd, true) => weight * f.sin(),
}
}
}
pub fn check_response<T, D>(
bands: &[Band<T>],
desired: D,
symmetry: Symmetry,
odd_length: bool,
) -> Result<()>
where
T: Float,
D: Fn(T) -> T,
{
let zero = T::zero();
let nyq = T::from(0.5).unwrap();
match (symmetry, odd_length) {
(Symmetry::Even, true) => {
Ok(())
}
(Symmetry::Even, false) => {
if bands.last().unwrap().end() == nyq && desired(nyq) != zero {
Err(InvalidResponse::EvenSymmEvenLengthNyquist)?
} else {
Ok(())
}
}
(Symmetry::Odd, false) => {
if bands[0].begin() == zero && desired(zero) != zero {
Err(InvalidResponse::OddSymmEvenLengthDC)?
} else {
Ok(())
}
}
(Symmetry::Odd, true) => {
if bands[0].begin() == zero && desired(zero) != zero {
Err(InvalidResponse::OddSymmOddLengthDC)?
} else if bands.last().unwrap().end() == nyq && desired(nyq) != zero {
Err(InvalidResponse::OddSymmOddLengthNyquist)?
} else {
Ok(())
}
}
}
}
pub fn adjust_bands<T: Float>(bands: &mut Vec<Band<T>>, symmetry: Symmetry, odd_length: bool) {
fn avoid_zero<T: Float>(bands: &mut Vec<Band<T>>) {
let eps = T::from(1e-4).unwrap();
let zero = T::zero();
if bands[0].begin() == zero {
let replacement = eps;
if bands[0].end() < replacement {
bands.remove(0);
} else {
bands[0] = Band::new(replacement, bands[0].end()).unwrap();
}
}
}
fn avoid_nyquist<T: Float>(bands: &mut Vec<Band<T>>) {
let eps = T::from(1e-4).unwrap();
let nyq = T::from(0.5).unwrap();
if bands.last().unwrap().end() == nyq {
let replacement = nyq - eps;
if bands.last().unwrap().begin() > replacement {
bands.pop();
} else {
*bands.last_mut().unwrap() =
Band::new(bands.last().unwrap().begin(), replacement).unwrap();
}
}
}
match (symmetry, odd_length) {
(Symmetry::Even, true) => {
}
(Symmetry::Even, false) => {
avoid_nyquist(bands);
}
(Symmetry::Odd, false) => {
avoid_zero(bands);
}
(Symmetry::Odd, true) => {
avoid_zero(bands);
avoid_nyquist(bands);
}
}
}
pub fn h_from_ak<T: Float>(
ak: &[T],
num_taps: usize,
symmetry: Symmetry,
odd_length: bool,
) -> Vec<T> {
let mut h = Vec::with_capacity(num_taps);
let scale = T::from(0.5).unwrap();
let scale4 = T::from(0.25).unwrap();
match (symmetry, odd_length) {
(Symmetry::Even, true) => {
h.extend(ak[1..].iter().rev().map(|&a| a * scale));
h.push(ak[0]);
h.extend(ak[1..].iter().map(|&a| a * scale));
}
(Symmetry::Even, false) => {
h.push(*ak.last().unwrap() * scale4);
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(2))
.rev()
.map(|(&b1, &b2)| scale4 * (b1 + b2)),
);
h.push(ak[0] * scale + ak[1] * scale4);
h.push(ak[0] * scale + ak[1] * scale4);
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(2))
.rev()
.map(|(&b1, &b2)| scale4 * (b1 + b2))
.rev(),
);
h.push(*ak.last().unwrap() * scale4);
}
(Symmetry::Odd, true) => {
h.push(*ak.last().unwrap() * scale4);
h.push(ak[ak.len() - 2] * scale4);
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(3))
.rev()
.map(|(&c1, &c2)| scale4 * (c1 - c2)),
);
h.push(ak[0] * scale - ak[2] * scale4);
h.push(T::zero());
h.push(-(ak[0] * scale - ak[2] * scale4));
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(3))
.rev()
.map(|(&c1, &c2)| -(scale4 * (c1 - c2)))
.rev(),
);
h.push(-(ak[ak.len() - 2] * scale4));
h.push(-(*ak.last().unwrap() * scale4));
}
(Symmetry::Odd, false) => {
h.push(*ak.last().unwrap() * scale4);
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(2))
.rev()
.map(|(&d1, &d2)| scale4 * (d1 - d2)),
);
h.push(ak[0] * scale - ak[1] * scale4);
h.push(-(ak[0] * scale - ak[1] * scale4));
h.extend(
ak.iter()
.skip(1)
.zip(ak.iter().skip(2))
.rev()
.map(|(&d1, &d2)| -(scale4 * (d1 - d2)))
.rev(),
);
h.push(-(*ak.last().unwrap() * scale4));
}
};
debug_assert!(h.len() == num_taps);
h
}