devalang_wasm/engine/audio/effects/processors/
compressor.rs1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct CompressorProcessor {
5 threshold: f32,
6 ratio: f32,
7 attack: f32,
8 release: f32,
9 envelope: f32,
10}
11
12impl CompressorProcessor {
13 pub fn new(threshold: f32, ratio: f32, attack: f32, release: f32) -> Self {
14 Self {
15 threshold,
16 ratio: ratio.max(1.0),
17 attack: attack.max(0.001),
18 release: release.max(0.001),
19 envelope: 0.0,
20 }
21 }
22}
23
24impl Default for CompressorProcessor {
25 fn default() -> Self {
26 Self::new(-20.0, 4.0, 0.005, 0.1)
27 }
28}
29
30impl EffectProcessor for CompressorProcessor {
31 fn process(&mut self, samples: &mut [f32], sample_rate: u32) {
32 let attack_coeff = (-1.0 / (self.attack * sample_rate as f32)).exp();
33 let release_coeff = (-1.0 / (self.release * sample_rate as f32)).exp();
34
35 for i in (0..samples.len()).step_by(2) {
36 let left = samples[i];
38 let right = if i + 1 < samples.len() {
39 samples[i + 1]
40 } else {
41 left
42 };
43 let rms = ((left * left + right * right) / 2.0).sqrt();
44
45 let db = if rms > 0.0001 {
47 20.0 * rms.log10()
48 } else {
49 -100.0
50 };
51
52 let target = if db > self.threshold {
54 self.threshold + (db - self.threshold) / self.ratio
55 } else {
56 db
57 };
58
59 let coeff = if target > self.envelope {
60 attack_coeff
61 } else {
62 release_coeff
63 };
64
65 self.envelope = target + coeff * (self.envelope - target);
66
67 let gain_db = self.envelope - db;
69 let gain = 10.0_f32.powf(gain_db / 20.0);
70
71 samples[i] *= gain;
73 if i + 1 < samples.len() {
74 samples[i + 1] *= gain;
75 }
76 }
77 }
78
79 fn reset(&mut self) {
80 self.envelope = 0.0;
81 }
82
83 fn name(&self) -> &str {
84 "Compressor"
85 }
86}