Skip to main content

rescale_core/buffer/
effects.rs

1//! Efek Audio Berbasis Waktu (Echo, Feedback Delay, Comb Filter).
2
3use super::delay_line::{DelayLine, InterpolationType};
4
5/// Feedback Delay Effect sederhana dengan parameter Wet/Dry mix dan Feedback
6pub struct FeedbackDelay {
7    delay_line: DelayLine,
8    delay_samples: f32,
9    feedback: f32,
10    mix: f32, // 0.0 (hanya Dry) s/d 1.0 (hanya Wet)
11    interp: InterpolationType,
12}
13
14impl FeedbackDelay {
15    pub fn new(max_delay_samples: usize, initial_delay: f32, feedback: f32, mix: f32) -> Self {
16        Self {
17            delay_line: DelayLine::new(max_delay_samples),
18            delay_samples: initial_delay,
19            feedback: feedback.clamp(-0.99, 0.99), // Safety limiter untuk mencegah ledakan resonansi
20            mix: mix.clamp(0.0, 1.0),
21            interp: InterpolationType::Linear,
22        }
23    }
24
25    pub fn set_delay_samples(&mut self, delay: f32) {
26        self.delay_samples = delay;
27    }
28
29    pub fn set_feedback(&mut self, feedback: f32) {
30        self.feedback = feedback.clamp(-0.99, 0.99);
31    }
32
33    pub fn set_mix(&mut self, mix: f32) {
34        self.mix = mix.clamp(0.0, 1.0);
35    }
36
37    pub fn set_interpolation(&mut self, interp: InterpolationType) {
38        self.interp = interp;
39    }
40
41    /// Memproses 1 sample audio secara real-time.
42    ///
43    /// Efek ini membaca delay **sebelum** menulis sampel baru, sehingga memakai
44    /// varian `read_delay_before_push` agar nilai yang diambil tetap `x[n - D]`.
45    #[inline]
46    pub fn process_sample(&mut self, input: f32) -> f32 {
47        let delayed = self
48            .delay_line
49            .read_delay_before_push(self.delay_samples, self.interp);
50        let to_delay = input + delayed * self.feedback;
51        self.delay_line.push(to_delay);
52
53        // Dry/Wet mixing: y = (1 - mix) * dry + mix * wet
54        (1.0 - self.mix) * input + self.mix * delayed
55    }
56
57    /// Memproses seluruh buffer in-place
58    pub fn process_buffer(&mut self, buffer: &mut [f32]) {
59        for sample in buffer.iter_mut() {
60            *sample = self.process_sample(*sample);
61        }
62    }
63
64    pub fn clear(&mut self) {
65        self.delay_line.clear();
66    }
67}