mod helpers;
mod interpolation;
use crate::helpers::*;
use crate::interpolation::*;
use num::traits::Float;
use std::error;
use std::fmt;
#[macro_use]
extern crate log;
type Res<T> = Result<T, Box<dyn error::Error>>;
#[derive(Debug)]
pub struct ResamplerError {
desc: String,
}
impl fmt::Display for ResamplerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.desc)
}
}
impl error::Error for ResamplerError {
fn description(&self) -> &str {
&self.desc
}
}
impl ResamplerError {
pub fn new(desc: &str) -> Self {
ResamplerError {
desc: desc.to_owned(),
}
}
}
#[derive(Debug)]
pub enum WindowFunction {
Blackman,
Blackman2,
BlackmanHarris,
BlackmanHarris2,
Hann,
Hann2,
}
#[derive(Debug)]
pub struct InterpolationParameters {
pub sinc_len: usize,
pub f_cutoff: f32,
pub oversampling_factor: usize,
pub interpolation: InterpolationType,
pub window: WindowFunction,
}
#[derive(Debug)]
pub enum InterpolationType {
Cubic,
Linear,
Nearest,
}
pub struct SincFixedIn<T: Float> {
nbr_channels: usize,
chunk_size: usize,
oversampling_factor: usize,
last_index: f64,
resample_ratio: f64,
resample_ratio_original: f64,
sinc_len: usize,
sincs: Vec<Vec<T>>,
buffer: Vec<Vec<T>>,
interpolation: InterpolationType,
}
pub struct SincFixedOut<T: Float> {
nbr_channels: usize,
chunk_size: usize,
needed_input_size: usize,
oversampling_factor: usize,
last_index: f64,
current_buffer_fill: usize,
resample_ratio: f64,
resample_ratio_original: f64,
sinc_len: usize,
sincs: Vec<Vec<T>>,
buffer: Vec<Vec<T>>,
interpolation: InterpolationType,
}
pub trait Resampler<T: Float> {
fn process(&mut self, wave_in: &[Vec<T>]) -> Res<Vec<Vec<T>>>;
fn set_resample_ratio(&mut self, new_ratio: f64) -> Res<()>;
fn set_resample_ratio_relative(&mut self, rel_ratio: f64) -> Res<()>;
fn nbr_frames_needed(&self) -> usize;
}
impl<T: Float> Resampler<T> for SincFixedIn<T> {
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 {
return Err(Box::new(ResamplerError::new(
"Wrong number of frames in input",
)));
}
let end_idx = self.chunk_size as isize - (self.sinc_len as isize + 1);
for wav in self.buffer.iter_mut() {
for idx in 0..(2 * self.sinc_len) {
wav[idx] = wav[idx + self.chunk_size];
}
}
for (chan, wav) in wave_in.iter().enumerate() {
for (idx, sample) in wav.iter().enumerate() {
self.buffer[chan][idx + 2 * self.sinc_len] = *sample;
}
}
let mut idx = self.last_index;
let t_ratio = 1.0 / self.resample_ratio as f64;
let mut wave_out =
vec![
vec![T::zero(); (self.chunk_size as f64 * self.resample_ratio + 10.0) as usize];
self.nbr_channels
];
let mut n = 0;
match self.interpolation {
InterpolationType::Cubic => {
let mut points = vec![T::zero(); 4];
let mut nearest = vec![(0isize, 0isize); 4];
while idx < end_idx as f64 {
idx += t_ratio;
get_nearest_times_4(idx, self.oversampling_factor as isize, &mut nearest);
let frac = idx * self.oversampling_factor as f64
- (idx * self.oversampling_factor as f64).floor();
let frac_offset = T::from(frac).unwrap();
for (chan, buf) in self.buffer.iter().enumerate() {
for (n, p) in nearest.iter().zip(points.iter_mut()) {
*p = get_sinc_interpolated(
&buf,
&self.sincs,
(n.0 + 2 * self.sinc_len as isize) as usize,
n.1 as usize,
);
}
wave_out[chan][n] = interp_cubic(frac_offset, &points);
}
n += 1;
}
}
InterpolationType::Linear => {
let mut points = vec![T::zero(); 2];
let mut nearest = vec![(0isize, 0isize); 2];
while idx < end_idx as f64 {
idx += t_ratio;
get_nearest_times_2(idx, self.oversampling_factor as isize, &mut nearest);
let frac = idx * self.oversampling_factor as f64
- (idx * self.oversampling_factor as f64).floor();
let frac_offset = T::from(frac).unwrap();
for (chan, buf) in self.buffer.iter().enumerate() {
for (n, p) in nearest.iter().zip(points.iter_mut()) {
*p = get_sinc_interpolated(
&buf,
&self.sincs,
(n.0 + 2 * self.sinc_len as isize) as usize,
n.1 as usize,
);
}
wave_out[chan][n] = interp_lin(frac_offset, &points);
}
n += 1;
}
}
InterpolationType::Nearest => {
let mut point;
let mut nearest;
while idx < end_idx as f64 {
idx += t_ratio;
nearest = get_nearest_time(idx, self.oversampling_factor as isize);
for (chan, buf) in self.buffer.iter().enumerate() {
point = get_sinc_interpolated(
&buf,
&self.sincs,
(nearest.0 + 2 * self.sinc_len as isize) as usize,
nearest.1 as usize,
);
wave_out[chan][n] = point;
}
n += 1;
}
}
}
self.last_index = idx - self.chunk_size as f64;
for w in wave_out.iter_mut() {
w.truncate(n);
}
trace!(
"Resampling, {} frames in, {} frames out",
wave_in[0].len(),
wave_out[0].len()
);
Ok(wave_out)
}
fn set_resample_ratio(&mut self, new_ratio: f64) -> Res<()> {
trace!("Change resample ratio to {}", new_ratio);
if (new_ratio / self.resample_ratio_original > 0.9)
&& (new_ratio / self.resample_ratio_original < 1.1)
{
self.resample_ratio = new_ratio;
Ok(())
} else {
Err(Box::new(ResamplerError::new(
"New resample ratio is too far off from original",
)))
}
}
fn set_resample_ratio_relative(&mut self, rel_ratio: f64) -> Res<()> {
let new_ratio = self.resample_ratio_original * rel_ratio;
self.set_resample_ratio(new_ratio)
}
fn nbr_frames_needed(&self) -> usize {
self.chunk_size
}
}
impl<T: Float> SincFixedIn<T> {
pub fn new(
resample_ratio: f64,
parameters: InterpolationParameters,
chunk_size: usize,
nbr_channels: usize,
) -> Self {
debug!(
"Create new SincFixedIn, ratio: {}, chunk_size: {}, channels: {}, parameters: {:?}",
resample_ratio, chunk_size, nbr_channels, parameters
);
let sinc_cutoff = if resample_ratio >= 1.0 {
parameters.f_cutoff
} else {
parameters.f_cutoff * resample_ratio as f32
};
let sincs = make_sincs(
parameters.sinc_len,
parameters.oversampling_factor,
sinc_cutoff,
parameters.window,
);
let buffer = vec![vec![T::zero(); chunk_size + 2 * parameters.sinc_len]; nbr_channels];
SincFixedIn {
nbr_channels,
chunk_size,
oversampling_factor: parameters.oversampling_factor,
last_index: -((parameters.sinc_len / 2) as f64),
resample_ratio,
resample_ratio_original: resample_ratio,
sinc_len: parameters.sinc_len,
sincs,
buffer,
interpolation: parameters.interpolation,
}
}
}
impl<T: Float> SincFixedOut<T> {
pub fn new(
resample_ratio: f64,
parameters: InterpolationParameters,
chunk_size: usize,
nbr_channels: usize,
) -> Self {
debug!(
"Create new SincFixedOut, ratio: {}, chunk_size: {}, channels: {}, parameters: {:?}",
resample_ratio, chunk_size, nbr_channels, parameters
);
let sinc_cutoff = if resample_ratio >= 1.0 {
parameters.f_cutoff
} else {
parameters.f_cutoff * resample_ratio as f32
};
let sincs = make_sincs(
parameters.sinc_len,
parameters.oversampling_factor,
sinc_cutoff,
parameters.window,
);
let needed_input_size =
(chunk_size as f64 / resample_ratio).ceil() as usize + 2 + parameters.sinc_len / 2;
let buffer = vec![
vec![T::zero(); 3 * needed_input_size / 2 + 2 * parameters.sinc_len];
nbr_channels
];
SincFixedOut {
nbr_channels,
chunk_size,
needed_input_size,
oversampling_factor: parameters.oversampling_factor,
last_index: -((parameters.sinc_len / 2) as f64),
current_buffer_fill: needed_input_size,
resample_ratio,
resample_ratio_original: resample_ratio,
sinc_len: parameters.sinc_len,
sincs,
buffer,
interpolation: parameters.interpolation,
}
}
}
impl<T: Float> Resampler<T> for SincFixedOut<T> {
fn nbr_frames_needed(&self) -> usize {
self.needed_input_size
}
fn set_resample_ratio(&mut self, new_ratio: f64) -> Res<()> {
trace!("Change resample ratio to {}", new_ratio);
if (new_ratio / self.resample_ratio_original > 0.9)
&& (new_ratio / self.resample_ratio_original < 1.1)
{
self.resample_ratio = new_ratio;
self.needed_input_size = (self.last_index as f32
+ self.chunk_size as f32 / self.resample_ratio as f32
+ self.sinc_len as f32)
.ceil() as usize
+ 2;
Ok(())
} else {
Err(Box::new(ResamplerError::new(
"New resample ratio is too far off from original",
)))
}
}
fn set_resample_ratio_relative(&mut self, rel_ratio: f64) -> Res<()> {
let new_ratio = self.resample_ratio_original * rel_ratio;
self.set_resample_ratio(new_ratio)
}
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.needed_input_size {
return Err(Box::new(ResamplerError::new(
"Wrong number of frames in input",
)));
}
for wav in self.buffer.iter_mut() {
for idx in 0..(2 * self.sinc_len) {
wav[idx] = wav[idx + self.current_buffer_fill];
}
}
self.current_buffer_fill = wave_in[0].len();
for (chan, wav) in wave_in.iter().enumerate() {
for (idx, sample) in wav.iter().enumerate() {
self.buffer[chan][idx + 2 * self.sinc_len] = *sample;
}
}
let mut idx = self.last_index;
let t_ratio = 1.0 / self.resample_ratio as f64;
let mut wave_out = vec![vec![T::zero(); self.chunk_size]; self.nbr_channels];
match self.interpolation {
InterpolationType::Cubic => {
let mut points = vec![T::zero(); 4];
let mut nearest = vec![(0isize, 0isize); 4];
for n in 0..self.chunk_size {
idx += t_ratio;
get_nearest_times_4(idx, self.oversampling_factor as isize, &mut nearest);
let frac = idx * self.oversampling_factor as f64
- (idx * self.oversampling_factor as f64).floor();
let frac_offset = T::from(frac).unwrap();
for (chan, buf) in self.buffer.iter().enumerate() {
for (n, p) in nearest.iter().zip(points.iter_mut()) {
*p = get_sinc_interpolated(
&buf,
&self.sincs,
(n.0 + 2 * self.sinc_len as isize) as usize,
n.1 as usize,
);
}
wave_out[chan][n] = interp_cubic(frac_offset, &points);
}
}
}
InterpolationType::Linear => {
let mut points = vec![T::zero(); 2];
let mut nearest = vec![(0isize, 0isize); 2];
for n in 0..self.chunk_size {
idx += t_ratio;
get_nearest_times_2(idx, self.oversampling_factor as isize, &mut nearest);
let frac = idx * self.oversampling_factor as f64
- (idx * self.oversampling_factor as f64).floor();
let frac_offset = T::from(frac).unwrap();
for (chan, buf) in self.buffer.iter().enumerate() {
for (n, p) in nearest.iter().zip(points.iter_mut()) {
*p = get_sinc_interpolated(
&buf,
&self.sincs,
(n.0 + 2 * self.sinc_len as isize) as usize,
n.1 as usize,
);
}
wave_out[chan][n] = interp_lin(frac_offset, &points);
}
}
}
InterpolationType::Nearest => {
let mut point;
let mut nearest;
for n in 0..self.chunk_size {
idx += t_ratio;
nearest = get_nearest_time(idx, self.oversampling_factor as isize);
for (chan, buf) in self.buffer.iter().enumerate() {
point = get_sinc_interpolated(
&buf,
&self.sincs,
(nearest.0 + 2 * self.sinc_len as isize) as usize,
nearest.1 as usize,
);
wave_out[chan][n] = point;
}
}
}
}
self.last_index = idx - self.current_buffer_fill as f64;
self.needed_input_size = (self.last_index as f32
+ self.chunk_size as f32 / self.resample_ratio as f32
+ self.sinc_len as f32)
.ceil() as usize
+ 2;
trace!(
"Resampling, {} frames in, {} frames out. Next needed length: {} frames, last index {}",
wave_in[0].len(),
wave_out[0].len(),
self.needed_input_size,
self.last_index
);
Ok(wave_out)
}
}
#[cfg(test)]
mod tests {
use crate::InterpolationParameters;
use crate::InterpolationType;
use crate::Resampler;
use crate::WindowFunction;
use crate::{SincFixedIn, SincFixedOut};
#[test]
fn make_resampler_fi() {
let params = InterpolationParameters {
sinc_len: 64,
f_cutoff: 0.95,
interpolation: InterpolationType::Cubic,
oversampling_factor: 16,
window: WindowFunction::BlackmanHarris2,
};
let mut resampler = SincFixedIn::<f64>::new(1.2, params, 1024, 2);
let waves = vec![vec![0.0f64; 1024]; 2];
let out = resampler.process(&waves).unwrap();
assert_eq!(out.len(), 2);
assert!(out[0].len() > 1150 && out[0].len() < 1250);
}
#[test]
fn make_resampler_fo() {
let params = InterpolationParameters {
sinc_len: 64,
f_cutoff: 0.95,
interpolation: InterpolationType::Cubic,
oversampling_factor: 16,
window: WindowFunction::BlackmanHarris2,
};
let mut resampler = SincFixedOut::<f64>::new(1.2, params, 1024, 2);
let frames = resampler.nbr_frames_needed();
println!("{}", frames);
assert!(frames > 800 && frames < 900);
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);
}
}