devalang_wasm/engine/audio/effects/processors/
bitcrush.rs1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct BitcrushProcessor {
5 pub depth: f32, pub sample_rate: f32, pub mix: f32,
8 sample_pos: usize,
9 hold_step: usize,
10}
11
12impl BitcrushProcessor {
13 pub fn new(depth: f32, sample_rate: f32, mix: f32) -> Self {
14 Self {
15 depth: depth.clamp(1.0, 16.0),
16 sample_rate: sample_rate.max(100.0),
17 mix: mix.clamp(0.0, 1.0),
18 sample_pos: 0,
19 hold_step: 1,
20 }
21 }
22}
23
24impl Default for BitcrushProcessor {
25 fn default() -> Self {
26 Self::new(8.0, 8000.0, 0.5)
27 }
28}
29
30impl EffectProcessor for BitcrushProcessor {
31 fn process(&mut self, samples: &mut [f32], sr: u32) {
32 let sr_f = sr as f32;
33 let target_rate = self.sample_rate.clamp(100.0, sr_f);
35 let step = (sr_f / target_rate).max(1.0) as usize;
36 self.hold_step = step;
37
38 let levels = (2u32.pow(self.depth as u32)) as f32;
39 let mut hold_l = 0.0f32;
40 let mut hold_r = 0.0f32;
41 for i in (0..samples.len()).step_by(2) {
42 if self.sample_pos % self.hold_step == 0 {
43 let in_l = samples[i];
45 let ql =
46 (((in_l + 1.0) * 0.5 * (levels - 1.0)).round() / (levels - 1.0)) * 2.0 - 1.0;
47 hold_l = ql;
48 if i + 1 < samples.len() {
49 let in_r = samples[i + 1];
50 let qr = (((in_r + 1.0) * 0.5 * (levels - 1.0)).round() / (levels - 1.0)) * 2.0
51 - 1.0;
52 hold_r = qr;
53 }
54 }
55 samples[i] = samples[i] * (1.0 - self.mix) + hold_l * self.mix;
56 if i + 1 < samples.len() {
57 samples[i + 1] = samples[i + 1] * (1.0 - self.mix) + hold_r * self.mix;
58 }
59 self.sample_pos = self.sample_pos.wrapping_add(1);
60 }
61 }
62
63 fn reset(&mut self) {
64 self.sample_pos = 0;
65 }
66
67 fn name(&self) -> &str {
68 "Bitcrush"
69 }
70}