xmrs/
envelope.rs

1use alloc::vec::Vec;
2use serde::{Deserialize, Serialize};
3
4/// Envelope Point, frame for the abscissa, value for the ordinate
5#[derive(Default, Serialize, Deserialize, Copy, Clone, Debug)]
6pub struct EnvelopePoint {
7    /// Frame number of the point (X-coordinate)
8    pub frame: usize,
9    /// Value of the point (Y-coordinate) [0..1.0]
10    pub value: f32,
11}
12
13impl EnvelopePoint {
14    /// Linear interpolation between two envelope points
15    pub fn lerp(a: &EnvelopePoint, b: &EnvelopePoint, pos: usize) -> f32 {
16        if pos <= a.frame {
17            return a.value;
18        } else if pos >= b.frame {
19            return b.value;
20        } else {
21            let p: f32 = (pos - a.frame) as f32 / (b.frame - a.frame) as f32;
22            return a.value * (1.0 - p) + b.value * p;
23        }
24    }
25}
26
27/// Envelope
28#[derive(Default, Serialize, Deserialize, Clone, Debug)]
29pub struct Envelope {
30    pub enabled: bool,
31
32    pub point: Vec<EnvelopePoint>,
33
34    pub sustain_enabled: bool,
35    /// index in `point`
36    pub sustain_start_point: usize,
37    /// index in `point`
38    pub sustain_end_point: usize,
39
40    pub loop_enabled: bool,
41    /// index in `point`
42    pub loop_start_point: usize,
43    /// index in `point`
44    pub loop_end_point: usize,
45}
46
47impl Envelope {
48    pub fn loop_in_sustain(&self, frame: usize) -> usize {
49        if self.sustain_enabled {
50            let sustain_end = self.point[self.sustain_end_point].frame;
51            if frame > sustain_end {
52                return self.point[self.sustain_start_point].frame;
53            }
54        }
55        frame
56    }
57
58    pub fn loop_in_loop(&self, frame: usize) -> usize {
59        if self.loop_enabled {
60            let loop_end = self.point[self.loop_end_point].frame;
61            if frame > loop_end {
62                return self.point[self.loop_start_point].frame;
63            }
64        }
65        frame
66    }
67
68}