Skip to content

Instantly share code, notes, and snippets.

@matteddy
Created May 23, 2020
Embed
What would you like to do?
Sinc resampler
use std::collections::VecDeque;
use std::f64::consts::PI;
pub struct ResampleConfig {
pub time_stretch_factor: f64,
pub number_of_sinced_samples_to_use: usize,
pub look_back_full: bool,
}
pub trait Resamplable {
fn time_stretch(self, config: ResampleConfig) -> Resample<Self>
where
Self: Sized;
}
impl<I> Resamplable for I
where
I: Iterator,
I: Sized,
{
fn time_stretch(self, config: ResampleConfig) -> Resample<Self> {
let dequeue_vec: VecDeque<f64> = VecDeque::new();
let sinc = Sinc::new();
Resample {
config,
iterator: self,
sample_counter: 0.0,
look_back: dequeue_vec,
look_back_full: false,
sinc: sinc,
}
}
}
pub struct Resample<T> {
pub iterator: T,
pub config: ResampleConfig,
look_back: VecDeque<f64>,
sample_counter: f64,
look_back_full: bool,
sinc: Sinc,
}
impl<T> Iterator for Resample<T>
where
T: Iterator<Item = i32>,
{
type Item = i32;
fn next(&mut self) -> Option<i32> {
let stretch_factor = self.config.time_stretch_factor;
let number_of_sinced_samples_to_use = self.config.number_of_sinced_samples_to_use;
let sample_counter = self.sample_counter;
if !self.config.look_back_full {
while self.look_back.len() < number_of_sinced_samples_to_use {
println!("initialize look back");
match self.iterator.next() {
Some(val) => {
self.look_back.push_back(val as f64);
}
None => {}
};
}
println!("lookback full? {}", self.look_back_full);
self.config.look_back_full = true;
println!("lookback full? {}", self.look_back_full);
}
let mut new_sample_value = 0.0;
for i in 0..number_of_sinced_samples_to_use {
let mut sinc_index = (number_of_sinced_samples_to_use / 2) as f64 - i as f64;
let offset = sample_counter.fract();
if sinc_index < 0.0 {
sinc_index = sinc_index - (1.0 - offset) + 1.0;
} else {
sinc_index = sinc_index + offset;
}
let value = self.sinc.get_sinc_value_at_real(sinc_index);
match self.look_back.get(i) {
Some(val) => {
new_sample_value = new_sample_value + (value * *val as f64);
}
None => {}
};
}
let forward_movement_amount =
((sample_counter + stretch_factor).floor() - sample_counter.floor()) as usize;
self.sample_counter = sample_counter + stretch_factor;
for _ in 0..forward_movement_amount {
match self.iterator.next() {
Some(val) => {
self.look_back.push_back(val as f64);
self.look_back.pop_front();
}
None => {
return None;
}
};
}
Some(new_sample_value as i32 / 2)
}
}
struct BlackmanWindow {
sample_values: Vec<f64>,
size_of_window: usize,
}
impl BlackmanWindow {
fn new(size_of_window: usize) -> BlackmanWindow {
let increment_rate = 0.001; // Maximum precision
let mut samples: Vec<f64> = Vec::new();
let mut starting_value = 0.0;
for i in 0..(size_of_window * 1000) {
let value = 0.42
+ 0.5 * (2.0 * PI * starting_value / size_of_window as f64 * 2 as f64).cos()
+ 0.08 * (4.0 * PI * starting_value / size_of_window as f64 * 2 as f64).cos();
samples.push(value);
starting_value = starting_value + increment_rate;
}
BlackmanWindow {
sample_values: samples,
size_of_window,
}
}
fn get_black_value_at_index(&self, index: usize) -> f64 {
*self.sample_values.get(index).unwrap()
}
}
struct Sinc {
sample_values: Vec<f64>,
blackman_window: BlackmanWindow,
}
impl Sinc {
fn new() -> Sinc {
let increment_rate = 0.001; // Maximum precision
let mut samples: Vec<f64> = Vec::new();
let mut starting_value = 0.0;
for i in 0..(100 * 1000) {
let value = (starting_value * PI).sin() / (starting_value * PI); // https://en.wikipedia.org/wiki/Sinc_function
starting_value = starting_value + increment_rate;
samples.push(value)
}
let blackman_window = BlackmanWindow::new(33);
Sinc {
sample_values: samples,
blackman_window,
}
}
fn get_sinc_value_at_real(&mut self, real: f64) -> f64 {
let abs_real = real.abs();
if abs_real > 99.0 {
return 0.0;
}
let index = (abs_real * 1000.0).round() as usize;
if index == 0 {
return 1.0;
} else {
let mut return_value = 0.0;
{
return_value = *self.sample_values.get(index).unwrap();
};
{
let bv = self.blackman_window.get_black_value_at_index(index);
return_value = bv * return_value;
}
return return_value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment