use crate::sinc::make_sincs;
use crate::windows::WindowFunction;
use num_complex::Complex;
use num_integer as integer;
use num_traits::Zero;
use std::sync::Arc;
use crate::error::{ResampleError, ResampleResult};
use crate::{Resampler, Sample};
use realfft::{ComplexToReal, RealFftPlanner, RealToComplex};
struct FftResampler<T> {
fft_size_in: usize,
fft_size_out: usize,
filter_f: Vec<Complex<T>>,
fft: Arc<dyn RealToComplex<T>>,
ifft: Arc<dyn ComplexToReal<T>>,
scratch_fw: Vec<Complex<T>>,
scratch_inv: Vec<Complex<T>>,
input_buf: Vec<T>,
input_f: Vec<Complex<T>>,
output_f: Vec<Complex<T>>,
output_buf: Vec<T>,
}
pub struct FftFixedIn<T> {
nbr_channels: usize,
chunk_size_in: usize,
fft_size_in: usize,
fft_size_out: usize,
overlaps: Vec<Vec<T>>,
input_buffers: Vec<Vec<T>>,
saved_frames: usize,
resampler: FftResampler<T>,
}
pub struct FftFixedOut<T> {
nbr_channels: usize,
chunk_size_out: usize,
fft_size_in: usize,
fft_size_out: usize,
overlaps: Vec<Vec<T>>,
output_buffers: Vec<Vec<T>>,
saved_frames: usize,
frames_needed: usize,
resampler: FftResampler<T>,
}
pub struct FftFixedInOut<T> {
nbr_channels: usize,
chunk_size_in: usize,
chunk_size_out: usize,
fft_size_in: usize,
overlaps: Vec<Vec<T>>,
resampler: FftResampler<T>,
}
impl<T> FftResampler<T>
where
T: Sample,
{
pub fn new(fft_size_in: usize, fft_size_out: usize) -> Self {
let cutoff = if fft_size_in > fft_size_out {
0.4f32.powf(16.0 / fft_size_in as f32) * fft_size_out as f32 / fft_size_in as f32
} else {
0.4f32.powf(16.0 / fft_size_in as f32)
};
debug!(
"Create new FftResampler, fft_size_in: {}, fft_size_out: {}, cutoff: {}",
fft_size_in, fft_size_out, cutoff
);
let sinc = make_sincs::<T>(fft_size_in, 1, cutoff, WindowFunction::BlackmanHarris2);
let mut filter_t: Vec<T> = vec![T::zero(); 2 * fft_size_in];
let mut filter_f: Vec<Complex<T>> = vec![Complex::zero(); fft_size_in + 1];
for (n, f) in filter_t.iter_mut().enumerate().take(fft_size_in) {
*f = sinc[0][n] / T::coerce(2 * fft_size_in);
}
let input_f: Vec<Complex<T>> = vec![Complex::zero(); fft_size_in + 1];
let input_buf: Vec<T> = vec![T::zero(); 2 * fft_size_in];
let output_f: Vec<Complex<T>> = vec![Complex::zero(); fft_size_out + 1];
let output_buf: Vec<T> = vec![T::zero(); 2 * fft_size_out];
let mut planner = RealFftPlanner::<T>::new();
let fft = planner.plan_fft_forward(2 * fft_size_in);
let ifft = planner.plan_fft_inverse(2 * fft_size_out);
fft.process(&mut filter_t, &mut filter_f).unwrap();
let scratch_fw = fft.make_scratch_vec();
let scratch_inv = ifft.make_scratch_vec();
FftResampler {
fft_size_in,
fft_size_out,
filter_f,
fft,
ifft,
scratch_fw,
scratch_inv,
input_buf,
input_f,
output_f,
output_buf,
}
}
fn resample_unit(&mut self, wave_in: &[T], wave_out: &mut [T], overlap: &mut [T]) {
self.input_buf[0..self.fft_size_in].copy_from_slice(wave_in);
for item in self
.input_buf
.iter_mut()
.skip(self.fft_size_in)
.take(self.fft_size_in)
{
*item = T::zero();
}
self.fft
.process_with_scratch(&mut self.input_buf, &mut self.input_f, &mut self.scratch_fw)
.unwrap();
self.input_f
.iter_mut()
.take(self.fft_size_in + 1)
.zip(self.filter_f.iter())
.for_each(|(spec, filt)| *spec *= filt);
let new_len = if self.fft_size_in < self.fft_size_out {
self.fft_size_in + 1
} else {
self.fft_size_out
};
self.output_f[0..new_len].copy_from_slice(&self.input_f[0..new_len]);
for val in self.output_f[new_len..].iter_mut() {
*val = Complex::zero();
}
self.ifft
.process_with_scratch(
&mut self.output_f,
&mut self.output_buf,
&mut self.scratch_inv,
)
.unwrap();
for (n, item) in wave_out.iter_mut().enumerate().take(self.fft_size_out) {
*item = self.output_buf[n] + overlap[n];
}
overlap.copy_from_slice(&self.output_buf[self.fft_size_out..]);
}
}
impl<T> FftFixedInOut<T>
where
T: Sample,
{
pub fn new(fs_in: usize, fs_out: usize, chunk_size_in: usize, nbr_channels: usize) -> Self {
debug!(
"Create new FftFixedInOut, fs_in: {}, fs_out: {} chunk_size_in: {}, channels: {}",
fs_in, fs_out, chunk_size_in, nbr_channels
);
let gcd = integer::gcd(fs_in, fs_out);
let min_chunk_out = fs_out / gcd;
let wanted = chunk_size_in;
let fft_chunks = (wanted as f32 / min_chunk_out as f32).ceil() as usize;
let fft_size_out = fft_chunks * fs_out / gcd;
let fft_size_in = fft_chunks * fs_in / gcd;
let resampler = FftResampler::<T>::new(fft_size_in, fft_size_out);
let overlaps: Vec<Vec<T>> = vec![vec![T::zero(); fft_size_out]; nbr_channels];
FftFixedInOut {
nbr_channels,
chunk_size_in: fft_size_in,
chunk_size_out: fft_size_out,
fft_size_in,
overlaps,
resampler,
}
}
}
impl<T> Resampler<T> for FftFixedInOut<T>
where
T: Sample,
{
fn nbr_frames_needed(&self) -> usize {
self.fft_size_in
}
fn process(&mut self, wave_in: &[Vec<T>]) -> ResampleResult<Vec<Vec<T>>> {
if wave_in.len() != self.nbr_channels {
return Err(ResampleError::WrongNumberOfChannels {
expected: self.nbr_channels,
actual: wave_in.len(),
});
}
let mut used_channels = Vec::new();
for (chan, wave) in wave_in.iter().enumerate() {
if !wave.is_empty() {
used_channels.push(chan);
if wave.len() != self.chunk_size_in {
return Err(ResampleError::WrongNumberOfFrames {
channel: chan,
expected: self.chunk_size_in,
actual: wave.len(),
});
}
}
}
let mut wave_out = vec![Vec::new(); self.nbr_channels];
for chan in used_channels.iter() {
wave_out[*chan] = vec![T::zero(); self.chunk_size_out];
}
for n in used_channels.iter() {
self.resampler
.resample_unit(&wave_in[*n], &mut wave_out[*n], &mut self.overlaps[*n])
}
Ok(wave_out)
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
}
impl<T> FftFixedOut<T>
where
T: Sample,
{
pub fn new(
fs_in: usize,
fs_out: usize,
chunk_size_out: usize,
sub_chunks: usize,
nbr_channels: usize,
) -> Self {
let gcd = integer::gcd(fs_in, fs_out);
let min_chunk_out = fs_out / gcd;
let wanted_subsize = chunk_size_out / sub_chunks;
let fft_chunks = (wanted_subsize as f32 / min_chunk_out as f32).ceil() as usize;
let fft_size_out = fft_chunks * fs_out / gcd;
let fft_size_in = fft_chunks * fs_in / gcd;
let resampler = FftResampler::<T>::new(fft_size_in, fft_size_out);
debug!(
"Create new FftFixedOut, fs_in: {}, fs_out: {} chunk_size_in: {}, channels: {}, fft_size_in: {}, fft_size_out: {}",
fs_in, fs_out, chunk_size_out, nbr_channels, fft_size_in, fft_size_out
);
let overlaps: Vec<Vec<T>> = vec![vec![T::zero(); fft_size_out]; nbr_channels];
let output_buffers: Vec<Vec<T>> =
vec![vec![T::zero(); chunk_size_out + fft_size_out]; nbr_channels];
let saved_frames = 0;
let chunks_needed = (chunk_size_out as f32 / fft_size_out as f32).ceil() as usize;
let frames_needed = chunks_needed * fft_size_in;
FftFixedOut {
nbr_channels,
chunk_size_out,
fft_size_in,
fft_size_out,
overlaps,
output_buffers,
saved_frames,
frames_needed,
resampler,
}
}
}
impl<T> Resampler<T> for FftFixedOut<T>
where
T: Sample,
{
fn nbr_frames_needed(&self) -> usize {
self.frames_needed
}
fn process(&mut self, wave_in: &[Vec<T>]) -> ResampleResult<Vec<Vec<T>>> {
if wave_in.len() != self.nbr_channels {
return Err(ResampleError::WrongNumberOfChannels {
expected: self.nbr_channels,
actual: wave_in.len(),
});
}
let mut used_channels = Vec::new();
for (chan, wave) in wave_in.iter().enumerate() {
if !wave.is_empty() {
used_channels.push(chan);
if wave.len() != self.frames_needed {
return Err(ResampleError::WrongNumberOfFrames {
channel: chan,
expected: self.frames_needed,
actual: wave.len(),
});
}
}
}
let mut wave_out = vec![Vec::new(); self.nbr_channels];
for chan in used_channels.iter() {
wave_out[*chan] = self.output_buffers[*chan].clone();
}
for n in used_channels.iter() {
for (in_chunk, out_chunk) in wave_in[*n]
.chunks(self.fft_size_in)
.zip(wave_out[*n][self.saved_frames..].chunks_mut(self.fft_size_out))
{
self.resampler
.resample_unit(in_chunk, out_chunk, &mut self.overlaps[*n]);
}
}
let processed_frames =
self.saved_frames + self.fft_size_out * (self.frames_needed / self.fft_size_in);
self.saved_frames = processed_frames - self.chunk_size_out;
if processed_frames > self.chunk_size_out {
for n in used_channels.iter() {
self.output_buffers[*n][0..self.saved_frames].copy_from_slice(
&wave_out[*n][self.chunk_size_out..(self.chunk_size_out + self.saved_frames)],
);
}
}
for n in used_channels.iter() {
wave_out[*n].truncate(self.chunk_size_out);
}
let frames_needed_out = if self.chunk_size_out > self.saved_frames {
self.chunk_size_out - self.saved_frames
} else {
0
};
let chunks_needed = (frames_needed_out as f32 / self.fft_size_out as f32).ceil() as usize;
self.frames_needed = chunks_needed * self.fft_size_in;
Ok(wave_out)
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
}
impl<T> FftFixedIn<T>
where
T: Sample,
{
pub fn new(
fs_in: usize,
fs_out: usize,
chunk_size_in: usize,
sub_chunks: usize,
nbr_channels: usize,
) -> Self {
let gcd = integer::gcd(fs_in, fs_out);
let min_chunk_in = fs_in / gcd;
let wanted_subsize = chunk_size_in / sub_chunks;
let fft_chunks = (wanted_subsize as f32 / min_chunk_in as f32).ceil() as usize;
let fft_size_out = fft_chunks * fs_out / gcd;
let fft_size_in = fft_chunks * fs_in / gcd;
let resampler = FftResampler::<T>::new(fft_size_in, fft_size_out);
debug!(
"Create new FftFixedOut, fs_in: {}, fs_out: {} chunk_size_in: {}, channels: {}, fft_size_in: {}, fft_size_out: {}",
fs_in, fs_out, chunk_size_in, nbr_channels, fft_size_in, fft_size_out
);
let overlaps: Vec<Vec<T>> = vec![vec![T::zero(); fft_size_out]; nbr_channels];
let input_buffers: Vec<Vec<T>> =
vec![vec![T::zero(); chunk_size_in + fft_size_out]; nbr_channels];
let saved_frames = 0;
FftFixedIn {
nbr_channels,
chunk_size_in,
fft_size_in,
fft_size_out,
overlaps,
input_buffers,
saved_frames,
resampler,
}
}
}
impl<T> Resampler<T> for FftFixedIn<T>
where
T: Sample,
{
fn nbr_frames_needed(&self) -> usize {
self.chunk_size_in
}
fn process(&mut self, wave_in: &[Vec<T>]) -> ResampleResult<Vec<Vec<T>>> {
if wave_in.len() != self.nbr_channels {
return Err(ResampleError::WrongNumberOfChannels {
expected: self.nbr_channels,
actual: wave_in.len(),
});
}
let mut used_channels = Vec::new();
for (chan, wave) in wave_in.iter().enumerate() {
if !wave.is_empty() {
used_channels.push(chan);
if wave.len() != self.chunk_size_in {
return Err(ResampleError::WrongNumberOfFrames {
channel: chan,
expected: self.chunk_size_in,
actual: wave.len(),
});
}
}
}
let mut input_temp = vec![Vec::new(); self.nbr_channels];
for chan in used_channels.iter() {
input_temp[*chan] = vec![T::zero(); self.saved_frames + self.chunk_size_in];
}
for n in used_channels.iter() {
for (input, buffer) in self.input_buffers[*n]
.iter()
.take(self.saved_frames)
.zip(input_temp[*n].iter_mut())
{
*buffer = *input;
}
}
for n in used_channels.iter() {
for (input, buffer) in wave_in[*n].iter().zip(
input_temp[*n]
.iter_mut()
.skip(self.saved_frames)
.take(self.chunk_size_in),
) {
*buffer = *input;
}
}
self.saved_frames += self.chunk_size_in;
let nbr_chunks_ready =
(self.saved_frames as f32 / self.fft_size_in as f32).floor() as usize;
let mut wave_out = vec![Vec::new(); self.nbr_channels];
for chan in used_channels.iter() {
wave_out[*chan] = vec![T::zero(); nbr_chunks_ready * self.fft_size_out];
}
for n in used_channels.iter() {
for (in_chunk, out_chunk) in input_temp[*n]
.chunks(self.fft_size_in)
.take(nbr_chunks_ready)
.zip(wave_out[*n].chunks_mut(self.fft_size_out))
{
self.resampler
.resample_unit(in_chunk, out_chunk, &mut self.overlaps[*n]);
}
}
let frames_in_used = nbr_chunks_ready * self.fft_size_in;
let extra = self.saved_frames - frames_in_used;
if self.saved_frames > frames_in_used {
for n in used_channels.iter() {
for (input, buffer) in input_temp[*n]
.iter()
.skip(frames_in_used)
.take(extra)
.zip(self.input_buffers[*n].iter_mut())
{
*buffer = *input;
}
}
}
self.saved_frames = extra;
Ok(wave_out)
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> ResampleResult<()> {
Err(ResampleError::SyncNotAdjustable)
}
}
#[cfg(test)]
mod tests {
use crate::synchro::{FftFixedIn, FftFixedInOut, FftFixedOut, FftResampler};
use crate::Resampler;
#[test]
fn resample_unit() {
let mut resampler = FftResampler::<f64>::new(147, 1000);
let mut wave_in = vec![0.0; 147];
wave_in[0] = 0.3;
wave_in[1] = 0.7;
wave_in[2] = 1.0;
wave_in[3] = 1.0;
wave_in[4] = 0.7;
wave_in[5] = 0.3;
let mut wave_out = vec![0.0; 1000];
let mut overlap = vec![0.0; 1000];
resampler.resample_unit(&wave_in, &mut wave_out, &mut overlap);
let vecsum = wave_out.iter().sum::<f64>();
let maxval = wave_out.iter().cloned().fold(0. / 0., f64::max);
assert!((vecsum - 4.0 * 1000.0 / 147.0).abs() < 1.0e-6);
assert!((maxval - 1.0).abs() < 0.1);
}
#[test]
fn make_resampler_fio() {
let mut resampler = FftFixedInOut::<f64>::new(44100, 48000, 1024, 2);
let frames = resampler.nbr_frames_needed();
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 1120);
}
#[test]
fn make_resampler_fio_skipped() {
let mut resampler = FftFixedInOut::<f64>::new(44100, 48000, 1024, 2);
let frames = resampler.nbr_frames_needed();
let waves = vec![vec![0.0f64; frames], Vec::new()];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 1120);
assert!(out[1].is_empty());
}
#[test]
fn make_resampler_fo() {
let mut resampler = FftFixedOut::<f64>::new(44100, 192000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 294);
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 1024);
}
#[test]
fn make_resampler_fo_skipped() {
let mut resampler = FftFixedOut::<f64>::new(44100, 192000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 294);
let waves = vec![vec![0.0f64; frames], Vec::new()];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 1024);
assert!(out[1].is_empty());
}
#[test]
fn make_resampler_fo_empty() {
let mut resampler = FftFixedOut::<f64>::new(44100, 192000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 294);
let waves = vec![Vec::new(); 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert!(out[0].is_empty());
assert!(out[1].is_empty());
}
#[test]
fn make_resampler_fi() {
let mut resampler = FftFixedIn::<f64>::new(44100, 48000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 1024);
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 640);
}
#[test]
fn make_resampler_fi_downsample() {
let mut resampler = FftFixedIn::<f64>::new(48000, 16000, 1200, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 1200);
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 400);
}
#[test]
fn make_resampler_fi_skipped() {
let mut resampler = FftFixedIn::<f64>::new(44100, 48000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 1024);
let waves = vec![vec![0.0f64; frames], Vec::new()];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 640);
assert!(out[1].is_empty());
}
#[test]
fn make_resampler_fi_empty() {
let mut resampler = FftFixedIn::<f64>::new(44100, 48000, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 1024);
let waves = vec![Vec::new(); 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert!(out[0].is_empty());
assert!(out[1].is_empty());
}
#[test]
fn make_resampler_fio_unusualratio() {
let mut resampler = FftFixedInOut::<f64>::new(44100, 44110, 1024, 2);
let frames = resampler.nbr_frames_needed();
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 4411);
}
#[test]
fn make_resampler_fo_unusualratio() {
let mut resampler = FftFixedOut::<f64>::new(44100, 44110, 1024, 2, 2);
let frames = resampler.nbr_frames_needed();
assert_eq!(frames, 4410);
let waves = vec![vec![0.0f64; frames]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert_eq!(out[0].len(), 1024);
}
}