use dasp_graph::{Buffer, Input};
use crate::node::{AudioNode, ProcessContext};
#[derive(Clone, Copy, Debug)]
pub enum GainMessage {
SetGain(f32),
}
pub struct Gain {
gain: f32,
smoothed_gain: f32,
smooth_coeff: f32,
}
impl Gain {
pub fn new(gain: f32) -> Self {
Self {
gain,
smoothed_gain: gain,
smooth_coeff: 0.995, }
}
pub fn with_smoothing_ms(mut self, ms: f32, sample_rate: u32) -> Self {
let samples = (ms / 1000.0) * sample_rate as f32;
self.smooth_coeff = (-1.0 / samples).exp();
self
}
pub fn without_smoothing(mut self) -> Self {
self.smooth_coeff = 0.0;
self
}
#[inline]
pub fn gain(&self) -> f32 {
self.gain
}
}
impl AudioNode for Gain {
type Message = GainMessage;
fn process(
&mut self,
_ctx: &ProcessContext,
messages: impl Iterator<Item = GainMessage>,
inputs: &[Input],
outputs: &mut [Buffer],
) {
for msg in messages {
match msg {
GainMessage::SetGain(g) => self.gain = g,
}
}
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 smooth_coeff = self.smooth_coeff;
let target_gain = self.gain;
let mut current_gain = self.smoothed_gain;
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 gain = current_gain;
for (out_sample, &in_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
gain = target_gain + smooth_coeff * (gain - target_gain);
*out_sample = in_sample * gain;
}
if ch == 0 {
current_gain = gain;
}
}
self.smoothed_gain = current_gain;
}
#[inline]
fn num_inputs(&self) -> usize { 1 }
#[inline]
fn num_outputs(&self) -> usize { 2 } }