use super::complex::Complex;
use std::f32::consts::PI;
pub struct Fft;
impl Fft {
pub fn forward(buffer: &mut [Complex]) {
let n = buffer.len();
assert!(
n > 0 && (n & (n - 1)) == 0,
"FFT size must be a power of two"
);
Self::bit_reverse_permutation(buffer);
let mut len = 2;
while len <= n {
let half_len = len / 2;
let angle_step = -2.0 * PI / (len as f32);
let w_step = Complex::from_polar(1.0, angle_step);
let mut i = 0;
while i < n {
let mut w = Complex::new(1.0, 0.0);
for j in 0..half_len {
let u = buffer[i + j];
let v = buffer[i + j + half_len] * w;
buffer[i + j] = u + v;
buffer[i + j + half_len] = u - v;
w = w * w_step;
}
i += len;
}
len *= 2;
}
}
pub fn inverse(buffer: &mut [Complex]) {
let n = buffer.len();
assert!(
n > 0 && (n & (n - 1)) == 0,
"IFFT size must be a power of two"
);
for item in buffer.iter_mut() {
*item = item.conjugate();
}
Self::forward(buffer);
let inv_n = 1.0 / (n as f32);
for item in buffer.iter_mut() {
*item = item.conjugate() * inv_n;
}
}
pub fn compute_magnitude_spectrum(buffer: &[Complex]) -> Vec<f32> {
if buffer.is_empty() {
return Vec::new();
}
let half = buffer.len() / 2 + 1; let mut mags = Vec::with_capacity(half);
for item in &buffer[0..half] {
mags.push(item.magnitude());
}
mags
}
pub fn find_dominant_frequency(buffer: &[Complex], sample_rate: f32) -> (f32, f32) {
if buffer.is_empty() {
return (0.0, 0.0);
}
let half = buffer.len() / 2 + 1;
let mut max_mag = 0.0_f32;
let mut max_bin = 0;
for (i, item) in buffer[0..half].iter().enumerate() {
let mag = item.magnitude();
if mag > max_mag {
max_mag = mag;
max_bin = i;
}
}
let freq_hz = (max_bin as f32) * sample_rate / (buffer.len() as f32);
(freq_hz, max_mag)
}
fn bit_reverse_permutation(buffer: &mut [Complex]) {
let n = buffer.len();
let mut j = 0;
for i in 0..n {
if i < j {
buffer.swap(i, j);
}
let mut bit = n >> 1;
while j & bit != 0 {
j ^= bit;
bit >>= 1;
}
j ^= bit;
}
}
}