synthahol_dx7/
algorithms.rs

1//! Routing between operators.
2
3use std::fmt::{Display, Formatter};
4
5use lazy_static::lazy_static;
6
7// use lazy_static::lazy_static;
8use crate::{OperatorId, Preset};
9
10/// The destination of an operator
11///
12/// An operator ID can be converted to an output:
13///
14/// ```
15/// use synthahol_dx7::Output;
16/// assert_eq!(Output::from(2), Some(Output::Op3));
17/// ```
18#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
19#[repr(u8)]
20pub enum Output {
21    // Operators
22    Op1 = 0,
23    Op2,
24    Op3,
25    Op4,
26    Op5,
27    Op6,
28
29    /// Amplifier output
30    Amplifier,
31}
32
33impl Output {
34    pub fn is_operator(&self) -> bool {
35        self != &Output::Amplifier
36    }
37
38    pub fn from(operator_id: OperatorId) -> Option<Output> {
39        use Output::*;
40        match operator_id {
41            0 => Some(Op1),
42            1 => Some(Op2),
43            2 => Some(Op3),
44            3 => Some(Op4),
45            4 => Some(Op5),
46            5 => Some(Op6),
47            _ => None,
48        }
49    }
50}
51
52impl Display for Output {
53    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
54        use Output::*;
55        let msg = match self {
56            Op1 => "Operator 1",
57            Op2 => "Operator 2",
58            Op3 => "Operator 3",
59            Op4 => "Operator 4",
60            Op5 => "Operator 5",
61            Op6 => "Operator 6",
62            Amplifier => "Amplifier",
63        };
64        f.write_str(msg)
65    }
66}
67
68pub type AlgorithmId = usize;
69
70/// Routing between the operators and amplifier
71pub struct Algorithm {
72    routing_by_operator: [Vec<Output>; Preset::OPERATOR_COUNT],
73}
74
75impl Algorithm {
76    pub const fn new(operators: [Vec<Output>; Preset::OPERATOR_COUNT]) -> Self {
77        Self {
78            routing_by_operator: operators,
79        }
80    }
81
82    /// Returns `true` if the operator exists and is a carrier
83    pub fn is_carrier(&self, operator_id: OperatorId) -> bool {
84        let routing = self.routing(operator_id);
85        routing == Some(&vec![Output::Amplifier])
86    }
87
88    /// Returns `true` if the operator exists and feeds back into itself.
89    pub fn is_feedback(&self, operator_id: OperatorId) -> bool {
90        let output = Output::from(operator_id);
91        let routing = self.routing(operator_id);
92        output
93            .and_then(|output| routing.map(|routing| routing.contains(&output)))
94            .unwrap_or_default()
95    }
96
97    pub fn routing(&self, operator_id: OperatorId) -> Option<&Vec<Output>> {
98        self.routing_by_operator.get(operator_id as usize)
99    }
100}
101
102lazy_static! {
103static ref ALGORITHMS: [Algorithm; Algorithms::COUNT] = {
104    use Output::*;
105    [
106        Algorithm::new( [
107            vec![Amplifier],
108            vec![Op1],
109            vec![Amplifier],
110            vec![Op3],
111            vec![Op4],
112            vec![Op5, Op6],
113        ]), // 1
114        Algorithm::new( [
115            vec![Amplifier],
116            vec![Op1, Op2],
117            vec![Amplifier],
118            vec![Op3],
119            vec![Op4],
120            vec![Op5],
121        ]),
122        Algorithm::new( [
123            vec![Amplifier],
124            vec![Op1],
125            vec![Op2],
126            vec![Amplifier],
127            vec![Op4],
128            vec![Op5, Op6],
129        ]),
130        Algorithm::new( [
131            vec![Amplifier],
132            vec![Op1],
133            vec![Op2],
134            vec![Amplifier],
135            vec![Op4],
136            vec![Op5, Amplifier],
137        ]),
138        Algorithm::new( [
139            vec![Amplifier],
140            vec![Op1],
141            vec![Amplifier],
142            vec![Op3],
143            vec![Amplifier],
144            vec![Op5, Op6],
145        ]), // 5
146Algorithm::new(        [
147            vec![Amplifier],
148            vec![Op1],
149            vec![Amplifier],
150            vec![Op3],
151            vec![Amplifier],
152            vec![Op5, Amplifier],
153        ]),
154Algorithm::new(        [
155            vec![Amplifier],
156            vec![Op1],
157            vec![Amplifier],
158            vec![Op3],
159            vec![Op3],
160            vec![Op5, Op6],
161        ]),
162Algorithm::new(        [
163            vec![Amplifier],
164            vec![Op1],
165            vec![Amplifier],
166            vec![Op3, Op4],
167            vec![Op3],
168            vec![Op5],
169        ]),
170Algorithm::new(        [
171            vec![Amplifier],
172            vec![Op1, Op2],
173            vec![Amplifier],
174            vec![Op3],
175            vec![Op3],
176            vec![Op5],
177        ]),
178Algorithm::new(        [
179            vec![Amplifier],
180            vec![Op1],
181            vec![Op2, Op3],
182            vec![Amplifier],
183            vec![Op4],
184            vec![Op4],
185        ]), // 10
186Algorithm::new(        [
187            vec![Amplifier],
188            vec![Op1],
189            vec![Op2],
190            vec![Amplifier],
191            vec![Op4],
192            vec![Op4, Op6],
193        ]),
194Algorithm::new(        [
195            vec![Amplifier],
196            vec![Op1, Op2],
197            vec![Amplifier],
198            vec![Op3],
199            vec![Op3],
200            vec![Op3],
201        ]),
202Algorithm::new(        [
203            vec![Amplifier],
204            vec![Op1],
205            vec![Amplifier],
206            vec![Op3],
207            vec![Op3],
208            vec![Op3, Op6],
209        ]),
210Algorithm::new(        [
211            vec![Amplifier],
212            vec![Op1],
213            vec![Amplifier],
214            vec![Op3],
215            vec![Op4],
216            vec![Op4, Op6],
217        ]),
218Algorithm::new(        [
219            vec![Amplifier],
220            vec![Op1, Op2],
221            vec![Amplifier],
222            vec![Op3],
223            vec![Op4],
224            vec![Op4],
225        ]), // 15
226Algorithm::new(        [
227            vec![Amplifier],
228            vec![Op1],
229            vec![Op1],
230            vec![Op3],
231            vec![Op1],
232            vec![Op5, Op6],
233        ]),
234Algorithm::new(        [
235            vec![Amplifier],
236            vec![Op1, Op2],
237            vec![Op1],
238            vec![Op3],
239            vec![Op1],
240            vec![Op5],
241        ]),
242Algorithm::new(        [
243            vec![Amplifier],
244            vec![Op1],
245            vec![Op1, Op3],
246            vec![Op1],
247            vec![Op4],
248            vec![Op5],
249        ]),
250Algorithm::new(        [
251            vec![Amplifier],
252            vec![Op1],
253            vec![Op2],
254            vec![Amplifier],
255            vec![Amplifier],
256            vec![Op4, Op5, Op6],
257        ]),
258Algorithm::new(        [
259            vec![Amplifier],
260            vec![Amplifier],
261            vec![Op1, Op2, Op3],
262            vec![Amplifier],
263            vec![Op4],
264            vec![Op4],
265        ]), // 20
266Algorithm::new(        [
267            vec![Amplifier],
268            vec![Amplifier],
269            vec![Op1, Op2, Op3],
270            vec![Amplifier],
271            vec![Amplifier],
272            vec![Op4, Op5],
273        ]),
274Algorithm::new(        [
275            vec![Amplifier],
276            vec![Op1],
277            vec![Amplifier],
278            vec![Amplifier],
279            vec![Amplifier],
280            vec![Op3, Op4, Op5, Op6],
281        ]),
282Algorithm::new(        [
283            vec![Amplifier],
284            vec![Amplifier],
285            vec![Op2],
286            vec![Amplifier],
287            vec![Amplifier],
288            vec![Op4, Op5, Op6],
289        ]),
290Algorithm::new(        [
291            vec![Amplifier],
292            vec![Amplifier],
293            vec![Amplifier],
294            vec![Amplifier],
295            vec![Amplifier],
296            vec![Op3, Op4, Op5, Op6],
297        ]),
298Algorithm::new(        [
299            vec![Amplifier],
300            vec![Amplifier],
301            vec![Amplifier],
302            vec![Amplifier],
303            vec![Amplifier],
304            vec![Op4, Op5, Op6],
305        ]), // 25
306Algorithm::new(        [
307            vec![Amplifier],
308            vec![Amplifier],
309            vec![Op2],
310            vec![Amplifier],
311            vec![Op4],
312            vec![Op4, Op6],
313        ]),
314Algorithm::new(        [
315            vec![Amplifier],
316            vec![Amplifier],
317            vec![Op2, Op3],
318            vec![Amplifier],
319            vec![Op4],
320            vec![Op4],
321        ]),
322Algorithm::new(        [
323            vec![Amplifier],
324            vec![Op1],
325            vec![Amplifier],
326            vec![Op3],
327            vec![Op4, Op5],
328            vec![Amplifier],
329        ]),
330Algorithm::new(        [
331            vec![Amplifier],
332            vec![Amplifier],
333            vec![Amplifier],
334            vec![Op3],
335            vec![Amplifier],
336            vec![Op5, Op6],
337        ]),
338Algorithm::new(        [
339            vec![Amplifier],
340            vec![Amplifier],
341            vec![Amplifier],
342            vec![Op3],
343            vec![Op4, Op5],
344            vec![Amplifier],
345        ]), // 30
346Algorithm::new(        [
347            vec![Amplifier],
348            vec![Amplifier],
349            vec![Amplifier],
350            vec![Amplifier],
351            vec![Amplifier],
352            vec![Op5, Op6],
353        ]),
354Algorithm::new(        [
355            vec![Amplifier],
356            vec![Amplifier],
357            vec![Amplifier],
358            vec![Amplifier],
359            vec![Amplifier],
360            vec![Amplifier, Op6],
361        ]), // 32
362    ]
363};
364}
365
366pub struct Algorithms;
367
368impl Algorithms {
369    const COUNT: usize = 32;
370
371    pub fn all() -> &'static [Algorithm; Algorithms::COUNT] {
372        &ALGORITHMS
373    }
374
375    pub fn get(id: AlgorithmId) -> Option<&'static Algorithm> {
376        ALGORITHMS.get(id)
377    }
378}
379
380#[cfg(test)]
381mod tests {
382    use std::collections::HashSet;
383
384    use super::*;
385
386    #[test]
387    fn carrier() {
388        let algorithm = Algorithms::get(0).unwrap();
389        assert!(algorithm.is_carrier(0));
390        assert!(!algorithm.is_carrier(1));
391        assert!(algorithm.is_carrier(2));
392        assert!(!algorithm.is_carrier(3));
393        assert!(!algorithm.is_carrier(5));
394        assert!(!algorithm.is_carrier(6));
395    }
396
397    #[test]
398    fn feedback() {
399        let algorithm = Algorithms::get(0).unwrap();
400        assert!(!algorithm.is_feedback(0));
401        assert!(algorithm.is_feedback(5));
402    }
403
404    #[test]
405    fn routing() {
406        // Every operator must have an output and not have duplicates
407        for (algorithm_index, algorithm) in Algorithms::all().iter().enumerate() {
408            for operator_id in 0..ALGORITHMS[0].routing_by_operator.len() {
409                let routing = algorithm
410                    .routing(operator_id as OperatorId)
411                    .expect("every operator has a routing");
412                let unique: HashSet<&Output> = routing.into_iter().collect();
413                assert_eq!(
414                    routing.len(),
415                    unique.len(),
416                    "Algorithm index {algorithm_index} contains duplicates"
417                );
418                assert!(
419                    !routing.is_empty(),
420                    "Algorithm index {algorithm_index} does not have an output for operator ID {operator_id}"
421                );
422            }
423        }
424    }
425}