devalang_wasm/engine/audio/nodes/
mod.rs1use crate::language::syntax::ast::Value;
5use std::collections::HashMap;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum NodeType {
10 Synth,
12 Sample,
14 Bus,
16 Group,
18 Output,
20}
21
22impl NodeType {
23 pub fn is_source(&self) -> bool {
24 matches!(self, NodeType::Synth | NodeType::Sample)
25 }
26
27 pub fn is_container(&self) -> bool {
28 matches!(self, NodeType::Bus | NodeType::Group | NodeType::Output)
29 }
30}
31
32#[derive(Debug, Clone)]
34pub struct NodeParam {
35 pub name: String,
36 pub default: f32,
37 pub min: f32,
38 pub max: f32,
39 pub description: Option<String>,
40}
41
42#[derive(Debug, Clone)]
44pub struct AudioNode {
45 pub id: String,
47 pub name: Option<String>,
49 pub node_type: NodeType,
51 pub effects: Vec<(String, Value)>,
53 pub parameters: HashMap<String, f32>,
55}
56
57impl AudioNode {
58 pub fn new_synth(id: impl Into<String>) -> Self {
60 let id = id.into();
61 let mut params = HashMap::new();
62 params.insert("volume".to_string(), 1.0);
63 params.insert("pan".to_string(), 0.0);
64
65 Self {
66 id,
67 name: None,
68 node_type: NodeType::Synth,
69 effects: Vec::new(),
70 parameters: params,
71 }
72 }
73
74 pub fn new_sample(id: impl Into<String>) -> Self {
76 let id = id.into();
77 let mut params = HashMap::new();
78 params.insert("volume".to_string(), 1.0);
79 params.insert("pan".to_string(), 0.0);
80
81 Self {
82 id,
83 name: None,
84 node_type: NodeType::Sample,
85 effects: Vec::new(),
86 parameters: params,
87 }
88 }
89
90 pub fn new_group(id: impl Into<String>) -> Self {
92 let id = id.into();
93 let mut params = HashMap::new();
94 params.insert("volume".to_string(), 1.0);
95 params.insert("pan".to_string(), 0.0);
96
97 Self {
98 id,
99 name: None,
100 node_type: NodeType::Group,
101 effects: Vec::new(),
102 parameters: params,
103 }
104 }
105
106 pub fn new_bus(id: impl Into<String>) -> Self {
108 let id = id.into();
109 let mut params = HashMap::new();
110 params.insert("volume".to_string(), 1.0);
111 params.insert("pan".to_string(), 0.0);
112
113 Self {
114 id,
115 name: None,
116 node_type: NodeType::Bus,
117 effects: Vec::new(),
118 parameters: params,
119 }
120 }
121
122 pub fn new_master() -> Self {
124 let mut params = HashMap::new();
125 params.insert("volume".to_string(), 1.0);
126
127 Self {
128 id: "master".to_string(),
129 name: Some("Master Output".to_string()),
130 node_type: NodeType::Output,
131 effects: Vec::new(),
132 parameters: params,
133 }
134 }
135
136 pub fn add_effect(&mut self, name: impl Into<String>, params: Value) {
138 self.effects.push((name.into(), params));
139 }
140
141 pub fn set_parameter(&mut self, name: impl Into<String>, value: f32) {
143 self.parameters.insert(name.into(), value);
144 }
145
146 pub fn get_parameter(&self, name: &str) -> Option<f32> {
148 self.parameters.get(name).copied()
149 }
150
151 pub fn volume(&self) -> f32 {
153 self.parameters.get("volume").copied().unwrap_or(1.0)
154 }
155
156 pub fn pan(&self) -> f32 {
158 self.parameters.get("pan").copied().unwrap_or(0.0)
159 }
160
161 pub fn set_volume(&mut self, vol: f32) {
163 self.set_parameter("volume", vol);
164 }
165
166 pub fn set_pan(&mut self, pan: f32) {
168 self.set_parameter("pan", pan.clamp(-1.0, 1.0));
169 }
170
171 pub fn is_source(&self) -> bool {
173 self.node_type.is_source()
174 }
175
176 pub fn is_container(&self) -> bool {
178 self.node_type.is_container()
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_new_synth_node() {
188 let node = AudioNode::new_synth("synth_1");
189 assert_eq!(node.id, "synth_1");
190 assert_eq!(node.node_type, NodeType::Synth);
191 assert_eq!(node.volume(), 1.0);
192 assert_eq!(node.pan(), 0.0);
193 assert!(node.is_source());
194 }
195
196 #[test]
197 fn test_new_group_node() {
198 let node = AudioNode::new_group("drums");
199 assert_eq!(node.id, "drums");
200 assert_eq!(node.node_type, NodeType::Group);
201 assert!(node.is_container());
202 }
203
204 #[test]
205 fn test_set_volume() {
206 let mut node = AudioNode::new_synth("syn");
207 node.set_volume(0.5);
208 assert_eq!(node.volume(), 0.5);
209 }
210
211 #[test]
212 fn test_add_effect() {
213 let mut node = AudioNode::new_synth("syn");
214 node.add_effect("reverb", Value::Number(0.8));
215 assert_eq!(node.effects.len(), 1);
216 assert_eq!(node.effects[0].0, "reverb");
217 }
218}