Changed slew logix to a real slew rate limiter
This commit is contained in:
parent
99eead8402
commit
993c690bc4
3 changed files with 76 additions and 23 deletions
|
@ -705,8 +705,55 @@ impl TriggerSampleClock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A slew rate limiter, with a configurable time per 1.0 increase.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct SlewValue<F: Flt> {
|
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,
|
slew_count: u64,
|
||||||
current: F,
|
current: F,
|
||||||
target: F,
|
target: F,
|
||||||
|
@ -714,7 +761,7 @@ pub struct SlewValue<F: Flt> {
|
||||||
sr_ms: F,
|
sr_ms: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Flt> SlewValue<F> {
|
impl<F: Flt> RampValue<F> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
slew_count: 0,
|
slew_count: 0,
|
||||||
|
|
|
@ -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_exp6!{n_lfot d_lfot 0.1,300000.0}
|
||||||
define_exp!{n_time d_time 0.5, 5000.0}
|
define_exp!{n_time d_time 0.5, 5000.0}
|
||||||
define_exp!{n_ftme d_ftme 0.1, 1000.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
|
// Special linear gain factor for the Out node, to be able
|
||||||
// to reach more exact "1.0".
|
// 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)
|
(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)
|
(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)
|
(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],
|
[0 sig],
|
||||||
delay => Delay UIType::Generic UICategory::Signal
|
delay => Delay UIType::Generic UICategory::Signal
|
||||||
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
(0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
|
|
@ -13,8 +13,9 @@ use crate::dsp::{
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RndWk {
|
pub struct RndWk {
|
||||||
rng: Rng,
|
rng: Rng,
|
||||||
slew_val: SlewValue<f32>,
|
slew_val: SlewValue<f64>,
|
||||||
trig: Trigger,
|
trig: Trigger,
|
||||||
|
target: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RndWk {
|
impl RndWk {
|
||||||
|
@ -26,8 +27,9 @@ impl RndWk {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
rng,
|
rng,
|
||||||
trig: Trigger::new(),
|
trig: Trigger::new(),
|
||||||
slew_val: SlewValue::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 \
|
"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.\
|
that is outside of this range, it will be reflected back into it.\
|
||||||
\nRange: (0..1)";
|
\nRange: (0..1)";
|
||||||
pub const slewt : &'static str =
|
pub const slew : &'static str =
|
||||||
"RndWk slewt\nThe slew time, the time it takes to reach the \
|
"RndWk slew\nThe slew rate limiting time. Thats the time it takes to \
|
||||||
new target value. This can be used to smooth off rough transitions and \
|
get to 1.0 from 0.0. Useful for smoothing modulation of audio signals. \
|
||||||
clicky noises.\nRange: (0..1)";
|
The higher the time, the smoother/slower the transition to new \
|
||||||
|
target values will be.\nRange: (0..1)";
|
||||||
pub const sig : &'static str =
|
pub const sig : &'static str =
|
||||||
"RndWk sig\nOscillator output\nRange: (-1..1)\n";
|
"RndWk sig\nOscillator output\nRange: (-1..1)\n";
|
||||||
pub const DESC : &'static str =
|
pub const DESC : &'static str =
|
||||||
r#"Random Walker
|
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 =
|
pub const HELP : &'static str =
|
||||||
r#"RndWk - Random Walker
|
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.
|
minimal step width each 'trig' has to change the target value.
|
||||||
|
|
||||||
For smoother transitions, if you want to modulate an audio signal with this,
|
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.
|
You can disable all randomness by setting 'step' to 0.0.
|
||||||
|
|
||||||
Tip: Interesting and smooth results can be achieved if you set 'slewt'
|
Tip: Interesting and smooth results can be achieved if you set 'slew'
|
||||||
to a longer time than the interval in that you trigger 'trig'. It will smooth
|
to a (way) longer time than the 'trig' interval. It will smooth
|
||||||
off the step widths and the overall motion even more.
|
off the step widths and the overall motion even more.
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
@ -87,12 +90,13 @@ impl DspNode for RndWk {
|
||||||
fn outputs() -> usize { 1 }
|
fn outputs() -> usize { 1 }
|
||||||
|
|
||||||
fn set_sample_rate(&mut self, srate: f32) {
|
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) {
|
fn reset(&mut self) {
|
||||||
self.slew_val.reset();
|
self.slew_val.reset();
|
||||||
self.trig.reset();
|
self.trig.reset();
|
||||||
|
self.target = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -109,7 +113,7 @@ impl DspNode for RndWk {
|
||||||
let offs = inp::RndWk::offs(inputs);
|
let offs = inp::RndWk::offs(inputs);
|
||||||
let min = inp::RndWk::min(inputs);
|
let min = inp::RndWk::min(inputs);
|
||||||
let max = inp::RndWk::max(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);
|
let out = out::RndWk::sig(outputs);
|
||||||
|
|
||||||
for frame in 0..ctx.nframes() {
|
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 offs = denorm::RndWk::offs(offs, frame).clamp(-1.0, 1.0);
|
||||||
|
|
||||||
let target =
|
let target =
|
||||||
self.slew_val.value()
|
self.slew_val.value() as f32
|
||||||
+ ((self.rng.next() * 2.0 * step) - step)
|
+ ((self.rng.next() * 2.0 * step) - step)
|
||||||
+ offs;
|
+ offs;
|
||||||
let target = ((target - min) % delta).abs() + min;
|
self.target = (((target - min) % delta).abs() + min) as f64;
|
||||||
|
|
||||||
let slew_time_ms = denorm::RndWk::slewt(slewt, frame);
|
|
||||||
|
|
||||||
self.slew_val.set_target(target, slew_time_ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
ctx_vals[0].set(out.read(ctx.nframes() - 1));
|
||||||
|
|
Loading…
Reference in a new issue