PC Music Generator - a Virtual Modular Synthesizer
1use crate::devices::Device;
2use std::collections::{
3 BTreeMap,
4 BTreeSet,
5 VecDeque,
6};
7
8use super::{
9 CtlGraph,
10 DeviceId,
11};
12
13type NodeToDevice = BTreeMap<DeviceId, usize>;
14type OutputMap = BTreeMap<usize, ((DeviceId, u8), Vec<(DeviceId, u8)>)>;
15
16pub struct ByteCode {
17 devices: Vec<Box<dyn Device + Send + Sync>>,
18 node_to_device: NodeToDevice,
19 code: Vec<Op>,
20 sample: f32,
21}
22
23impl std::fmt::Debug for ByteCode {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("ByteCode")
26 .field("devices_count", &self.devices.len())
27 .field("node_to_device", &self.node_to_device)
28 .field("code", &self.code)
29 .field("sample", &self.sample)
30 .finish()
31 }
32}
33
34impl ByteCode {
35 pub fn update_param(&mut self, _pid @ (dev, param): (DeviceId, u8), value: f32) {
36 let d = if let Some(d) = self.node_to_device.get(&dev) {
37 *d
38 } else {
39 return;
40 };
41 let d = self.devices.get_mut(d).expect("No such device");
42 d.set_param_indexed(param, value)
43 }
44
45 pub fn sample(&mut self) -> f32 {
46 for op in &self.code {
47 match op {
48 Op::Sample(d, oid) => {
49 self.sample = self.devices[*d as usize].get_output_indexed(*oid);
50 }
51 Op::Output => break,
52 Op::Parametrise(d, pid) => {
53 self.devices[*d as usize].set_param_indexed(*pid, self.sample)
54 }
55 }
56 }
57 self.sample
58 }
59}
60
61#[derive(Debug)]
62enum Op {
63 Sample(u16, u8),
64 Output,
65 Parametrise(u16, u8),
66}
67pub fn compile(ctl_graph: &CtlGraph, sample_rate: f32) -> ByteCode {
68 let mut graph = ctl_graph.graph.clone();
69 let mut code = VecDeque::new();
70 let mut node_to_device = BTreeMap::new();
71 let mut devices = Vec::new();
72 let mut output_params: OutputMap = BTreeMap::new();
73
74 let mut last = ctl_graph.end;
75 let mut counter = 0;
76
77 let mut prevs = BTreeSet::new();
78 while let Some((dev, params)) = graph.remove(&last) {
79 let device_idx = dev.make()(&mut devices, sample_rate);
80 node_to_device.insert(last, device_idx);
81
82 for (pid, params) in params.into_iter().enumerate() {
83 if let Some((source_did, source_pid)) = params {
84 prevs.insert(source_did);
85
86 let (_, to_parametrise) = output_params
87 .entry(counter)
88 .or_insert(((source_did, source_pid), Vec::new()));
89 counter += 1;
90
91 to_parametrise.push((last, pid as u8));
92 }
93 }
94 if let Some(new) = prevs.pop_first() {
95 last = new;
96 } else {
97 break;
98 }
99 }
100
101 for ((nid, oid), params) in output_params.into_values().rev() {
102 code.push_back(Op::Sample(node_to_device[&nid] as u16, oid));
103 for (puid, pid) in params {
104 code.push_back(Op::Parametrise(node_to_device[&puid] as u16, pid));
105 }
106 }
107
108 code.push_back(Op::Output);
109
110 let code = code.into();
111 ByteCode {
112 devices,
113 node_to_device,
114 code,
115 sample: 0.0,
116 }
117}