synthahol_phase_plant/modulator/
envelope.rs1use std::any::Any;
4
5use uom::si::ratio::{percent, ratio};
6
7use super::*;
8
9#[derive(Debug, PartialEq)]
10pub struct EnvelopeModulator {
11 pub envelope: Envelope,
12 pub depth: Ratio,
13
14 pub trigger_threshold: Ratio,
16 pub note_trigger_mode: NoteTriggerMode,
17 pub seamless: bool,
18}
19
20impl Default for EnvelopeModulator {
21 fn default() -> Self {
22 Self {
23 envelope: Default::default(),
24 depth: Ratio::new::<percent>(100.0),
25 note_trigger_mode: NoteTriggerMode::Auto,
26 trigger_threshold: Ratio::new::<ratio>(0.5),
27 seamless: false,
28 }
29 }
30}
31
32impl Modulator for EnvelopeModulator {
33 fn as_block(&self) -> ModulatorBlock {
34 self.into()
35 }
36
37 fn box_eq(&self, other: &dyn Any) -> bool {
38 other
39 .downcast_ref::<Self>()
40 .map_or(false, |other| self == other)
41 }
42
43 fn mode(&self) -> ModulatorMode {
44 ModulatorMode::Envelope
45 }
46}
47
48#[cfg(test)]
49mod test {
50 use approx::assert_relative_eq;
51 use uom::si::ratio::percent;
52 use uom::si::time::second;
53
54 use crate::test::read_modulator_preset;
55
56 use super::*;
57
58 #[test]
59 fn init() {
60 for file in &["envelope-1.8.13.phaseplant", "envelope-2.1.0.phaseplant"] {
61 let preset = read_modulator_preset("envelope", file).unwrap();
62 assert_eq!(preset.modulator_containers.len(), 1);
63 let container = preset.modulator_container(0).unwrap();
64 assert_eq!(container.id, 0);
65 assert!(container.enabled);
66 assert!(!container.minimized);
67 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
68 assert_relative_eq!(modulator.depth.get::<percent>(), 100.0);
69 assert_eq!(modulator.trigger_threshold.get::<percent>(), 50.0);
70 assert_eq!(modulator.note_trigger_mode, NoteTriggerMode::Auto);
71 assert!(!modulator.seamless);
72 let envelope = &modulator.envelope;
73 assert_relative_eq!(envelope.delay.get::<second>(), 0.0);
74 assert_relative_eq!(envelope.attack.get::<second>(), 0.010, epsilon = 0.00001);
75 assert_relative_eq!(envelope.attack_curve, 0.0);
76 assert_relative_eq!(envelope.hold.get::<second>(), 0.0);
77 assert_relative_eq!(envelope.decay.get::<second>(), 0.100, epsilon = 0.0001);
78 assert_relative_eq!(envelope.decay_falloff, 0.0);
79 assert_relative_eq!(envelope.sustain.get::<percent>(), 1.0);
80 assert_relative_eq!(envelope.release.get::<second>(), 0.100, epsilon = 0.0001);
81 assert_relative_eq!(envelope.release_falloff, 0.0);
82 }
83 }
84
85 #[test]
86 fn eleven_to_sixteen() {
87 let preset =
88 read_modulator_preset("envelope", "envelope-11to16-1.8.13.phaseplant").unwrap();
89 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
90 assert_relative_eq!(modulator.depth.get::<percent>(), 100.0);
91 let envelope = &modulator.envelope;
92 assert_relative_eq!(envelope.delay.get::<second>(), 0.011, epsilon = 0.0001);
93 assert_relative_eq!(envelope.attack.get::<second>(), 0.012, epsilon = 0.0001);
94 assert_relative_eq!(envelope.attack_curve, 0.0);
95 assert_relative_eq!(envelope.hold.get::<second>(), 0.013, epsilon = 0.0001);
96 assert_relative_eq!(envelope.decay.get::<second>(), 0.014, epsilon = 0.0001);
97 assert_relative_eq!(envelope.decay_falloff, 0.0);
98 assert_relative_eq!(envelope.sustain.get::<percent>(), 0.15, epsilon = 0.0001);
99 assert_relative_eq!(envelope.release.get::<second>(), 0.016, epsilon = 0.0001);
100 assert_relative_eq!(envelope.release_falloff, 0.0);
101 }
102
103 #[test]
104 fn curves() {
105 let preset =
106 read_modulator_preset("envelope", "envelope-curves25-50-75-1.8.13.phaseplant").unwrap();
107 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
108 assert_relative_eq!(modulator.envelope.attack_curve, 0.25);
109 assert_relative_eq!(modulator.envelope.decay_falloff, 0.50);
110 assert_relative_eq!(modulator.envelope.release_falloff, 0.75);
111 }
112
113 #[test]
114 fn disabled() {
115 let preset =
116 read_modulator_preset("envelope", "envelope-disabled-1.8.13.phaseplant").unwrap();
117 let container = preset.modulator_container(0).unwrap();
118 assert!(!container.enabled);
119 }
120
121 #[test]
122 fn depth() {
123 let preset =
124 read_modulator_preset("envelope", "envelope-minimized-depth50-1.8.13.phaseplant")
125 .unwrap();
126 let container = preset.modulator_container(0).unwrap();
127 assert!(container.enabled);
128 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
129 assert_relative_eq!(modulator.depth.get::<percent>(), 50.0);
130 }
131
132 #[test]
133 fn note_trigger() {
134 let preset =
135 read_modulator_preset("envelope", "envelope-note_trigger_always-2.1.0.phaseplant")
136 .unwrap();
137 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
138 assert_eq!(modulator.note_trigger_mode, NoteTriggerMode::Always);
139 }
140
141 #[test]
142 fn seamless() {
143 let preset =
144 read_modulator_preset("envelope", "envelope-seamless-2.1.0.phaseplant").unwrap();
145 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
146 assert!(modulator.seamless);
147 }
148
149 #[test]
150 fn trigger_threshold() {
151 let preset =
152 read_modulator_preset("envelope", "envelope-trigger_threshold25-2.1.0.phaseplant")
153 .unwrap();
154 let modulator: &EnvelopeModulator = preset.modulator(0).unwrap();
155 assert_eq!(modulator.trigger_threshold.get::<percent>(), 25.0);
156 }
157}