use std::collections::VecDeque;
use std::sync::Arc;
use rustfft::{Fft, FftPlanner, num_complex::Complex};
#[derive(Clone)]
pub struct Convolver {
pub fft_size: usize,
ir_segments: Vec<Vec<Complex<f32>>>, previous_frame_q: VecDeque<Vec<Complex<f32>>>, pub previous_tail: Vec<f32>, fft_processor: Arc<dyn Fft<f32>>,
ifft_processor: Arc<dyn Fft<f32>>, }
impl Convolver {
pub fn new(ir_signal: &[f32], fft_size: usize) -> Self {
let mut planner = FftPlanner::<f32>::new();
let fft_processor = planner.plan_fft_forward(fft_size);
let ifft_processor = planner.plan_fft_inverse(fft_size);
let ir_segments = segment_buffer(ir_signal, fft_size, &fft_processor);
let segment_count = ir_segments.len();
Self {
fft_size,
ir_segments,
fft_processor,
ifft_processor,
previous_frame_q: init_previous_frame_q(segment_count, fft_size),
previous_tail: init_previous_tail(fft_size/2),
}
}
pub fn process(&mut self, input_buffer: &[f32]) -> Vec<f32> {
let io_len = input_buffer.len();
let input_segments = segment_buffer(input_buffer, self.fft_size, &self.fft_processor);
let mut output_segments: Vec<Vec<Complex<f32>>> = Vec::new();
for segment in input_segments {
self.previous_frame_q.push_front(segment);
self.previous_frame_q.pop_back();
output_segments.push(self.convolve_frame());
}
let mut time_domain: Vec<f32> = Vec::new();
for mut segment in output_segments {
self.ifft_processor.process(&mut segment);
for sample in segment {
time_domain.push(sample.re);
}
}
for (i, sample) in self.previous_tail.iter().enumerate() {
match time_domain.get_mut(i) {
Some(out_sample) => *out_sample += sample,
None => break
}
}
self.previous_tail = time_domain[io_len..time_domain.len()].to_vec();
return time_domain[0..io_len].to_vec();
}
fn convolve_frame(&mut self) -> Vec<Complex<f32>> {
let mut convolved: Vec<Complex<f32>> = Vec::new();
for _ in 0..self.fft_size {
convolved.push(Complex {re: 0. , im: 0. });
}
for i in 0..self.ir_segments.len() {
add_frames(&mut convolved, mult_frames(
&self.previous_frame_q[i],
&self.ir_segments[i]
));
}
convolved
}
}
pub fn add_frames(f1: &mut [Complex<f32>], f2: Vec<Complex<f32>>) {
for (mut sample1, sample2) in f1.iter_mut().zip(f2) {
sample1.re = sample1.re + sample2.re;
sample1.im = sample1.im + sample2.im;
}
}
pub fn mult_frames(f1: &[Complex<f32>], f2: &[Complex<f32>]) -> Vec<Complex<f32>> {
let mut out: Vec<Complex<f32>> = Vec::new();
for (sample1, sample2) in f1.iter().zip(f2) {
out.push(Complex {
re: (sample1.re * sample2.re) - (sample1.im * sample2.im),
im: (sample1.im * sample2.re) - (sample1.re * sample2.im)
});
}
out
}
pub fn init_previous_tail(size: usize) -> Vec<f32> {
let mut tail = Vec::new();
for _ in 0..size {
tail.push(0.);
}
tail
}
pub fn segment_buffer(buffer: &[f32], fft_size: usize, fft_processor: &Arc<dyn Fft<f32>>) -> Vec<Vec<Complex<f32>>> {
let mut segments = Vec::new();
let segment_size = fft_size / 2;
let mut index = 0;
while index < buffer.len() {
let mut new_segment: Vec<Complex<f32>> = Vec::new();
for i in index..index+segment_size {
match buffer.get(i) {
Some(sample) => new_segment.push(Complex { re: *sample, im: 0. }),
None => continue
}
}
while new_segment.len() < fft_size {
new_segment.push(Complex { re: 0., im: 0. });
}
fft_processor.process(&mut new_segment);
segments.push(new_segment);
index += segment_size;
}
segments
}
pub fn init_previous_frame_q(segment_count: usize, fft_size: usize) -> VecDeque<Vec<Complex<f32>>> {
let mut q = VecDeque::new();
for _ in 0..segment_count {
let mut empty = Vec::new();
for _ in 0..fft_size {
empty.push(Complex{ re: 0., im: 0. });
}
q.push_back(empty);
}
q
}