Changed slew logix to a real slew rate limiter

This commit is contained in:
Weird Constructor 2021-08-13 06:04:48 +02:00
parent 99eead8402
commit 993c690bc4
3 changed files with 76 additions and 23 deletions

View file

@ -705,8 +705,55 @@ impl TriggerSampleClock {
}
}
/// A slew rate limiter, with a configurable time per 1.0 increase.
#[derive(Debug, Clone, Copy)]
pub struct SlewValue<F: Flt> {
current: F,
slew_per_ms: F,
}
impl<F: Flt> SlewValue<F> {
pub fn new() -> Self {
Self {
current: f(0.0),
slew_per_ms: f(1000.0 / 44100.0),
}
}
pub fn reset(&mut self) {
self.current = f(0.0);
}
pub fn set_sample_rate(&mut self, srate: F) {
self.slew_per_ms = f::<F>(1000.0) / srate;
}
#[inline]
pub fn value(&self) -> F { self.current }
/// * `slew_ms_per_1` - The time (in milliseconds) it should take
/// to get to 1.0 from 0.0.
#[inline]
pub fn next(&mut self, target: F, slew_ms_per_1: F) -> F {
// at 0.11ms, there are barely enough samples for proper slew.
if slew_ms_per_1 < f(0.11) {
self.current = target;
} else {
let max_delta = self.slew_per_ms / slew_ms_per_1;
self.current =
target
.min(self.current + max_delta)
.max(self.current - max_delta);
}
self.current
}
}
/// A ramped value changer, with a configurable time to reach the target value.
#[derive(Debug, Clone, Copy)]
pub struct RampValue<F: Flt> {
slew_count: u64,
current: F,
target: F,
@ -714,7 +761,7 @@ pub struct SlewValue<F: Flt> {
sr_ms: F,
}
impl<F: Flt> SlewValue<F> {
impl<F: Flt> RampValue<F> {
pub fn new() -> Self {
Self {
slew_count: 0,

View file

@ -610,7 +610,7 @@ define_exp!{n_env d_env 0.0, 1000.0}
define_exp6!{n_lfot d_lfot 0.1,300000.0}
define_exp!{n_time d_time 0.5, 5000.0}
define_exp!{n_ftme d_ftme 0.1, 1000.0}
define_exp!{n_ftmz d_ftmz 0.0, 1000.0}
define_exp!{n_ftmz d_ftmz 0.0, 5000.0}
// Special linear gain factor for the Out node, to be able
// to reach more exact "1.0".
@ -760,7 +760,7 @@ macro_rules! node_list {
(2 offs n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
(3 min n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0)
(4 max n_id d_id r_id f_def stp_d 0.0, 1.0, 1.0)
(5 slewt n_ftmz d_ftmz r_fmz f_ms stp_m 0.0, 1.0, 10.0)
(5 slew n_ftmz d_ftmz r_fmz f_ms stp_m 0.0, 1.0, 75.0)
[0 sig],
delay => Delay UIType::Generic UICategory::Signal
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)

View file

@ -13,8 +13,9 @@ use crate::dsp::{
#[derive(Debug, Clone)]
pub struct RndWk {
rng: Rng,
slew_val: SlewValue<f32>,
slew_val: SlewValue<f64>,
trig: Trigger,
target: f64,
}
impl RndWk {
@ -26,8 +27,9 @@ impl RndWk {
Self {
rng,
trig: Trigger::new(),
slew_val: SlewValue::new(),
trig: Trigger::new(),
slew_val: SlewValue::new(),
target: 0.0,
}
}
@ -52,16 +54,17 @@ impl RndWk {
"RndWk max\nThe maximum of the new target value. If a value is drawn \
that is outside of this range, it will be reflected back into it.\
\nRange: (0..1)";
pub const slewt : &'static str =
"RndWk slewt\nThe slew time, the time it takes to reach the \
new target value. This can be used to smooth off rough transitions and \
clicky noises.\nRange: (0..1)";
pub const slew : &'static str =
"RndWk slew\nThe slew rate limiting time. Thats the time it takes to \
get to 1.0 from 0.0. Useful for smoothing modulation of audio signals. \
The higher the time, the smoother/slower the transition to new \
target values will be.\nRange: (0..1)";
pub const sig : &'static str =
"RndWk sig\nOscillator output\nRange: (-1..1)\n";
pub const DESC : &'static str =
r#"Random Walker
This modulator generates a random number by walking a pre defined maximum random 'step' width. For smoother transitions a slew time is integrated.
This modulator generates a random number by walking a pre defined maximum random 'step' width. For smoother transitions a slew rate limiter is integrated.
"#;
pub const HELP : &'static str =
r#"RndWk - Random Walker
@ -72,12 +75,12 @@ be folded within the defined 'min'/'max' range. The 'offs' parameter defines a
minimal step width each 'trig' has to change the target value.
For smoother transitions, if you want to modulate an audio signal with this,
a slew time ('slewt') is integrated.
a slew rate limiter ('slew') is integrated.
You can disable all randomness by setting 'step' to 0.0.
Tip: Interesting and smooth results can be achieved if you set 'slewt'
to a longer time than the interval in that you trigger 'trig'. It will smooth
Tip: Interesting and smooth results can be achieved if you set 'slew'
to a (way) longer time than the 'trig' interval. It will smooth
off the step widths and the overall motion even more.
"#;
@ -87,12 +90,13 @@ impl DspNode for RndWk {
fn outputs() -> usize { 1 }
fn set_sample_rate(&mut self, srate: f32) {
self.slew_val.set_sample_rate(srate);
self.slew_val.set_sample_rate(srate as f64);
}
fn reset(&mut self) {
self.slew_val.reset();
self.trig.reset();
self.target = 0.0;
}
#[inline]
@ -109,7 +113,7 @@ impl DspNode for RndWk {
let offs = inp::RndWk::offs(inputs);
let min = inp::RndWk::min(inputs);
let max = inp::RndWk::max(inputs);
let slewt = inp::RndWk::slewt(inputs);
let slew = inp::RndWk::slew(inputs);
let out = out::RndWk::sig(outputs);
for frame in 0..ctx.nframes() {
@ -125,17 +129,19 @@ impl DspNode for RndWk {
let offs = denorm::RndWk::offs(offs, frame).clamp(-1.0, 1.0);
let target =
self.slew_val.value()
self.slew_val.value() as f32
+ ((self.rng.next() * 2.0 * step) - step)
+ offs;
let target = ((target - min) % delta).abs() + min;
let slew_time_ms = denorm::RndWk::slewt(slewt, frame);
self.slew_val.set_target(target, slew_time_ms);
self.target = (((target - min) % delta).abs() + min) as f64;
}
out.write(frame, self.slew_val.next());
let slew_time_ms = denorm::RndWk::slew(slew, frame);
out.write(
frame,
self.slew_val.next(
self.target,
slew_time_ms as f64) as f32);
}
ctx_vals[0].set(out.read(ctx.nframes() - 1));