sim_lib_audio_dsp/
gain.rs1use std::f32::consts::FRAC_PI_4;
2
3use sim_lib_audio_graph_core::{PrepareConfig, ProcessBlock, Processor};
4
5use crate::common::{input_sample, output_channels, prepare_channels};
6
7#[derive(Clone, Debug, PartialEq)]
18pub struct Gain {
19 gain: f32,
20}
21
22impl Gain {
23 pub fn new(gain: f32) -> Self {
25 Self { gain }
26 }
27
28 pub fn gain(&self) -> f32 {
30 self.gain
31 }
32}
33
34impl Processor for Gain {
35 fn prepare(&mut self, _cfg: PrepareConfig) {}
36
37 fn reset(&mut self) {}
38
39 fn process(&mut self, block: &mut ProcessBlock<'_>) {
40 let frames = block.frames as usize;
41 for channel in 0..output_channels(block) {
42 for frame in 0..frames {
43 block.out_audio[channel][frame] = input_sample(block, channel, frame) * self.gain;
44 }
45 }
46 }
47}
48
49#[derive(Clone, Debug, PartialEq)]
51pub struct Pan {
52 pan: f32,
53}
54
55impl Pan {
56 pub fn new(pan: f32) -> Self {
59 Self {
60 pan: pan.clamp(-1.0, 1.0),
61 }
62 }
63
64 pub fn gains(&self) -> (f32, f32) {
66 let angle = (self.pan + 1.0) * FRAC_PI_4;
67 (angle.cos(), angle.sin())
68 }
69}
70
71impl Processor for Pan {
72 fn prepare(&mut self, _cfg: PrepareConfig) {}
73
74 fn reset(&mut self) {}
75
76 fn process(&mut self, block: &mut ProcessBlock<'_>) {
77 let frames = block.frames as usize;
78 let (left_gain, right_gain) = self.gains();
79 match output_channels(block) {
80 0 => {}
81 1 => {
82 for frame in 0..frames {
83 let mono = input_sample(block, 0, frame);
84 block.out_audio[0][frame] = mono * (left_gain + right_gain) * 0.5;
85 }
86 }
87 _ => {
88 for frame in 0..frames {
89 let left = input_sample(block, 0, frame);
90 let right = if block.in_audio.len() > 1 {
91 input_sample(block, 1, frame)
92 } else {
93 left
94 };
95 block.out_audio[0][frame] = left * left_gain;
96 block.out_audio[1][frame] = right * right_gain;
97 }
98 }
99 }
100 }
101}
102
103#[derive(Clone, Copy, Debug, Default, PartialEq)]
104struct DcState {
105 x1: f32,
106 y1: f32,
107}
108
109#[derive(Clone, Debug, PartialEq)]
112pub struct DcBlocker {
113 coefficient: f32,
114 states: Vec<DcState>,
115}
116
117impl DcBlocker {
118 pub fn new(coefficient: f32) -> Self {
120 Self {
121 coefficient: coefficient.clamp(0.0, 0.9999),
122 states: Vec::new(),
123 }
124 }
125}
126
127impl Default for DcBlocker {
128 fn default() -> Self {
129 Self::new(0.995)
130 }
131}
132
133impl Processor for DcBlocker {
134 fn prepare(&mut self, cfg: PrepareConfig) {
135 prepare_channels(
136 &mut self.states,
137 cfg.out_channels as usize,
138 DcState::default(),
139 );
140 }
141
142 fn reset(&mut self) {
143 self.states.fill(DcState::default());
144 }
145
146 fn process(&mut self, block: &mut ProcessBlock<'_>) {
147 let channels = output_channels(block);
148 if self.states.len() < channels {
149 self.states.resize(channels, DcState::default());
150 }
151 let frames = block.frames as usize;
152 for channel in 0..channels {
153 let state = &mut self.states[channel];
154 for frame in 0..frames {
155 let input = input_sample(block, channel, frame);
156 let output = input - state.x1 + self.coefficient * state.y1;
157 state.x1 = input;
158 state.y1 = output;
159 block.out_audio[channel][frame] = output;
160 }
161 }
162 }
163}