sim_lib_audio_dsp/
smoothing.rs1use sim_lib_audio_graph_core::{BlockEvent, PrepareConfig, ProcessBlock, Processor};
2
3use crate::common::{input_sample, output_channels};
4
5#[derive(Clone, Copy, Debug, PartialEq)]
8pub struct SmoothValue {
9 current: f32,
10 target: f32,
11 step: f32,
12 remaining: u32,
13}
14
15impl SmoothValue {
16 pub fn new(value: f32) -> Self {
18 Self {
19 current: value,
20 target: value,
21 step: 0.0,
22 remaining: 0,
23 }
24 }
25
26 pub fn current(&self) -> f32 {
28 self.current
29 }
30
31 pub fn target(&self) -> f32 {
33 self.target
34 }
35
36 pub fn set_target(&mut self, target: f32, samples: u32) {
38 self.target = target;
39 if samples == 0 {
40 self.current = target;
41 self.step = 0.0;
42 self.remaining = 0;
43 return;
44 }
45 self.remaining = samples;
46 self.step = (target - self.current) / samples as f32;
47 }
48
49 pub fn next_sample(&mut self) -> f32 {
51 if self.remaining > 0 {
52 self.current += self.step;
53 self.remaining -= 1;
54 if self.remaining == 0 {
55 self.current = self.target;
56 }
57 }
58 self.current
59 }
60
61 pub fn reset(&mut self, value: f32) {
63 *self = Self::new(value);
64 }
65}
66
67#[derive(Clone, Debug, PartialEq)]
70pub struct SmoothedGain {
71 gain: SmoothValue,
72 ramp_ms: f32,
73 param_id: u32,
74 sample_rate_hz: f32,
75}
76
77impl SmoothedGain {
78 pub fn new(initial_gain: f32, ramp_ms: f32) -> Self {
80 Self {
81 gain: SmoothValue::new(initial_gain),
82 ramp_ms,
83 param_id: 0,
84 sample_rate_hz: 48_000.0,
85 }
86 }
87
88 pub fn with_param(mut self, param_id: u32) -> Self {
90 self.param_id = param_id;
91 self
92 }
93
94 fn ramp_samples(&self) -> u32 {
95 ((self.sample_rate_hz * self.ramp_ms.max(0.0)) / 1000.0).round() as u32
96 }
97}
98
99impl Processor for SmoothedGain {
100 fn prepare(&mut self, cfg: PrepareConfig) {
101 self.sample_rate_hz = cfg.sample_rate_hz as f32;
102 }
103
104 fn reset(&mut self) {
105 let value = self.gain.target();
106 self.gain.reset(value);
107 }
108
109 fn process(&mut self, block: &mut ProcessBlock<'_>) {
110 let frames = block.frames as usize;
111 let channels = output_channels(block);
112 for frame in 0..frames {
113 for event in block.in_events {
114 if let BlockEvent::ParamSet {
115 offset,
116 param,
117 value,
118 } = *event
119 && offset as usize == frame
120 && param == self.param_id
121 {
122 self.gain.set_target(value as f32, self.ramp_samples());
123 }
124 }
125 let gain = self.gain.next_sample();
126 for channel in 0..channels {
127 block.out_audio[channel][frame] = input_sample(block, channel, frame) * gain;
128 }
129 }
130 }
131}