Support overlapping FFT blocks
Now an arbitrary number of samples can be read and appended to the FFT block. Old samples will be dropped such that only BLOCK_LEN samples are in the memory buffer. Currently one half of the FFT block is replaced per update.
This commit is contained in:
parent
ff018a98e1
commit
942f66f7df
|
@ -1,3 +1,6 @@
|
||||||
// definitions for the FFT
|
// definitions for the FFT
|
||||||
pub const BLOCK_LEN: usize = 512;
|
pub const BLOCK_LEN: usize = 512;
|
||||||
pub const SAMP_RATE: f32 = 48000.0;
|
pub const SAMP_RATE: f32 = 48000.0;
|
||||||
|
|
||||||
|
// samples read from stdin per update
|
||||||
|
pub const SAMPLES_PER_UPDATE: usize = BLOCK_LEN/2;
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -1,6 +1,7 @@
|
||||||
// vim: noet
|
// vim: noet
|
||||||
|
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use byteorder::{NativeEndian, ReadBytesExt};
|
use byteorder::{NativeEndian, ReadBytesExt};
|
||||||
|
|
||||||
|
@ -34,17 +35,24 @@ fn main()
|
||||||
println!("Done! Starting main loop…");
|
println!("Done! Starting main loop…");
|
||||||
|
|
||||||
// array for samples directly read from stream
|
// array for samples directly read from stream
|
||||||
let mut samples = [0i16; config::BLOCK_LEN];
|
let mut samples: VecDeque<i16> = VecDeque::with_capacity(config::BLOCK_LEN);
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
loop {
|
loop {
|
||||||
|
|
||||||
// read a block of samples and exit gracefully on EOF
|
// read a block of samples and exit gracefully on EOF
|
||||||
for sample in samples.iter_mut() {
|
for _i in 0 .. config::SAMPLES_PER_UPDATE {
|
||||||
|
// avoid increasing the size of the deque
|
||||||
|
if samples.len() == config::BLOCK_LEN {
|
||||||
|
samples.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// read a sample from the input
|
||||||
let res = stdin.read_i16::<NativeEndian>();
|
let res = stdin.read_i16::<NativeEndian>();
|
||||||
|
|
||||||
|
// if everything is ok, append it to the samples deque
|
||||||
match res {
|
match res {
|
||||||
Ok(s) => *sample = s,
|
Ok(s) => samples.push_back(s),
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
|
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
|
||||||
println!("End of stream. Exiting.");
|
println!("End of stream. Exiting.");
|
||||||
exit(0);
|
exit(0);
|
||||||
|
@ -53,7 +61,13 @@ fn main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sigproc.import_i16_mono(&samples).unwrap();
|
// only run calculations if the deque has been filled enough
|
||||||
|
if samples.len() < config::BLOCK_LEN {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sigproc.import_i16_mono_from_iter(samples.iter()).unwrap();
|
||||||
sigproc.update_fft().unwrap();
|
sigproc.update_fft().unwrap();
|
||||||
|
|
||||||
let energy_bass = sigproc.get_energy_in_band( 0.0, 400.0);
|
let energy_bass = sigproc.get_energy_in_band( 0.0, 400.0);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// vim: noet
|
// vim: noet
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
|
||||||
use fftw::array::AlignedVec;
|
use fftw::array::AlignedVec;
|
||||||
use fftw::plan::*;
|
use fftw::plan::*;
|
||||||
use fftw::types::*;
|
use fftw::types::*;
|
||||||
|
@ -88,6 +90,20 @@ impl SignalProcessing
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_i16_mono_from_iter<'a>(&mut self, mut iter: impl std::iter::Iterator<Item=&'a i16>) -> std::result::Result<(), &str>
|
||||||
|
{
|
||||||
|
for fft_samp in self.fft_input.iter_mut() {
|
||||||
|
match iter.next() {
|
||||||
|
Some(sample) => *fft_samp = *sample as f32,
|
||||||
|
None => return Err("Too few samples in input.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.apply_window();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_fft(&mut self) -> fftw::error::Result<()>
|
pub fn update_fft(&mut self) -> fftw::error::Result<()>
|
||||||
{
|
{
|
||||||
self.fft_plan.r2c(&mut self.fft_input, &mut self.fft_output)?;
|
self.fft_plan.r2c(&mut self.fft_input, &mut self.fft_output)?;
|
||||||
|
|
Loading…
Reference in a new issue