devalang_wasm/engine/audio/interpreter/
audio_graph.rs1use crate::language::syntax::ast::Value;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
7pub struct Node {
8 pub name: String,
9 pub alias: Option<String>,
10 pub effects: Option<Value>, }
12
13#[derive(Debug, Clone)]
15pub enum Connection {
16 Route {
18 source: String,
19 destination: String,
20 gain: f32,
21 },
22 Duck {
24 source: String,
25 destination: String,
26 effect_params: Value, },
28 Sidechain {
30 source: String,
31 destination: String,
32 effect_params: Value, },
34}
35
36#[derive(Debug, Clone)]
38pub struct AudioGraph {
39 pub nodes: HashMap<String, Node>,
41 pub connections: Vec<Connection>,
43 pub master_node: String,
45}
46
47impl AudioGraph {
48 pub fn new() -> Self {
49 let mut nodes = HashMap::new();
50
51 nodes.insert(
53 "$master".to_string(),
54 Node {
55 name: "$master".to_string(),
56 alias: None,
57 effects: None,
58 },
59 );
60
61 Self {
62 nodes,
63 connections: Vec::new(),
64 master_node: "$master".to_string(),
65 }
66 }
67
68 pub fn add_node(&mut self, name: String, alias: Option<String>, effects: Option<Value>) {
70 self.nodes.insert(
71 name.clone(),
72 Node {
73 name,
74 alias,
75 effects,
76 },
77 );
78 }
79
80 pub fn add_connection(&mut self, connection: Connection) {
82 self.connections.push(connection);
83 }
84
85 pub fn from_routing_setup(
87 routing_setup: &crate::engine::audio::interpreter::driver::RoutingSetup,
88 ) -> Self {
89 let mut graph = AudioGraph::new();
90
91 for (name, node_config) in &routing_setup.nodes {
93 graph.add_node(
94 name.clone(),
95 node_config.alias.clone(),
96 node_config.effects.clone(),
97 );
98 }
99
100 for route in &routing_setup.routes {
102 let gain = if let Some(Value::Map(effects_map)) = &route.effects {
103 if let Some(Value::Map(volume_map)) = effects_map.get("volume") {
104 if let Some(Value::Number(g)) = volume_map.get("gain") {
105 *g
106 } else {
107 1.0
108 }
109 } else if let Some(Value::Number(g)) = effects_map.get("volume") {
110 *g
111 } else {
112 1.0
113 }
114 } else {
115 1.0
116 };
117
118 graph.add_connection(Connection::Route {
119 source: route.source.clone(),
120 destination: route.destination.clone(),
121 gain,
122 });
123 }
124
125 for duck in &routing_setup.ducks {
127 graph.add_connection(Connection::Duck {
128 source: duck.source.clone(),
129 destination: duck.destination.clone(),
130 effect_params: duck.effect.clone(),
131 });
132 }
133
134 for sidechain in &routing_setup.sidechains {
136 graph.add_connection(Connection::Sidechain {
137 source: sidechain.source.clone(),
138 destination: sidechain.destination.clone(),
139 effect_params: sidechain.effect.clone(),
140 });
141 }
142
143 graph
144 }
145
146 pub fn get_outgoing_routes(&self, node_name: &str) -> Vec<&Connection> {
148 self.connections
149 .iter()
150 .filter(|conn| match conn {
151 Connection::Route { source, .. } => source == node_name,
152 _ => false,
153 })
154 .collect()
155 }
156
157 pub fn get_incoming_ducks(&self, node_name: &str) -> Vec<&Connection> {
159 self.connections
160 .iter()
161 .filter(|conn| match conn {
162 Connection::Duck { source, .. } if source == node_name => true,
163 _ => false,
164 })
165 .collect()
166 }
167
168 pub fn get_incoming_sidechains(&self, node_name: &str) -> Vec<&Connection> {
170 self.connections
171 .iter()
172 .filter(|conn| match conn {
173 Connection::Sidechain { source, .. } if source == node_name => true,
174 _ => false,
175 })
176 .collect()
177 }
178
179 pub fn has_node(&self, node_name: &str) -> bool {
181 self.nodes.contains_key(node_name)
182 }
183
184 pub fn node_names(&self) -> Vec<String> {
186 self.nodes.keys().cloned().collect()
187 }
188
189 #[allow(dead_code)]
191 pub fn debug_print(&self) {
192 }
194}
195
196impl Default for AudioGraph {
197 fn default() -> Self {
198 Self::new()
199 }
200}