From 31b83a1daf401e41a1c73484c0aec3016b795e3f Mon Sep 17 00:00:00 2001 From: ozpv <39195175+ozpv@users.noreply.github.com> Date: Sat, 16 May 2026 03:06:33 -0500 Subject: latency --- src/windowed_fft.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/windowed_fft.rs (limited to 'src/windowed_fft.rs') diff --git a/src/windowed_fft.rs b/src/windowed_fft.rs new file mode 100644 index 0000000..161d3f0 --- /dev/null +++ b/src/windowed_fft.rs @@ -0,0 +1,111 @@ +#![allow(clippy::must_use_candidate)] +#![allow(clippy::return_self_not_must_use)] + +use crate::window::{ + BlackmanHarrisWindow, HammingWindow, HannWindow, RectangularWindow, WindowFunction, +}; +use num_complex::Complex; +use realfft::{ComplexToReal, RealFftPlanner, RealToComplex}; +use std::sync::Arc; + +pub struct WindowedRealFft { + fft_size: usize, + planner: RealFftPlanner, + forward: Arc>, + inverse: Arc>, + window_function: Box, + original_length: usize, +} + +impl WindowedRealFft { + pub fn new(fft_size: usize) -> Self { + let mut planner = RealFftPlanner::new(); + let forward = planner.plan_fft_forward(fft_size); + let inverse = planner.plan_fft_inverse(fft_size); + + let window_function = Box::new(HannWindow::new(fft_size)); + + Self { + fft_size, + planner, + forward, + inverse, + window_function, + original_length: 0, + } + } + + pub fn fft_size(mut self, value: usize) -> Self { + self.fft_size = value; + + let forward = self.planner.plan_fft_forward(value); + let inverse = self.planner.plan_fft_inverse(value); + + self.forward = forward; + self.inverse = inverse; + + self + } + + pub fn original_length(&mut self, value: usize) { + self.original_length = value; + } + + pub fn forward(&mut self, data: impl Into>) -> Vec>> { + let mut data = data.into(); + + let Some(new_length) = data.len().checked_next_multiple_of(self.fft_size) else { + return vec![]; + }; + + self.original_length = data.len(); + + data.resize(new_length, 0.0); + + self.window_function + .apply(data) + .into_par_iter() + .map(|mut chunk| { + let mut output = self.forward.make_output_vec(); + + self.forward.process(&mut chunk, &mut output).unwrap(); + + output + }) + .collect::>>>() + } + + pub fn inverse(&mut self, data: Vec>>) -> Vec { + let data = data + .into_par_iter() + .map(|mut chunk| { + let mut real_output = self.inverse.make_output_vec(); + + self.inverse.process(&mut chunk, &mut real_output).unwrap(); + + let chunk_size_f32 = self.fft_size as f32; + + real_output + .into_iter() + .map(|sample| sample / chunk_size_f32) + .collect::>() + }) + .collect::>>(); + + let mut output = self.window_function.reverse(data); + + output.truncate(self.original_length); + + output + } + + pub fn i32_to_f32(item: Vec) -> Vec { + item.into_iter().map(f32::from).collect::>() + } + + pub fn f32_to_i32(item: Vec) -> Vec { + item.into_iter() + .map(|value| value as i32) + .collect::>() + } +} -- cgit v1.2.3