weresocool_core/generation/
timed_op.rs

1use crate::generation::Op4D;
2use num_rational::Rational64;
3use serde::{Deserialize, Serialize};
4use weresocool_ast::{NameSet, OscType, PointOp, ASR};
5use weresocool_instrument::Basis;
6use weresocool_shared::r_to_f64;
7
8#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
9pub enum EventType {
10    On,
11    Off,
12}
13
14#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)]
15pub struct TimedOp {
16    pub t: Rational64,
17    pub event_type: EventType,
18    pub voice: usize,
19    pub event: usize,
20    pub attack: Rational64,
21    pub decay: Rational64,
22    pub reverb: Rational64,
23    pub asr: ASR,
24    pub portamento: Rational64,
25    pub osc_type: OscType,
26    pub fm: Rational64,
27    pub fa: Rational64,
28    pub pm: Rational64,
29    pub pa: Rational64,
30    pub g: Rational64,
31    pub l: Rational64,
32    pub names: Vec<String>,
33}
34
35impl TimedOp {
36    pub fn to_op_4d(&self, basis: &Basis) -> Op4D {
37        let zero = Rational64::new(0, 1);
38        let is_silent = (self.fm == zero && self.fa < Rational64::new(20, 1)) || self.g == zero;
39        let y = if is_silent {
40            0.0
41        } else {
42            r_to_f64(basis.f).mul_add(r_to_f64(self.fm), r_to_f64(self.fa))
43        };
44        let z = if is_silent {
45            0.0
46        } else {
47            r_to_f64(basis.g) * r_to_f64(self.g)
48        };
49        Op4D {
50            l: r_to_f64(self.l) * r_to_f64(basis.l),
51            t: r_to_f64(self.t) * r_to_f64(basis.l),
52            x: ((r_to_f64(basis.p) + r_to_f64(self.pa)) * r_to_f64(self.pm)),
53            y: y.log10(),
54            z,
55            voice: self.voice,
56            event: self.event,
57            names: self.names.to_owned(),
58        }
59    }
60
61    #[allow(clippy::missing_const_for_fn)]
62    pub fn to_point_op(&self) -> PointOp {
63        PointOp {
64            fm: self.fm,
65            fa: self.fa,
66            pm: self.pm,
67            pa: self.pa,
68            g: self.g,
69            l: self.l,
70            reverb: Some(self.reverb),
71            attack: self.decay,
72            decay: self.decay,
73            asr: self.asr,
74            portamento: self.portamento,
75            osc_type: self.osc_type,
76            names: NameSet::new(),
77            filters: Vec::new(),
78        }
79    }
80
81    pub fn from_point_op(
82        point_op: &PointOp,
83        time: &mut Rational64,
84        voice: usize,
85        event: usize,
86    ) -> Self {
87        let timed_op = Self {
88            fm: point_op.fm,
89            fa: point_op.fa,
90            pm: point_op.pm,
91            pa: point_op.pa,
92            attack: point_op.attack,
93            osc_type: point_op.osc_type,
94            decay: point_op.decay,
95            reverb: point_op
96                .reverb
97                .unwrap_or_else(|| Rational64::from_integer(0)),
98            asr: point_op.asr,
99            portamento: point_op.portamento,
100            g: point_op.g,
101            l: point_op.l,
102            t: *time,
103            event_type: EventType::On,
104            voice,
105            event,
106            names: point_op.names.to_vec(),
107        };
108
109        *time += point_op.l;
110
111        timed_op
112    }
113}