1use crate::complex::C64;
4use crate::env::{NodeId, ParamId};
5use crate::origin::Origin;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8pub enum Var {
9 T,
10 F,
11}
12
13impl Var {
14 pub fn as_str(self) -> &'static str {
15 match self {
16 Var::T => "t",
17 Var::F => "f",
18 }
19 }
20}
21
22#[derive(Clone, Debug, PartialEq)]
24pub struct ClosedForm {
25 pub var: Var,
26 pub body: Body,
27 pub origin: Origin,
28}
29
30#[derive(Clone, Debug, PartialEq)]
31pub struct Part {
32 pub origin: Origin,
33 pub body: Box<Body>,
34}
35
36impl Part {
37 pub fn new(origin: Origin, body: Body) -> Part {
38 Part {
39 origin,
40 body: Box::new(body),
41 }
42 }
43
44 pub fn bare(body: Body) -> Part {
45 Part::new(Origin::UNKNOWN, body)
46 }
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum Edge {
52 NegInf,
53 At(u64),
54 PosInf,
55}
56
57impl Ord for Edge {
59 fn cmp(&self, other: &Edge) -> std::cmp::Ordering {
60 self.value().total_cmp(&other.value())
61 }
62}
63
64impl PartialOrd for Edge {
65 fn partial_cmp(&self, other: &Edge) -> Option<std::cmp::Ordering> {
66 Some(self.cmp(other))
67 }
68}
69
70impl Edge {
71 pub fn at(x: f64) -> Edge {
72 match x {
73 x if x == f64::NEG_INFINITY => Edge::NegInf,
74 x if x == f64::INFINITY => Edge::PosInf,
75 x => Edge::At(crate::complex::canonical(x)),
76 }
77 }
78
79 pub fn value(self) -> f64 {
80 match self {
81 Edge::NegInf => f64::NEG_INFINITY,
82 Edge::At(bits) => f64::from_bits(bits),
83 Edge::PosInf => f64::INFINITY,
84 }
85 }
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq)]
89pub enum Unary {
90 Sin,
91 Cos,
92 Exp,
93 Tanh,
94 Sat,
95 Abs,
96 Log,
97 Sqrt,
98 Step,
100}
101
102impl Unary {
103 pub fn name(self) -> &'static str {
104 match self {
105 Unary::Sin => "sin",
106 Unary::Cos => "cos",
107 Unary::Exp => "exp",
108 Unary::Tanh => "tanh",
109 Unary::Sat => "sat",
110 Unary::Abs => "abs",
111 Unary::Log => "log",
112 Unary::Sqrt => "sqrt",
113 Unary::Step => "step",
114 }
115 }
116
117 pub const ALL: &'static [Unary] = &[
118 Unary::Sin,
119 Unary::Cos,
120 Unary::Exp,
121 Unary::Tanh,
122 Unary::Sat,
123 Unary::Abs,
124 Unary::Log,
125 Unary::Sqrt,
126 Unary::Step,
127 ];
128
129 pub fn from_name(name: &str) -> Option<Unary> {
130 Unary::ALL.iter().copied().find(|u| u.name() == name)
131 }
132
133 pub fn is_closed(self) -> bool {
135 matches!(self, Unary::Sin | Unary::Cos | Unary::Exp)
136 }
137}
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq)]
140pub enum Fold {
141 Max,
142 Min,
143 Mod,
144}
145
146#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
147pub struct IndexId(pub u32);
148
149#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum Bound {
151 Finite(i64),
152 Infinite,
153}
154
155#[derive(Clone, Debug, PartialEq)]
157pub struct Series {
158 pub index: IndexId,
159 pub lo: i64,
160 pub hi: Bound,
161 pub term: Part,
162}
163
164#[derive(Clone, Copy, Debug, PartialEq)]
165pub struct Mode {
166 pub omega: f64,
167 pub tau: f64,
168 pub amp: f64,
169 pub phase: f64,
170}
171
172#[derive(Clone, Copy, Debug, PartialEq)]
173pub enum Excitation {
174 HammerPulse { f0: f64, t0: f64, contact: f64 },
175 Impulse { t0: f64 },
176}
177
178#[derive(Clone, Debug, PartialEq)]
179pub struct ModalBank {
180 pub modes: Vec<Mode>,
181 pub excite: Excitation,
182}
183
184#[derive(Clone, Debug, PartialEq)]
186pub struct Rational {
187 pub zeros: Vec<C64>,
188 pub poles: Vec<C64>,
189 pub gain: C64,
190}
191
192#[derive(Clone, Debug, PartialEq)]
193pub enum Body {
194 Const(C64),
195 Line,
196 Index(IndexId),
197 Keyed {
199 seed: u64,
200 of: Part,
201 },
202 Param(ParamId),
203 Node(NodeId),
204 Add(Vec<Part>),
205 Mul(Vec<Part>),
206 Div(Part, Part),
207 Pow(Part, i32),
208 Apply(Unary, Part),
209 Fold(Fold, Vec<Part>),
210 Delta {
211 at: Part,
212 order: u16,
213 },
214 Pv(Part),
215 Shift {
216 by: f64,
217 of: Part,
218 },
219 Warp {
222 at: Part,
223 of: Part,
224 },
225 Deriv {
226 order: u16,
227 of: Part,
228 },
229 Crop {
231 of: Part,
232 l: Edge,
233 r: Edge,
234 rise: f64,
235 fall: f64,
236 },
237 Join(Vec<Part>),
238 Channel(Part, u8),
239 Rational(Rational),
240 Series(Box<Series>),
241 Modal(ModalBank),
242 Run(Box<crate::run::Run>),
243}
244
245pub fn children(f: &Body) -> Vec<&Part> {
248 match f {
249 Body::Const(_)
250 | Body::Line
251 | Body::Index(_)
252 | Body::Param(_)
253 | Body::Node(_)
254 | Body::Rational(_)
255 | Body::Modal(_)
256 | Body::Run(_) => Vec::new(),
257 Body::Keyed { of, .. } => vec![of],
258 Body::Add(parts) | Body::Mul(parts) | Body::Join(parts) | Body::Fold(_, parts) => {
259 parts.iter().collect()
260 }
261 Body::Div(a, b) | Body::Warp { at: a, of: b } => vec![a, b],
262 Body::Pow(of, _)
263 | Body::Apply(_, of)
264 | Body::Pv(of)
265 | Body::Channel(of, _)
266 | Body::Delta { at: of, .. }
267 | Body::Shift { of, .. }
268 | Body::Deriv { of, .. }
269 | Body::Crop { of, .. } => vec![of],
270 Body::Series(s) => vec![&s.term],
271 }
272}
273
274pub fn map_children(f: &Body, mut g: impl FnMut(&Part) -> Part) -> Body {
275 let one = |p: &Part, g: &mut dyn FnMut(&Part) -> Part| g(p);
276 match f {
277 Body::Const(_)
278 | Body::Line
279 | Body::Index(_)
280 | Body::Param(_)
281 | Body::Node(_)
282 | Body::Rational(_)
283 | Body::Modal(_)
284 | Body::Run(_) => f.clone(),
285 Body::Keyed { seed, of } => Body::Keyed {
286 seed: *seed,
287 of: one(of, &mut g),
288 },
289 Body::Add(parts) => Body::Add(parts.iter().map(g).collect()),
290 Body::Mul(parts) => Body::Mul(parts.iter().map(g).collect()),
291 Body::Join(parts) => Body::Join(parts.iter().map(g).collect()),
292 Body::Fold(op, parts) => Body::Fold(*op, parts.iter().map(g).collect()),
293 Body::Div(a, b) => Body::Div(g(a), g(b)),
294 Body::Warp { at, of } => Body::Warp {
295 at: g(at),
296 of: g(of),
297 },
298 Body::Pow(of, n) => Body::Pow(g(of), *n),
299 Body::Apply(op, of) => Body::Apply(*op, g(of)),
300 Body::Pv(of) => Body::Pv(g(of)),
301 Body::Channel(of, k) => Body::Channel(g(of), *k),
302 Body::Delta { at, order } => Body::Delta {
303 at: g(at),
304 order: *order,
305 },
306 Body::Shift { by, of } => Body::Shift { by: *by, of: g(of) },
307 Body::Deriv { order, of } => Body::Deriv {
308 order: *order,
309 of: g(of),
310 },
311 Body::Crop {
312 of,
313 l,
314 r,
315 rise,
316 fall,
317 } => Body::Crop {
318 of: g(of),
319 l: *l,
320 r: *r,
321 rise: *rise,
322 fall: *fall,
323 },
324 Body::Series(s) => Body::Series(Box::new(Series {
325 term: g(&s.term),
326 ..(**s).clone()
327 })),
328 }
329}
330
331pub fn shift_line(f: &Body, by: f64) -> Body {
334 let walk = |p: &Part| Part::new(p.origin, shift_line(&p.body, by));
335 match f {
336 Body::Line => Body::Add(vec![
337 Part::bare(Body::Line),
338 Part::bare(Body::Const(crate::complex::C64::real(-by))),
339 ]),
340 Body::Crop {
341 of,
342 l,
343 r,
344 rise,
345 fall,
346 } => Body::Crop {
347 of: walk(of),
348 l: Edge::at(l.value() + by),
349 r: Edge::at(r.value() + by),
350 rise: *rise,
351 fall: *fall,
352 },
353 Body::Warp { at, of } => Body::Warp {
354 at: walk(at),
355 of: of.clone(),
356 },
357 other => map_children(other, walk),
358 }
359}
360
361pub fn read_at(f: &Body, at: &Body) -> Body {
363 match f {
364 Body::Line => at.clone(),
365 Body::Crop { .. } => Body::Warp {
366 at: Part::bare(at.clone()),
367 of: Part::bare(f.clone()),
368 },
369 Body::Warp { at: inner, of } => Body::Warp {
370 at: Part::new(inner.origin, read_at(&inner.body, at)),
371 of: of.clone(),
372 },
373 other => map_children(other, |p| Part::new(p.origin, read_at(&p.body, at))),
374 }
375}
376
377pub fn shifts_opaquely(f: &Body) -> bool {
379 matches!(
380 f,
381 Body::Node(_) | Body::Param(_) | Body::Rational(_) | Body::Modal(_) | Body::Run(_)
382 ) || children(f).iter().any(|p| shifts_opaquely(&p.body))
383}