PC Music Generator - a Virtual Modular Synthesizer
at main 225 lines 5.7 kB view raw
1use std::{ 2 collections::BTreeMap, 3 ops::{ 4 Index, 5 IndexMut, 6 }, 7}; 8 9use slotmap::{ 10 new_key_type, 11 SecondaryMap, 12 SlotMap, 13}; 14 15use crate::devices::description::DeviceKind; 16 17use self::modules::Module; 18 19pub mod compiled; 20pub mod modules; 21 22new_key_type! { 23 pub struct ModuleId; 24 pub struct DeviceId; 25 pub struct VisualId; 26 27 pub struct InputId; 28 pub struct OutputId; 29} 30 31#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 32pub enum Connector { 33 /// Connected to an input of a device 34 In(InputId), 35 /// Connected to an output of a device 36 Out(OutputId), 37} 38 39#[derive(Default, Debug)] 40pub struct Graph { 41 pub modules: SlotMap<ModuleId, Module>, 42 pub devices: SlotMap<DeviceId, DeviceKind>, 43 44 /// What device a given input belongs o 45 pub ins: SlotMap<InputId, (DeviceId, u8)>, 46 /// What device a given output belongs to 47 pub outs: SlotMap<OutputId, (DeviceId, u8)>, 48 /// What ins a given device has 49 pub dev_ins: SecondaryMap<DeviceId, Vec<InputId>>, 50 /// What outs a given device has 51 pub dev_outs: SecondaryMap<DeviceId, Vec<OutputId>>, 52 /// Connections linking node's inputs back to outputs 53 pub cables: SecondaryMap<InputId, OutputId>, 54} 55 56type CtlGraphGraph = BTreeMap<DeviceId, (DeviceKind, [Option<(DeviceId, u8)>; 16])>; 57 58#[derive(Debug, Default)] 59pub struct CtlGraph { 60 pub end: DeviceId, 61 pub dev_map: BTreeMap<Connector, (DeviceId, u8)>, 62 pub midis: SecondaryMap<OutputId, (DeviceId, u8)>, 63 graph: CtlGraphGraph, 64} 65 66struct Walker { 67 dev_map: BTreeMap<Connector, (DeviceId, u8)>, 68 midis: SecondaryMap<OutputId, (DeviceId, u8)>, 69 /// from node closer to output backwards 70 graph: CtlGraphGraph, 71} 72 73impl Walker { 74 fn walk(to: InputId, graph: &Graph) -> CtlGraph { 75 let end = graph.ins[to].0; 76 let mut this = Self { 77 dev_map: Default::default(), 78 midis: Default::default(), 79 graph: Default::default(), 80 }; 81 82 this.walk_input(to, graph); 83 84 let Walker { 85 dev_map, 86 midis, 87 graph, 88 } = this; 89 90 CtlGraph { 91 end, 92 dev_map, 93 midis, 94 graph, 95 } 96 } 97 98 fn walk_input(&mut self, input: InputId, graph: &Graph) { 99 let (dev, param) = graph[input]; 100 let dev_desc = graph.devices[dev]; 101 println!("Walking input {param} for {dev_desc:?}"); 102 103 self.dev_map.insert(Connector::In(input), (dev, param)); 104 105 let prev = graph.cables.get(input).copied().map(|out| graph[out]); 106 if let Some((prev_dev, _)) = prev { 107 // for each of this device's previous devices' outputs 108 let prevs = graph 109 .dev_outs 110 .get(prev_dev) 111 .map(|outs| &**outs) 112 .unwrap_or(&[]) 113 .iter() 114 .copied() 115 .map(|out| (out, graph.outs.get(out).copied())); 116 117 for (output, _) in prevs { 118 let r = self.walk_output(output, graph); 119 120 let (_, params) = self.graph.entry(dev).or_insert((dev_desc, [None; 16])); 121 params[param as usize] = Some(r); 122 } 123 } 124 } 125 126 fn walk_output(&mut self, output: OutputId, graph: &Graph) -> (DeviceId, u8) { 127 let (dev, param) = graph[output]; 128 let dev_desc = graph.devices[dev]; 129 println!("Walking output {param} for {dev_desc:?}"); 130 131 if matches!(dev_desc, DeviceKind::MidiControl) { 132 self.midis.insert(output, (dev, param)); 133 } 134 let (_, _) = self.graph.entry(dev).or_insert((dev_desc, [None; 16])); 135 136 self.dev_map.insert(Connector::Out(output), (dev, param)); 137 138 // for each of this device's inputs 139 let prevs = graph 140 .dev_ins 141 .get(dev) 142 .map(|ins| &**ins) 143 .unwrap_or(&[]) 144 .iter() 145 .copied(); 146 147 for input in prevs { 148 self.walk_input(input, graph); 149 } 150 (dev, param) 151 } 152} 153 154impl Graph { 155 pub fn new() -> Self { 156 Default::default() 157 } 158 159 pub fn remove_module(&mut self, mid: ModuleId) { 160 let (mut removed_ins, mut removed_outs) = (Vec::new(), Vec::new()); 161 162 let module = self.modules.remove(mid).unwrap(); 163 for did in module.devices { 164 self.ins.retain(|i, (dev, _)| { 165 if *dev != did { 166 removed_ins.push(i); 167 168 true 169 } else { 170 false 171 } 172 }); 173 self.outs.retain(|o, (dev, _)| { 174 if *dev != did { 175 removed_outs.push(o); 176 177 true 178 } else { 179 false 180 } 181 }); 182 } 183 for i in removed_ins { 184 self.cables.remove(i); 185 } 186 187 for o in removed_outs { 188 self.cables.retain(|_, co| o != *co); 189 } 190 } 191 192 pub fn walk_to(&self, end: InputId) -> CtlGraph { 193 Walker::walk(end, self) 194 } 195} 196 197impl Index<InputId> for Graph { 198 type Output = (DeviceId, u8); 199 200 fn index(&self, index: InputId) -> &Self::Output { 201 &self.ins[index] 202 } 203} 204 205impl Index<OutputId> for Graph { 206 type Output = (DeviceId, u8); 207 208 fn index(&self, index: OutputId) -> &Self::Output { 209 &self.outs[index] 210 } 211} 212 213impl Index<ModuleId> for Graph { 214 type Output = Module; 215 216 fn index(&self, index: ModuleId) -> &Self::Output { 217 self.modules.get(index).unwrap() 218 } 219} 220 221impl IndexMut<ModuleId> for Graph { 222 fn index_mut(&mut self, index: ModuleId) -> &mut Self::Output { 223 self.modules.get_mut(index).unwrap() 224 } 225}