devalang_wasm/engine/audio/effects/processors/
roll.rs

1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct RollProcessor {
5    pub duration_ms: f32,
6    pub sync: bool,
7    pub repeats: i32,
8    pub fade: f32,
9}
10
11impl RollProcessor {
12    pub fn new(duration_ms: f32, sync: bool, repeats: i32, fade: f32) -> Self {
13        Self {
14            duration_ms: duration_ms.max(1.0),
15            sync,
16            repeats: repeats.clamp(1, 16),
17            fade: fade.clamp(0.0, 1.0),
18        }
19    }
20}
21
22impl Default for RollProcessor {
23    fn default() -> Self {
24        Self::new(100.0, false, 4, 0.02)
25    }
26}
27
28impl EffectProcessor for RollProcessor {
29    fn process(&mut self, samples: &mut [f32], sr: u32) {
30        let frames = samples.len() / 2;
31        let ms2frames = |ms: f32| ((ms / 1000.0) * sr as f32) as usize;
32        let len = ms2frames(self.duration_ms).max(1).min(frames);
33        // take first 'len' frames and repeat
34        let mut segment = vec![0.0f32; len * 2];
35        for i in 0..len {
36            let si = i * 2;
37            segment[si] = samples[si];
38            if si + 1 < samples.len() {
39                segment[si + 1] = samples[si + 1];
40            }
41        }
42        let mut out = vec![0.0f32; samples.len()];
43        let mut pos = 0usize;
44        for _r in 0..self.repeats {
45            for i in 0..len {
46                let di = pos * 2;
47                if di + 1 < out.len() {
48                    out[di] = segment[i * 2];
49                    out[di + 1] = segment[i * 2 + 1];
50                }
51                pos += 1;
52                if pos >= frames {
53                    break;
54                }
55            }
56            if pos >= frames {
57                break;
58            }
59        }
60        // fill rest with original tail
61        let mut src_pos = len * 2;
62        while pos < frames {
63            let di = pos * 2;
64            let si = src_pos.min(samples.len() - 2);
65            out[di] = samples[si];
66            out[di + 1] = samples[si + 1];
67            pos += 1;
68            src_pos += 2;
69        }
70        samples.copy_from_slice(&out);
71    }
72    fn reset(&mut self) {}
73    fn name(&self) -> &str {
74        "Roll"
75    }
76}