devalang_wasm/engine/audio/interpreter/statements/
routing.rs1use anyhow::Result;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
7pub struct AudioRoute {
8 pub source: String,
9 pub destination: String,
10 pub channels: Vec<usize>,
11 pub mix_level: f32,
12}
13
14impl Default for AudioRoute {
15 fn default() -> Self {
16 Self {
17 source: String::new(),
18 destination: "master".to_string(),
19 channels: vec![0, 1], mix_level: 1.0,
21 }
22 }
23}
24
25pub fn execute_routing(
46 route: &AudioRoute,
47 routing_table: &mut HashMap<String, Vec<AudioRoute>>,
48) -> Result<()> {
49 if route.source.is_empty() {
51 anyhow::bail!("Routing source cannot be empty");
52 }
53
54 if route.destination.is_empty() {
55 anyhow::bail!("Routing destination cannot be empty");
56 }
57
58 if route.mix_level < 0.0 || route.mix_level > 2.0 {
59 anyhow::bail!(
60 "Mix level must be between 0.0 and 2.0, got: {}",
61 route.mix_level
62 );
63 }
64
65 if route.channels.is_empty() {
66 anyhow::bail!("Routing must specify at least one channel");
67 }
68
69 routing_table
71 .entry(route.source.clone())
72 .or_insert_with(Vec::new)
73 .push(route.clone());
74
75 #[cfg(feature = "cli")]
77 {
78 eprintln!(
79 "Route: {} -> {} ({} ch @ {:.2})",
80 route.source,
81 route.destination,
82 route.channels.len(),
83 route.mix_level
84 );
85 }
86
87 Ok(())
88}
89
90pub fn create_default_route(source: String) -> AudioRoute {
92 AudioRoute {
93 source,
94 destination: "master".to_string(),
95 channels: vec![0, 1],
96 mix_level: 1.0,
97 }
98}
99
100pub fn parse_routing_expr(expr: &str) -> Result<AudioRoute> {
102 let parts: Vec<&str> = expr.split("->").collect();
106 if parts.len() != 2 {
107 anyhow::bail!("Invalid routing expression: {}", expr);
108 }
109
110 let source = parts[0].trim().to_string();
111 let dest_and_level: Vec<&str> = parts[1].split('@').collect();
112
113 let destination = dest_and_level[0].trim().to_string();
114 let mix_level = if dest_and_level.len() > 1 {
115 dest_and_level[1]
116 .trim()
117 .parse::<f32>()
118 .map_err(|_| anyhow::anyhow!("Invalid mix level: {}", dest_and_level[1]))?
119 } else {
120 1.0
121 };
122
123 Ok(AudioRoute {
124 source,
125 destination,
126 channels: vec![0, 1],
127 mix_level,
128 })
129}