euphony_dsp/
env.rs

1use crate::prelude::*;
2
3#[derive(Debug, Default, Node)]
4#[node(id = 200, module = "env")]
5#[input(target, default = 0.0, trigger = set_target)]
6#[input(duration, default = 0.01, trigger = set_duration)]
7#[input(value, default = 0.0, trigger = set_value)]
8pub struct Linear {
9    value: f64,
10    target: f64,
11    duration: f64,
12    step: f64,
13    samples: usize,
14}
15
16impl Linear {
17    #[inline]
18    fn set_value(&mut self, value: f64) {
19        self.value = value;
20        self.update();
21    }
22
23    #[inline]
24    fn set_target(&mut self, value: f64) {
25        self.target = value;
26        self.update();
27    }
28
29    #[inline]
30    fn set_duration(&mut self, value: f64) {
31        self.duration = value;
32        self.update();
33    }
34
35    fn update(&mut self) {
36        let diff = self.target - self.value;
37        let samples = (self.duration * Rate::VALUE).round();
38        self.samples = samples as _;
39        if self.samples > 0 {
40            self.step = diff / samples;
41        } else {
42            self.step = 0.0;
43        }
44    }
45
46    #[inline]
47    pub fn render(&mut self, output: &mut [f64]) {
48        for frame in output {
49            *frame = self.value;
50            if let Some(samples) = self.samples.checked_sub(1) {
51                self.samples = samples;
52                self.value += self.step;
53            } else {
54                self.value = self.target;
55            }
56        }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn linear_test() {
66        let mut env = Linear::new();
67        env.set_target(1.0);
68
69        let mut out = [0.0; 512];
70        env.render(&mut out[..]);
71        assert_eq!(out[0], 0.0);
72        assert_eq!(out[511], 1.0);
73        assert_ne!(out[1], 0.0);
74
75        env.set_target(0.0);
76        env.render(&mut out[..]);
77        assert_eq!(out[0], 1.0);
78        assert_eq!(out[511], 0.0);
79    }
80}