weresocool_core/generation/
timed_op.rs1use 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}