use dasp_graph::{Buffer, Input};
use crate::node::{AudioNode, ProcessContext};
#[derive(Clone, Copy, Debug)]
pub enum SlewLimiterMessage {
SetRate(f32),
SetRatePerSecond(f32),
}
pub struct SlewLimiter {
rate: f32,
last: [f32; 8],
rate_per_second: Option<f32>,
}
impl SlewLimiter {
pub fn new(rate: f32) -> Self {
Self {
rate: rate.abs(),
last: [0.0; 8],
rate_per_second: None,
}
}
pub fn from_rate_per_second(rate: f32) -> Self {
Self {
rate: 0.0, last: [0.0; 8],
rate_per_second: Some(rate),
}
}
#[inline]
pub fn rate(&self) -> f32 {
self.rate
}
}
impl AudioNode for SlewLimiter {
type Message = SlewLimiterMessage;
fn process(
&mut self,
ctx: &ProcessContext,
messages: impl Iterator<Item = SlewLimiterMessage>,
inputs: &[Input],
outputs: &mut [Buffer],
) {
for msg in messages {
match msg {
SlewLimiterMessage::SetRate(r) => {
self.rate = r.abs();
self.rate_per_second = None;
}
SlewLimiterMessage::SetRatePerSecond(r) => {
self.rate_per_second = Some(r);
self.rate = r / ctx.sample_rate as f32;
}
}
}
if let Some(rps) = self.rate_per_second {
self.rate = rps / ctx.sample_rate as f32;
}
if inputs.is_empty() || outputs.is_empty() {
return;
}
let input = &inputs[0];
let in_buffers = input.buffers();
if in_buffers.is_empty() {
for buffer in outputs.iter_mut() {
buffer.iter_mut().for_each(|s| *s = 0.0);
}
return;
}
let max_delta = self.rate;
for (ch, out_buffer) in outputs.iter_mut().enumerate() {
let in_buffer = in_buffers.get(ch).unwrap_or_else(|| in_buffers.last().unwrap());
let mut last = self.last[ch.min(7)];
for (out_sample, &in_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
let delta = in_sample - last;
let clamped_delta = delta.clamp(-max_delta, max_delta);
last += clamped_delta;
*out_sample = last;
}
self.last[ch.min(7)] = last;
}
}
#[inline]
fn num_inputs(&self) -> usize { 1 }
#[inline]
fn num_outputs(&self) -> usize { 2 }
}