some basic fft code based on rustfft crate

This commit is contained in:
Weird Constructor 2021-07-12 06:23:45 +02:00
parent 5a3eb18f5c
commit 4e2cb0dca4
4 changed files with 72 additions and 1 deletions

View file

@ -24,6 +24,7 @@ hound = "3.4.0"
microfft = "0.3.1" microfft = "0.3.1"
num-complex = "0.2" num-complex = "0.2"
jack = "0.6.6" jack = "0.6.6"
rustfft = "6.0.0"
[lib] [lib]
path = "src/lib.rs" path = "src/lib.rs"

View file

@ -143,5 +143,7 @@ impl DspNode for SFilter {
}, },
_ => {}, _ => {},
} }
ctx_vals[0].set(out.read(ctx.nframes() - 1));
} }
} }

View file

@ -422,6 +422,18 @@ pub fn run_and_get_fft4096(
fft_thres_at_ms(&mut out_l[..], FFT::F4096, thres, offs_ms) fft_thres_at_ms(&mut out_l[..], FFT::F4096, thres, offs_ms)
} }
#[allow(unused)]
pub fn run_and_get_fft4096_2(
node_exec: &mut hexodsp::nodes::NodeExecutor,
thres: u32) -> Vec<(u16, u32)>
{
let min_samples_for_fft = 4096.0;
let min_len_samples = 2.0 * min_samples_for_fft;
let run_len_s = min_len_samples / SAMPLE_RATE;
let (mut out_l, _out_r) = run_no_input(node_exec, run_len_s);
fft_16k(&mut out_l[..], 4096, thres)
}
#[allow(unused)] #[allow(unused)]
pub fn calc_exp_avg_buckets4096(fft: &[(u16, u32)]) -> Vec<(u16, u32)> { pub fn calc_exp_avg_buckets4096(fft: &[(u16, u32)]) -> Vec<(u16, u32)> {
let mut avg = vec![]; let mut avg = vec![];
@ -592,3 +604,49 @@ pub fn fft_thres_at_ms(buf: &mut [f32], size: FFT, amp_thres: u32, ms_idx: f32)
res res
} }
pub fn fft_16k(buf: &mut [f32], len: usize, amp_thres: u32) -> Vec<(u16, u32)> {
let mut res = vec![];
if len > buf.len() {
return res;
}
// Hann window:
for (i, s) in buf[0..len].iter_mut().enumerate() {
let w =
0.5
* (1.0
- ((2.0 * std::f32::consts::PI * i as f32)
/ (len as f32 - 1.0))
.cos());
*s *= w;
}
use rustfft::{FftPlanner, num_complex::Complex};
let mut complex_buf =
buf.iter()
.map(|s| Complex { re: *s, im: 0.0 })
.collect::<Vec<Complex<f32>>>();
let mut p = FftPlanner::<f32>::new();
let fft = p.plan_fft_forward(len);
fft.process(&mut complex_buf[0..len]);
let amplitudes: Vec<_> =
complex_buf[0..len].iter().map(|c| c.norm() as u32).collect();
println!("fft: {:?}", &complex_buf[0..len]);
for (i, amp) in amplitudes.iter().enumerate() {
if *amp >= amp_thres {
let freq = (i as f32 * SAMPLE_RATE) / len as f32;
println!("{:6.0} {}", freq, *amp);
res.push((freq.round() as u16, *amp));
}
}
res
}

View file

@ -2,7 +2,7 @@ mod common;
use common::*; use common::*;
fn setup_sfilter_matrix() -> (Matrix, NodeExecutor) { fn setup_sfilter_matrix() -> (Matrix, NodeExecutor) {
let (node_conf, mut node_exec) = new_node_engine(); let (node_conf, node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3); let mut matrix = Matrix::new(node_conf, 3, 3);
let noise = NodeId::Noise(0); let noise = NodeId::Noise(0);
@ -50,6 +50,16 @@ fn check_node_sfilter_lowpass() {
(1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0), (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0),
]); ]);
// let v = run_and_get_fft4096_2(&mut node_exec, 1);
// assert_eq!(
// avg_fft_freqs(4.0, &[
// 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000,
// ], &v[..]), vec![
// (0, 16), (100, 24), (250, 16), (500, 12), (750, 12), (1000, 12),
// (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0),
// ]);
// assert!(false);
// Low Pass @ 4000Hz // Low Pass @ 4000Hz
let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 4000.0, 0.0); let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 4000.0, 0.0);
assert_eq!( assert_eq!(