devalang_wasm/engine/audio/effects/processors/
roll.rs1use 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 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 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}