use crate::sinc::make_sincs;
use crate::windows::WindowFunction;
use num_complex::Complex;
use num_integer as integer;
use num_traits::Zero;
use std::error;
type Res<T> = Result<T, Box<dyn error::Error>>;
use crate::Resampler;
use crate::ResamplerError;
use realfft::{ComplexToReal, RealToComplex};
struct FftResampler<T> {
fft_size_in: usize,
fft_size_out: usize,
filter_f: Vec<Complex<T>>,
fft: RealToComplex<T>,
ifft: ComplexToReal<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>,
}
macro_rules! impl_resampler {
($ft:ty, $rt:ty) => {
impl $rt {
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::<$ft>(fft_size_in, 1, cutoff, WindowFunction::BlackmanHarris2);
let mut filter_t: Vec<$ft> = vec![0.0; 2 * fft_size_in];
let mut filter_f: Vec<Complex<$ft>> = vec![Complex::zero(); fft_size_in + 1];
for n in 0..fft_size_in {
filter_t[n] = sinc[0][n] / (fft_size_in as $ft);
}
let input_f: Vec<Complex<$ft>> = vec![Complex::zero(); fft_size_in + 1];
let input_buf: Vec<$ft> = vec![0.0; 2 * fft_size_in];
let output_f: Vec<Complex<$ft>> = vec![Complex::zero(); fft_size_out + 1];
let output_buf: Vec<$ft> = vec![0.0; 2 * fft_size_out];
let mut fft = RealToComplex::<$ft>::new(2 * fft_size_in).unwrap();
let ifft = ComplexToReal::<$ft>::new(2 * fft_size_out).unwrap();
fft.process(&mut filter_t, &mut filter_f).unwrap();
FftResampler {
fft_size_in,
fft_size_out,
filter_f,
fft,
ifft,
input_buf,
input_f,
output_f,
output_buf,
}
}
fn resample_unit(
&mut self,
wave_in: &[$ft],
wave_out: &mut [$ft],
overlap: &mut [$ft],
) {
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 = 0.0;
}
self.fft
.process(&mut self.input_buf, &mut self.input_f)
.unwrap();
self.input_f
.iter_mut()
.take(self.fft_size_in)
.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
} else {
self.fft_size_out
};
self.output_f[0..new_len].copy_from_slice(&self.input_f[0..new_len]);
self.output_f[self.fft_size_out] = self.input_f[self.fft_size_in];
self.ifft
.process(&self.output_f, &mut self.output_buf)
.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_resampler!(f32, FftResampler<f32>);
impl_resampler!(f64, FftResampler<f64>);
macro_rules! impl_fixedinout {
($ft:ty) => {
impl FftFixedInOut<$ft> {
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::<$ft>::new(fft_size_in, fft_size_out);
let overlaps: Vec<Vec<$ft>> = vec![vec![0.0; 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_fixedinout!(f64);
impl_fixedinout!(f32);
macro_rules! resampler_FftFixedinout {
($t:ty) => {
impl Resampler<$t> for FftFixedInOut<$t> {
fn nbr_frames_needed(&self) -> usize {
self.fft_size_in
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn process(&mut self, wave_in: &[Vec<$t>]) -> Res<Vec<Vec<$t>>> {
if wave_in.len() != self.nbr_channels {
return Err(Box::new(ResamplerError::new(
"Wrong number of channels in input",
)));
}
if wave_in[0].len() != self.chunk_size_in {
return Err(Box::new(ResamplerError::new(
format!(
"Wrong number of frames in input, expected {}, got {}",
self.chunk_size_in,
wave_in[0].len()
)
.as_str(),
)));
}
let mut wave_out = vec![vec![0.0 as $t; self.chunk_size_out]; self.nbr_channels];
for n in 0..self.nbr_channels {
self.resampler.resample_unit(
&wave_in[n],
&mut wave_out[n],
&mut self.overlaps[n],
)
}
Ok(wave_out)
}
}
};
}
resampler_FftFixedinout!(f32);
resampler_FftFixedinout!(f64);
macro_rules! impl_fixedout {
($ft:ty) => {
impl FftFixedOut<$ft> {
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::<$ft>::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<$ft>> = vec![vec![0.0; fft_size_out]; nbr_channels];
let output_buffers: Vec<Vec<$ft>> = vec![vec![0.0; 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_fixedout!(f64);
impl_fixedout!(f32);
macro_rules! resampler_FftFixedout {
($t:ty) => {
impl Resampler<$t> for FftFixedOut<$t> {
fn nbr_frames_needed(&self) -> usize {
self.frames_needed
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn process(&mut self, wave_in: &[Vec<$t>]) -> Res<Vec<Vec<$t>>> {
if wave_in.len() != self.nbr_channels {
return Err(Box::new(ResamplerError::new(
"Wrong number of channels in input",
)));
}
if wave_in[0].len() != self.frames_needed {
return Err(Box::new(ResamplerError::new(
format!(
"Wrong number of frames in input, expected {}, got {}",
self.frames_needed,
wave_in[0].len()
)
.as_str(),
)));
}
let mut wave_out = self.output_buffers.clone();
let mut processed_samples = self.saved_frames * self.nbr_channels;
for n in 0..self.nbr_channels {
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]);
processed_samples += self.fft_size_out;
}
}
let processed_frames = processed_samples / self.nbr_channels;
self.saved_frames = processed_frames - self.chunk_size_out;
if processed_frames > self.chunk_size_out {
for n in 0..self.nbr_channels {
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 0..self.nbr_channels {
wave_out[n].truncate(self.chunk_size_out);
}
let frames_needed_out = self.chunk_size_out - self.saved_frames;
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)
}
}
};
}
resampler_FftFixedout!(f32);
resampler_FftFixedout!(f64);
macro_rules! impl_fixedin {
($ft:ty) => {
impl FftFixedIn<$ft> {
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::<$ft>::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<$ft>> = vec![vec![0.0; fft_size_out]; nbr_channels];
let input_buffers: Vec<Vec<$ft>> = vec![vec![0.0; 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_fixedin!(f64);
impl_fixedin!(f32);
macro_rules! resampler_FftFixedin {
($t:ty) => {
impl Resampler<$t> for FftFixedIn<$t> {
fn nbr_frames_needed(&self) -> usize {
self.chunk_size_in
}
fn set_resample_ratio(&mut self, _new_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn set_resample_ratio_relative(&mut self, _rel_ratio: f64) -> Res<()> {
Err(Box::new(ResamplerError::new(
"Not possible to adjust a synchronous resampler)",
)))
}
fn process(&mut self, wave_in: &[Vec<$t>]) -> Res<Vec<Vec<$t>>> {
if wave_in.len() != self.nbr_channels {
return Err(Box::new(ResamplerError::new(
"Wrong number of channels in input",
)));
}
if wave_in[0].len() != self.chunk_size_in {
return Err(Box::new(ResamplerError::new(
format!(
"Wrong number of frames in input, expected {}, got {}",
self.chunk_size_in,
wave_in[0].len()
)
.as_str(),
)));
}
let mut input_temp =
vec![vec![0.0; self.saved_frames + self.chunk_size_in]; self.nbr_channels];
for n in 0..self.nbr_channels {
for (input, buffer) in self.input_buffers[n]
.iter()
.take(self.saved_frames)
.zip(input_temp[n].iter_mut())
{
*buffer = *input;
}
}
for n in 0..self.nbr_channels {
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![0.0; nbr_chunks_ready * self.fft_size_out]; self.nbr_channels];
for n in 0..self.nbr_channels {
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 0..self.nbr_channels {
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)
}
}
};
}
resampler_FftFixedin!(f32);
resampler_FftFixedin!(f64);
#[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_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_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);
}
}