devalang_wasm/engine/audio/effects/processors/
vibrato.rs1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct VibratoProcessor {
5 pub rate: f32,
6 pub depth: f32,
7 pub sync: bool,
8 buf_l: Vec<f32>,
9 buf_r: Vec<f32>,
10 pos: usize,
11 phase: f32,
12}
13
14impl VibratoProcessor {
15 pub fn new(rate: f32, depth: f32, sync: bool) -> Self {
16 let max_delay = 2048usize;
17 Self {
18 rate: rate.clamp(0.1, 10.0),
19 depth: depth.clamp(0.0, 0.02),
20 sync,
21 buf_l: vec![0.0; max_delay],
22 buf_r: vec![0.0; max_delay],
23 pos: 0,
24 phase: 0.0,
25 }
26 }
27}
28
29impl Default for VibratoProcessor {
30 fn default() -> Self {
31 Self::new(5.0, 0.003, false)
32 }
33}
34
35impl EffectProcessor for VibratoProcessor {
36 fn process(&mut self, samples: &mut [f32], sr: u32) {
37 let sr_f = sr as f32;
38 let max_delay = (self.buf_l.len() - 2) as f32;
39 for i in (0..samples.len()).step_by(2) {
40 let in_l = samples[i];
41 let in_r = if i + 1 < samples.len() {
42 samples[i + 1]
43 } else {
44 in_l
45 };
46 let lfo = (2.0 * std::f32::consts::PI * self.phase).sin();
48 let delay = ((self.depth * max_delay) * (lfo + 1.0) * 0.5).max(0.0);
49 let read_pos =
50 (self.pos as f32 - delay + self.buf_l.len() as f32) % self.buf_l.len() as f32;
51 let idx = read_pos.floor() as usize % self.buf_l.len();
52 let frac = read_pos - read_pos.floor();
53 let a = self.buf_l[idx];
54 let b = self.buf_l[(idx + 1) % self.buf_l.len()];
55 samples[i] = a * (1.0 - frac) + b * frac;
56
57 if i + 1 < samples.len() {
58 let a2 = self.buf_r[idx];
59 let b2 = self.buf_r[(idx + 1) % self.buf_r.len()];
60 samples[i + 1] = a2 * (1.0 - frac) + b2 * frac;
61 }
62
63 let write_idx = self.pos % self.buf_l.len();
65 self.buf_l[write_idx] = in_l;
66 self.buf_r[write_idx] = in_r;
67 self.pos = (self.pos + 1) % self.buf_l.len();
68 self.phase += self.rate / sr_f;
69 if self.phase >= 1.0 {
70 self.phase -= 1.0;
71 }
72 }
73 }
74
75 fn reset(&mut self) {
76 self.pos = 0;
77 self.phase = 0.0;
78 }
79
80 fn name(&self) -> &str {
81 "Vibrato"
82 }
83}