use std::{f32, sync::Arc};
use crate::dsp::complex::Complex;
use crate::dsp::fft::MAX_SIZE;
pub struct Fft {
scratch: Box<[Complex<f32>]>,
fft: Arc<dyn rustfft::Fft<f32>>,
}
impl Fft {
pub fn new(n: usize) -> Self {
assert!(n.is_power_of_two());
assert!(n <= MAX_SIZE);
let mut planner = rustfft::FftPlanner::<f32>::new();
let fft = planner.plan_fft_forward(n);
let scratch = vec![Default::default(); fft.get_inplace_scratch_len()].into_boxed_slice();
Self { scratch, fft }
}
pub fn size(&self) -> usize {
self.fft.len()
}
pub fn fft(&mut self, x: &[Complex<f32>], y: &mut [Complex<f32>]) {
assert_eq!(x.len(), y.len());
assert_eq!(x.len(), self.fft.len());
y.copy_from_slice(x);
self.fft.process_with_scratch(y, &mut self.scratch);
}
pub fn fft_inplace(&mut self, x: &mut [Complex<f32>]) {
assert_eq!(x.len(), x.len());
assert_eq!(x.len(), self.fft.len());
self.fft.process_with_scratch(x, &mut self.scratch);
}
}
pub struct Ifft {
scratch: Box<[Complex<f32>]>,
ifft: Arc<dyn rustfft::Fft<f32>>,
}
impl Ifft {
pub fn new(n: usize) -> Self {
assert!(n.is_power_of_two());
assert!(n <= MAX_SIZE);
let mut planner = rustfft::FftPlanner::<f32>::new();
let ifft = planner.plan_fft_inverse(n);
let scratch = vec![Default::default(); ifft.get_inplace_scratch_len()].into_boxed_slice();
Self { scratch, ifft }
}
pub fn size(&self) -> usize {
self.ifft.len()
}
pub fn ifft(&mut self, x: &[Complex<f32>], y: &mut [Complex<f32>]) {
assert_eq!(x.len(), y.len());
assert_eq!(x.len(), self.ifft.len());
y.copy_from_slice(x);
self.ifft.process_with_scratch(y, &mut self.scratch);
let c = 1.0 / y.len() as f32;
for y in y.iter_mut() {
*y *= c;
}
}
pub fn ifft_inplace(&mut self, x: &mut [Complex<f32>]) {
assert_eq!(x.len(), self.ifft.len());
self.ifft.process_with_scratch(x, &mut self.scratch);
let c = 1.0 / x.len() as f32;
for x in x.iter_mut() {
*x *= c;
}
}
}