1use crate::sqrt4_to_pow4;
17use crate::{TrigSignal, Trigger};
18
19#[derive(Debug, Clone)]
45pub struct EnvState {
46 pub srate_ms: f32,
47 pub stage: u32,
48 pub phase: f32,
49 pub start: f32,
50 pub current: f32,
51}
52
53impl EnvState {
54 pub fn new() -> Self {
56 Self {
57 srate_ms: 44100.0 / 1000.0,
58 stage: std::u32::MAX,
59 phase: 0.0,
60 start: 0.0,
61 current: 0.0,
62 }
63 }
64
65 #[inline]
66 pub fn set_sample_rate(&mut self, srate: f32) {
67 self.srate_ms = srate / 1000.0;
68 }
69
70 #[inline]
71 pub fn trigger(&mut self) {
72 self.stage = 0;
73 }
74
75 #[inline]
76 pub fn is_running(&self) -> bool {
77 self.stage != std::u32::MAX
78 }
79
80 #[inline]
81 pub fn stop_immediately(&mut self) {
82 self.stage = std::u32::MAX;
83 }
84
85 pub fn reset(&mut self) {
86 self.stage = std::u32::MAX;
87 self.phase = 0.0;
88 self.start = 0.0;
89 self.current = 0.0;
90 }
91}
92
93#[macro_export]
98macro_rules! env_hold_stage {
99 ($state: expr, $stage_idx: expr, $time_ms: expr, $else: block) => {
100 if $state.stage == $stage_idx || $state.stage == ($stage_idx + 1) {
101 if $state.stage == $stage_idx {
102 $state.phase = 0.0;
103 $state.stage += 1;
104 $state.start = $state.current;
105 }
106
107 let inc = 1.0 / ($time_ms * $state.srate_ms);
108 $state.phase += inc;
109 if $state.phase >= 1.0 {
110 $state.stage += 1;
111 }
112 $state.current = $state.start;
113 } else $else
114 };
115}
116
117#[macro_export]
126macro_rules! env_target_stage {
127 ($state: expr, $stage_idx: expr, $time_ms: expr, $value: expr, $shape_fn: expr, $else: block) => {
128 if $state.stage == $stage_idx || $state.stage == ($stage_idx + 1) {
129 if $state.stage == $stage_idx {
130 $state.phase = 0.0;
131 $state.start = $state.current;
132 $state.stage += 1;
133 }
134
135 let inc = 1.0 / ($time_ms * $state.srate_ms).max(1.0);
136 $state.phase += inc;
137 if $state.phase >= 1.0 {
138 $state.stage += 1;
139 $state.current = $value;
140 } else {
141 let phase_shped = ($shape_fn)($state.phase);
142 $state.current = $state.start * (1.0 - phase_shped) + phase_shped * $value;
143 }
144 } else $else
145 };
146}
147
148#[macro_export]
158macro_rules! env_target_stage_lin_time_adj {
159 ($state: expr, $stage_idx: expr, $time_ms: expr, $src_value: expr, $value: expr, $shape_fn: expr, $else: block) => {
160 if $state.stage == $stage_idx || $state.stage == ($stage_idx + 1) {
161 if $state.stage == $stage_idx {
162 $state.phase = 0.0;
163 $state.start = $state.current;
164 $state.stage += 1;
165 }
166
167 let time_adj_factor = 1.0 - ($state.start - $src_value) / ($value - $src_value);
168 let inc = 1.0 / (time_adj_factor * $time_ms * $state.srate_ms).max(1.0);
169 $state.phase += inc;
170 if $state.phase >= 1.0 {
171 $state.stage += 1;
172 $state.current = $value;
173 } else {
174 let phase_shped = ($shape_fn)($state.phase);
175 $state.current = $state.start * (1.0 - phase_shped) + phase_shped * $value;
176 }
177 } else $else
178 };
179}
180
181#[macro_export]
186macro_rules! env_sustain_stage {
187 ($state: expr, $stage_idx: expr, $sustain_value: expr, $gate: expr, $else: block) => {
188 if $state.stage == $stage_idx {
189 if $gate < $crate::TRIG_LOW_THRES {
190 $state.stage += 1;
191 }
192
193 $state.current = $sustain_value;
194 } else $else
195 };
196}
197
198#[derive(Debug, Clone)]
221pub struct EnvRetrigAD {
222 state: EnvState,
223 trig: Trigger,
224 trig_sig: TrigSignal,
225}
226
227impl EnvRetrigAD {
228 pub fn new() -> Self {
230 Self { state: EnvState::new(), trig: Trigger::new(), trig_sig: TrigSignal::new() }
231 }
232
233 pub fn set_sample_rate(&mut self, srate: f32) {
235 self.state.set_sample_rate(srate);
236 self.trig_sig.set_sample_rate(srate);
237 }
238
239 pub fn reset(&mut self) {
241 self.state.reset();
242 self.trig_sig.reset();
243 self.trig.reset();
244 }
245
246 #[inline]
281 pub fn tick(
282 &mut self,
283 trigger: f32,
284 attack_ms: f32,
285 attack_shape: f32,
286 decay_ms: f32,
287 decay_shape: f32,
288 ) -> (f32, f32) {
289 if self.trig.check_trigger(trigger) {
290 self.state.trigger();
291 }
292
293 if self.state.is_running() {
294 env_target_stage_lin_time_adj!(
295 self.state,
296 0,
297 attack_ms,
298 0.0,
299 1.0,
300 |x: f32| sqrt4_to_pow4(x.clamp(0.0, 1.0), attack_shape),
301 {
302 env_target_stage!(
303 self.state,
304 2,
305 decay_ms,
306 0.0,
307 |x: f32| sqrt4_to_pow4(x.clamp(0.0, 1.0), decay_shape),
308 {
309 self.trig_sig.trigger();
310 self.state.stop_immediately();
311 }
312 );
313 }
314 );
315 }
316
317 (self.state.current, self.trig_sig.next())
318 }
319}
320
321#[derive(Debug, Clone, Copy)]
322pub struct EnvADSRParams {
323 pub attack_ms: f32,
324 pub attack_shape: f32,
325 pub decay_ms: f32,
326 pub decay_shape: f32,
327 pub sustain: f32,
328 pub release_ms: f32,
329 pub release_shape: f32,
330}
331
332impl Default for EnvADSRParams {
333 fn default() -> Self {
334 Self {
335 attack_ms: 0.0,
336 attack_shape: 0.0,
337 decay_ms: 0.0,
338 decay_shape: 0.0,
339 sustain: 0.0,
340 release_ms: 0.0,
341 release_shape: 0.0,
342 }
343 }
344}
345
346#[derive(Debug, Clone)]
347pub struct EnvRetrigADSR {
348 state: EnvState,
349 trig: Trigger,
350 trig_sig: TrigSignal,
351}
352
353impl EnvRetrigADSR {
354 pub fn new() -> Self {
356 Self { state: EnvState::new(), trig: Trigger::new(), trig_sig: TrigSignal::new() }
357 }
358
359 pub fn set_sample_rate(&mut self, srate: f32) {
361 self.state.set_sample_rate(srate);
362 self.trig_sig.set_sample_rate(srate);
363 }
364
365 pub fn reset(&mut self) {
367 self.state.reset();
368 self.trig_sig.reset();
369 self.trig.reset();
370 }
371
372 #[inline]
373 pub fn tick(
374 &mut self,
375 gate: f32,
376 params: &mut EnvADSRParams,
377 ) -> (f32, f32) {
378 if self.trig.check_trigger(gate) {
379 self.state.trigger();
380 }
381
382 if self.state.is_running() {
383 env_target_stage_lin_time_adj!(
385 self.state,
386 0,
387 params.attack_ms,
388 0.0,
389 1.0,
390 |x: f32| sqrt4_to_pow4(x.clamp(0.0, 1.0), params.attack_shape),
391 {
392 env_target_stage!(
394 self.state,
395 2,
396 params.decay_ms,
397 params.sustain,
398 |x: f32| sqrt4_to_pow4(x.clamp(0.0, 1.0), params.decay_shape),
399 {
400 env_sustain_stage!(
402 self.state,
403 4,
404 params.sustain,
405 gate,
406 {
407 env_target_stage!(
409 self.state,
410 5,
411 params.release_ms,
412 0.0,
413 |x: f32| sqrt4_to_pow4(x.clamp(0.0, 1.0), params.release_shape),
414 {
415 self.trig_sig.trigger();
416 self.state.stop_immediately();
417 }
418 );
419 }
420 );
421 }
422 );
423 }
424 );
425 }
426
427 (self.state.current, self.trig_sig.next())
428 }
429}
430
431#[cfg(test)]
432mod test {
433 use super::*;
434 use crate::assert_decimated_slope_feq;
435 use crate::assert_vec_feq;
436
437 #[test]
438 fn check_hold_stage() {
439 let mut state = EnvState::new();
440 state.trigger();
441
442 state.current = 0.6;
443 for _ in 0..88 {
444 env_hold_stage!(state, 0, 2.0, {});
445 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
446 assert!(state.stage == 1);
447 assert!(state.current > 0.5);
448 }
449
450 env_hold_stage!(state, 0, 2.0, {});
451 assert!(state.stage == 2);
452 assert!(state.current > 0.5);
453 }
454
455 #[test]
456 fn check_target_stage() {
457 let mut state = EnvState::new();
458 state.trigger();
459
460 for _ in 0..88 {
461 env_target_stage!(state, 0, 2.0, 0.6, |x| x, {});
462 assert!(state.stage == 1);
463 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
464 }
465
466 env_target_stage!(state, 0, 2.0, 0.6, |x| x, {});
467 assert!(state.stage == 2);
468 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
469 assert!(state.current >= 0.5999);
470 }
471
472 #[test]
473 fn check_very_short_target_stage() {
474 let mut state = EnvState::new();
475 state.trigger();
476
477 env_target_stage!(state, 0, 0.01, 0.6, |x| x, {});
478 assert!(state.stage == 2);
479 assert!(state.current == 0.6);
480 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
481 }
482
483 #[test]
484 fn check_short_target_stage() {
485 let mut state = EnvState::new();
486 state.trigger();
487
488 env_target_stage!(state, 0, 0.03, 0.6, |x| x, {});
489 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
490 assert!(state.stage == 1);
491 assert!((state.current - 0.4535).abs() < 0.0001);
492
493 env_target_stage!(state, 0, 0.03, 0.6, |x| x, {});
494 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
495 assert!(state.stage == 2);
496 assert!(state.current == 0.6);
497 }
498
499 #[test]
500 fn check_target_adj_stage() {
501 let mut state = EnvState::new();
502 state.trigger();
503
504 state.current = 0.0;
505
506 for _ in 0..88 {
507 env_target_stage_lin_time_adj!(state, 0, 2.0, 0.0, 0.6, |x| x, {});
508 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
509 assert!(state.stage == 1);
510 }
511
512 env_target_stage_lin_time_adj!(state, 0, 2.0, 0.0, 0.6, |x| x, {});
513 assert!(state.stage == 2);
514 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
515 assert!(state.current >= 0.5999);
516 }
517
518 #[test]
519 fn check_target_adj_stage_shortened() {
520 let mut state = EnvState::new();
521 state.trigger();
522
523 state.current = 0.3;
524
525 for _ in 0..44 {
526 env_target_stage_lin_time_adj!(state, 0, 2.0, 0.0, 0.6, |x| x, {});
527 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
528 assert!(state.stage == 1);
529 }
530
531 env_target_stage_lin_time_adj!(state, 0, 2.0, 0.0, 0.6, |x| x, {});
532 assert!(state.stage == 2);
533 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
534 assert!(state.current >= 0.5999);
535 }
536
537 #[test]
538 fn check_target_adj_stage_none() {
539 let mut state = EnvState::new();
540 state.trigger();
541
542 state.current = 0.6;
543
544 env_target_stage_lin_time_adj!(state, 0, 2.0, 0.0, 0.6, |x| x, {});
545 assert!(state.stage == 2);
546 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
547 assert!(state.current >= 0.5999);
548 }
549
550 #[test]
551 fn check_sustain_stage() {
552 let mut state = EnvState::new();
553 state.trigger();
554
555 env_sustain_stage!(state, 0, 0.5, 1.0, {});
556 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
557 assert!(state.stage == 0);
558 assert!((state.current - 0.5).abs() < 0.0001);
559
560 env_sustain_stage!(state, 0, 0.5, 1.0, {});
561 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
562 assert!(state.stage == 0);
563 assert!((state.current - 0.5).abs() < 0.0001);
564
565 env_sustain_stage!(state, 0, 0.5, 0.0, {});
566 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
567 assert!(state.stage == 1);
568 assert!((state.current - 0.5).abs() < 0.0001);
569 }
570
571 #[test]
572 fn check_sustain_stage_short() {
573 let mut state = EnvState::new();
574 state.trigger();
575
576 env_sustain_stage!(state, 0, 0.5, 0.0, {});
577 println!("V[{:6.4} / {}]: {:6.4}", state.phase, state.stage, state.current);
578 assert!(state.stage == 1);
579 assert!((state.current - 0.5).abs() < 0.0001);
580 }
581
582 #[test]
583 fn check_ahd_env() {
584 let mut state = EnvState::new();
585 state.set_sample_rate(48000.0);
586 state.trigger();
587
588 let attack_ms = 1.0;
589 let hold_ms = 2.0;
590 let delay_ms = 2.0;
591
592 let mut env_samples = vec![];
593 for _ in 0..(((48000.0 * (attack_ms + hold_ms + delay_ms)) / 1000.0) as usize) {
594 env_target_stage!(state, 0, attack_ms, 1.0, |x| x, {
595 env_hold_stage!(state, 2, hold_ms, {
596 env_target_stage!(state, 4, delay_ms, 0.0, |x| x, {});
597 });
598 });
599 env_samples.push(state.current);
600 }
601
602 assert_decimated_slope_feq!(env_samples[0..48], 4, vec![0.02083; 100]);
603 assert_decimated_slope_feq!(env_samples[48..146], 4, vec![0.0; 20]);
604 assert_decimated_slope_feq!(env_samples[146..240], 4, vec![-0.01041; 40]);
605 }
606
607 #[test]
608 fn check_env_ad() {
609 let mut env = EnvRetrigAD::new();
610
611 env.set_sample_rate(10.0);
612
613 let mut values = vec![];
614 let mut retrig_index = -1;
615 for i in 0..16 {
616 let (value, retrig) = env.tick(1.0, 1000.0, 0.5, 500.0, 0.5);
617 values.push(value);
618 if retrig > 0.0 {
619 retrig_index = i as i32;
620 }
621 }
622
623 assert_vec_feq!(
624 values,
625 vec![
626 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.70000005, 0.8000001, 0.9000001, 1.0, 0.8, 0.6,
627 0.39999998, 0.19999999, 0.0, 0.0
628 ]
629 );
630
631 assert_eq!(retrig_index, 15);
632 }
633
634 #[test]
635 fn check_env_ad_shaped() {
636 let mut env = EnvRetrigAD::new();
637
638 env.set_sample_rate(10.0);
639
640 let mut values = vec![];
641 let mut retrig_index = -1;
642 for i in 0..16 {
643 let (value, retrig) = env.tick(1.0, 1000.0, 0.7, 500.0, 0.3);
644 values.push(value);
645 if retrig > 0.0 {
646 retrig_index = i as i32;
647 }
648 }
649
650 assert_vec_feq!(
651 values,
652 vec![
653 0.2729822, 0.39777088, 0.49817806, 0.58596444, 0.6656854, 0.7396773, 0.809328,
654 0.8755418, 0.93894666, 1.0, 0.928, 0.79199994, 0.592, 0.32799995, 0.0, 0.0
655 ]
656 );
657
658 assert_eq!(retrig_index, 15);
659 }
660}