working on finally fixed interpolation functions in the delay line and the sampler
This commit is contained in:
parent
1fbc6741cb
commit
1ee4af6cd1
3 changed files with 213 additions and 11 deletions
|
@ -892,7 +892,6 @@ fn fclampc<F: Flt>(x: F, mi: f64, mx: f64) -> F {
|
|||
x.max(f(mi)).min(f(mx))
|
||||
}
|
||||
|
||||
|
||||
/// Hermite / Cubic interpolation of a buffer full of samples at the given _index_.
|
||||
/// _len_ is the buffer length to consider and wrap the index into. And _fract_ is the
|
||||
/// fractional part of the index.
|
||||
|
@ -913,6 +912,7 @@ fn fclampc<F: Flt>(x: F, mi: f64, mx: f64) -> F {
|
|||
///```
|
||||
#[inline]
|
||||
pub fn cubic_interpolate<F: Flt>(data: &[F], len: usize, index: usize, fract: F) -> F {
|
||||
let index = index + len;
|
||||
// Hermite interpolation, take from
|
||||
// https://github.com/eric-wood/delay/blob/main/src/delay.rs#L52
|
||||
//
|
||||
|
@ -1031,11 +1031,21 @@ impl<F: Flt> DelayBuffer<F> {
|
|||
let offs = s_offs.floor().to_usize().unwrap_or(0) % len;
|
||||
let fract = s_offs.fract();
|
||||
|
||||
let i = (self.wr + len) - offs;
|
||||
// one extra offset, because feed() advances self.wr to the next writing position!
|
||||
let i = (self.wr + len) - (offs + 1);
|
||||
let x0 = data[i % len];
|
||||
let x1 = data[(i - 1) % len];
|
||||
|
||||
x0 + fract * (x1 - x0)
|
||||
let res = x0 + fract * (x1 - x0);
|
||||
//d// eprintln!(
|
||||
//d// "INTERP: {:6.4} x0={:6.4} x1={:6.4} fract={:6.4} => {:6.4}",
|
||||
//d// s_offs.to_f64().unwrap_or(0.0),
|
||||
//d// x0.to_f64().unwrap(),
|
||||
//d// x1.to_f64().unwrap(),
|
||||
//d// fract.to_f64().unwrap(),
|
||||
//d// res.to_f64().unwrap(),
|
||||
//d// );
|
||||
res
|
||||
}
|
||||
|
||||
/// Fetch a sample from the delay buffer at the given time.
|
||||
|
@ -1057,23 +1067,33 @@ impl<F: Flt> DelayBuffer<F> {
|
|||
let offs = s_offs.floor().to_usize().unwrap_or(0) % len;
|
||||
let fract = s_offs.fract();
|
||||
|
||||
let i = (self.wr + len) - offs;
|
||||
|
||||
cubic_interpolate(data, len, i, f::<F>(1.0) - fract)
|
||||
let i = (self.wr + len) - (offs + 2);
|
||||
let res = cubic_interpolate(data, len, i, f::<F>(1.0) - fract);
|
||||
// eprintln!(
|
||||
// "cubic at={} ({:6.4}) res={:6.4}",
|
||||
// i % len,
|
||||
// s_offs.to_f64().unwrap(),
|
||||
// res.to_f64().unwrap()
|
||||
// );
|
||||
res
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn nearest_at(&self, delay_time_ms: F) -> F {
|
||||
let len = self.data.len();
|
||||
let offs = ((delay_time_ms * self.srate) / f(1000.0)).floor().to_usize().unwrap_or(0) % len;
|
||||
let idx = ((self.wr + len) - offs) % len;
|
||||
// (offs + 1) one extra offset, because feed() advances
|
||||
// self.wr to the next writing position!
|
||||
let idx = ((self.wr + len) - (offs + 1)) % len;
|
||||
self.data[idx]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn at(&self, delay_sample_count: usize) -> F {
|
||||
let len = self.data.len();
|
||||
let idx = ((self.wr + len) - delay_sample_count) % len;
|
||||
// (delay_sample_count + 1) one extra offset, because feed() advances self.wr to
|
||||
// the next writing position!
|
||||
let idx = ((self.wr + len) - (delay_sample_count + 1)) % len;
|
||||
self.data[idx]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,8 +148,8 @@ impl Sampl {
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
let j = self.phase.floor() as usize % sd_len;
|
||||
let i = ((sd_len - 1) - j) + sd_len;
|
||||
let j = self.phase.floor() as usize;
|
||||
let i = ((sd_len - 1) - j);
|
||||
|
||||
let f = self.phase.fract();
|
||||
self.phase = j as f64 + f + sr_factor * speed;
|
||||
|
@ -165,7 +165,7 @@ impl Sampl {
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
let i = self.phase.floor() as usize + sd_len;
|
||||
let i = self.phase.floor() as usize;
|
||||
let f = self.phase.fract();
|
||||
self.phase = (i % sd_len) as f64 + f + sr_factor * speed;
|
||||
|
||||
|
|
182
tests/delay_buffer.rs
Normal file
182
tests/delay_buffer.rs
Normal file
|
@ -0,0 +1,182 @@
|
|||
// Copyright (c) 2021 Weird Constructor <weirdconstructor@gmail.com>
|
||||
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
|
||||
// See README.md and COPYING for details.
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
fn check_delaybuffer_linear_interpolation() {
|
||||
let mut buf = crate::helpers::DelayBuffer::new();
|
||||
|
||||
buf.feed(0.0);
|
||||
buf.feed(0.1);
|
||||
buf.feed(0.2);
|
||||
buf.feed(0.3);
|
||||
buf.feed(0.4);
|
||||
buf.feed(0.5);
|
||||
buf.feed(0.6);
|
||||
buf.feed(0.7);
|
||||
buf.feed(0.8);
|
||||
buf.feed(0.9);
|
||||
buf.feed(1.0);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.5;
|
||||
for _ in 0..20 {
|
||||
samples_out.push(buf.linear_interpolate_at_s(pos));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35000002, 0.3,
|
||||
0.25, 0.2, 0.15, 0.1, 0.05
|
||||
]
|
||||
);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.2;
|
||||
for _ in 0..30 {
|
||||
samples_out.push(buf.linear_interpolate_at_s(pos));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 0.98, 0.96, 0.94, 0.91999996, 0.9, 0.88, 0.85999995, 0.84, 0.82, 0.8, 0.78, 0.76,
|
||||
0.73999995, 0.71999997, 0.6999999, 0.67999995, 0.65999997, 0.6399999, 0.61999995,
|
||||
0.59999996, 0.58, 0.56, 0.54, 0.52000004, 0.50000006, 0.48000008, 0.4600001,
|
||||
0.44000012, 0.42000014
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_delaybuffer_nearest() {
|
||||
let mut buf = crate::helpers::DelayBuffer::new();
|
||||
|
||||
buf.feed(0.0);
|
||||
buf.feed(0.1);
|
||||
buf.feed(0.2);
|
||||
buf.feed(0.3);
|
||||
buf.feed(0.4);
|
||||
buf.feed(0.5);
|
||||
buf.feed(0.6);
|
||||
buf.feed(0.7);
|
||||
buf.feed(0.8);
|
||||
buf.feed(0.9);
|
||||
buf.feed(1.0);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.5;
|
||||
for _ in 0..20 {
|
||||
samples_out.push(buf.at(pos as usize));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 1.0, 0.9, 0.9, 0.8, 0.8, 0.7, 0.7, 0.6, 0.6, 0.5, 0.5, 0.4, 0.4, 0.3, 0.3, 0.2,
|
||||
0.2, 0.1, 0.1
|
||||
]
|
||||
);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.2;
|
||||
for _ in 0..30 {
|
||||
samples_out.push(buf.at(pos as usize));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.8, 0.8, 0.8, 0.8, 0.7, 0.7,
|
||||
0.7, 0.7, 0.7, 0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.5
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_cubic_interpolate() {
|
||||
use crate::helpers::cubic_interpolate;
|
||||
let data = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0];
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0_f32;
|
||||
let pos_inc = 0.1_f32;
|
||||
for _ in 0..30 {
|
||||
let i = pos.floor() as usize;
|
||||
let f = pos.fract();
|
||||
samples_out.push(cubic_interpolate(&data[..], data.len(), i, f));
|
||||
pos += pos_inc;
|
||||
}
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 1.03455, 1.0504, 1.05085, 1.0392, 1.01875, 0.99279994, 0.9646499, 0.9375999,
|
||||
0.91494995, 0.9, 0.89, 0.87999994, 0.86999995, 0.85999995, 0.84999996, 0.84, 0.83,
|
||||
0.82, 0.80999994, 0.8, 0.79, 0.78000003, 0.77000004, 0.76, 0.75, 0.74, 0.73, 0.72,
|
||||
0.71000004
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_delaybuffer_cubic_interpolation() {
|
||||
let mut buf = crate::helpers::DelayBuffer::new();
|
||||
|
||||
buf.feed(0.0);
|
||||
buf.feed(0.1);
|
||||
buf.feed(0.2);
|
||||
buf.feed(0.3);
|
||||
buf.feed(0.4);
|
||||
buf.feed(0.5);
|
||||
buf.feed(0.6);
|
||||
buf.feed(0.7);
|
||||
buf.feed(0.8);
|
||||
buf.feed(0.9);
|
||||
buf.feed(1.0);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.5;
|
||||
for _ in 0..20 {
|
||||
samples_out.push(buf.cubic_interpolate_at_s(pos));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35000002, 0.3,
|
||||
0.25, 0.2, 0.15, 0.1, 0.05
|
||||
]
|
||||
);
|
||||
|
||||
let mut samples_out = vec![];
|
||||
let mut pos = 0.0;
|
||||
let pos_inc = 0.2;
|
||||
for _ in 0..30 {
|
||||
samples_out.push(buf.cubic_interpolate_at_s(pos));
|
||||
pos += pos_inc;
|
||||
}
|
||||
|
||||
assert_vec_feq!(
|
||||
samples_out,
|
||||
vec![
|
||||
1.0, 0.98, 0.96, 0.94, 0.91999996, 0.9, 0.88, 0.85999995, 0.84, 0.82, 0.8, 0.78, 0.76,
|
||||
0.73999995, 0.71999997, 0.6999999, 0.67999995, 0.65999997, 0.6399999, 0.61999995,
|
||||
0.59999996, 0.58, 0.56, 0.54, 0.52000004, 0.50000006, 0.48000008, 0.4600001,
|
||||
0.44000012, 0.42000014
|
||||
]
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue