pub use microfft::Complex32;
use alloc::vec::Vec;
use core::convert::TryInto;
use core::mem;
use microfft::real;
macro_rules! real_fft_n {
($buffer:expr, $( $i:literal ),*) => {
match $buffer.len() {
$(
$i => {
let fixed_size_view = $buffer.as_mut_slice().try_into().unwrap();
paste::paste! (
real::[<rfft_$i>]
)(fixed_size_view)
}
)*
_ => { unimplemented!("should be one of the supported buffer lengths, but was {}", $buffer.len()) }
}
};
}
pub struct FftImpl;
impl FftImpl {
#[inline]
pub(crate) fn calc(samples: &[f32]) -> Vec<Complex32> {
assert_eq!(
samples.len() % 2,
0,
"buffer length must be a multiple of two!"
);
let mut vec_buffer = Vec::with_capacity(samples.len() + 2 );
assert_eq!(
vec_buffer.capacity() % 2,
0,
"vector capacity must be a multiple of two for safe casting!"
);
vec_buffer.extend_from_slice(samples);
let _fft_res: &mut [Complex32] = real_fft_n!(
&mut vec_buffer,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
2048,
4096,
8192,
16384,
32768
);
let mut buffer = {
let ptr = vec_buffer.as_mut_ptr().cast::<Complex32>();
let len = vec_buffer.len() / 2;
let capacity = vec_buffer.capacity() / 2;
let new_buffer_view = unsafe { Vec::from_raw_parts(ptr, len, capacity) };
mem::forget(vec_buffer);
new_buffer_view
};
let nyquist_fr_pos_val = buffer[0].im;
buffer[0].im = 0.0;
buffer.push(Complex32::new(nyquist_fr_pos_val, 0.0));
buffer
}
}
#[cfg(test)]
mod tests {
use crate::fft::FftImpl;
#[test]
fn test_memory_safety() {
let samples = [1.0, 2.0, 3.0, 4.0];
let fft = FftImpl::calc(&samples);
assert_eq!(fft.len(), 2 + 1);
}
}