devalang_wasm/engine/audio/interpreter/driver/
mod.rs

1use crate::engine::audio::events::AudioEventList;
2use crate::engine::events::EventRegistry;
3use crate::engine::functions::FunctionRegistry;
4use crate::engine::special_vars::{SpecialVarContext, is_special_var, resolve_special_var};
5use crate::engine::audio::events::SynthDefinition;
6use crate::language::syntax::ast::{Statement, Value};
7use crate::language::addons::registry::BankRegistry;
8/// Audio interpreter driver - main execution loop
9use anyhow::Result;
10use std::collections::HashMap;
11
12pub mod collector;
13pub mod handler;
14pub mod extractor;
15pub mod renderer;
16
17pub struct AudioInterpreter {
18    pub sample_rate: u32,
19    pub bpm: f32,
20    pub function_registry: FunctionRegistry,
21    pub events: AudioEventList,
22    pub variables: HashMap<String, Value>,
23    pub groups: HashMap<String, Vec<Statement>>,
24    pub banks: BankRegistry,
25    pub cursor_time: f32,
26    pub special_vars: SpecialVarContext,
27    pub event_registry: EventRegistry,
28    /// Track current statement location for better error reporting
29    current_statement_location: Option<(usize, usize)>, // (line, column)
30    /// Internal guard to avoid re-entrant beat emission during handler execution
31    pub suppress_beat_emit: bool,
32}
33
34impl AudioInterpreter {
35    pub fn new(sample_rate: u32) -> Self {
36        Self {
37            sample_rate,
38            bpm: 120.0,
39            function_registry: FunctionRegistry::new(),
40            events: AudioEventList::new(),
41            variables: HashMap::new(),
42            groups: HashMap::new(),
43            banks: BankRegistry::new(),
44            cursor_time: 0.0,
45            special_vars: SpecialVarContext::new(120.0, sample_rate),
46            event_registry: EventRegistry::new(),
47            current_statement_location: None,
48            suppress_beat_emit: false,
49        }
50    }
51
52    /// Handle a trigger statement (e.g., .kit.kick or kit.kick)
53    fn handle_trigger(&mut self, entity: &str) -> Result<()> {
54        // Delegate detailed trigger handling to the handler module
55        handler::handle_trigger(self, entity)
56    }
57
58    /// Helper to print banks and triggers for debugging
59    fn debug_list_banks(&self) {
60        println!("🔍 Available triggers in BankRegistry:");
61        for (bank_name, bank) in self.banks.list_banks() {
62            println!("   Bank: {}", bank_name);
63            for trigger in bank.list_triggers() {
64                println!("      Trigger: {}", trigger);
65            }
66        }
67    }
68
69    pub fn interpret(&mut self, statements: &[Statement]) -> Result<Vec<f32>> {
70        // Initialize special vars context
71        let total_duration = self.calculate_total_duration(statements)?;
72        self.special_vars.total_duration = total_duration;
73        self.special_vars.update_bpm(self.bpm);
74
75        // Phase 1: Collect events
76        self.collect_events(statements)?;
77
78        // Phase 2: Render audio
79
80        // Phase 2: Render audio
81        self.render_audio()
82    }
83
84    /// Get reference to collected audio events (for MIDI export)
85    pub fn events(&self) -> &AudioEventList {
86        &self.events
87    }
88
89    /// Get current statement location for error reporting
90    pub fn current_statement_location(&self) -> Option<(usize, usize)> {
91        self.current_statement_location
92    }
93
94    /// Calculate approximate total duration by scanning statements
95    pub fn calculate_total_duration(&self, _statements: &[Statement]) -> Result<f32> {
96        // For now, return a default duration (will be updated during collect_events)
97        Ok(60.0) // Default 60 seconds
98    }
99
100    pub fn collect_events(&mut self, statements: &[Statement]) -> Result<()> {
101        // Delegate to the collector child module
102        collector::collect_events(self, statements)
103    }
104    pub fn handle_let(&mut self, name: &str, value: &Value) -> Result<()> {
105        handler::handle_let(self, name, value)
106    }
107
108    pub fn extract_audio_event(
109        &mut self,
110        target: &str,
111        context: &crate::engine::functions::FunctionContext,
112    ) -> Result<()> {
113        // Delegate to extractor child module
114        extractor::extract_audio_event(self, target, context)
115    }
116
117    pub fn render_audio(&self) -> Result<Vec<f32>> {
118        // Delegate to renderer child module
119        renderer::render_audio(self)
120    }
121
122    pub fn set_bpm(&mut self, bpm: f32) {
123        self.bpm = bpm.max(1.0).min(999.0);
124    }
125
126    pub fn samples_per_beat(&self) -> usize {
127        ((60.0 / self.bpm) * self.sample_rate as f32) as usize
128    }
129
130    /// Get duration of one beat in seconds
131    pub fn beat_duration(&self) -> f32 {
132        60.0 / self.bpm
133    }
134
135    /// Execute print statement with variable interpolation
136    /// Supports {variable_name} syntax
137    pub fn execute_print(&self, value: &Value) -> Result<()> {
138        handler::execute_print(self, value)
139    }
140
141    /// Interpolate variables in a string
142    /// Replaces {variable_name} with the variable's value
143    pub fn interpolate_string(&self, template: &str) -> String {
144        let mut result = template.to_string();
145
146        // Find all {variable} patterns
147        let re = regex::Regex::new(r"\{([a-zA-Z_][a-zA-Z0-9_]*)\}").unwrap();
148
149        for cap in re.captures_iter(template) {
150            let full_match = &cap[0]; // {variable_name}
151            let var_name = &cap[1]; // variable_name
152
153            if let Some(value) = self.variables.get(var_name) {
154                let replacement = self.value_to_string(value);
155                result = result.replace(full_match, &replacement);
156            } else {
157                // Variable not found, leave placeholder or show error
158                result = result.replace(full_match, &format!("<undefined:{}>", var_name));
159            }
160        }
161
162        result
163    }
164
165    /// Convert a Value to a displayable string
166    fn value_to_string(&self, value: &Value) -> String {
167        match value {
168            Value::String(s) => {
169                // Remove surrounding quotes if present
170                s.trim_matches('"').trim_matches('\'').to_string()
171            }
172            Value::Number(n) => {
173                // Format nicely: remove trailing zeros
174                if n.fract() == 0.0 {
175                    format!("{:.0}", n)
176                } else {
177                    format!("{}", n)
178                }
179            }
180            Value::Boolean(b) => b.to_string(),
181            Value::Array(arr) => {
182                let items: Vec<String> = arr.iter().map(|v| self.value_to_string(v)).collect();
183                format!("[{}]", items.join(", "))
184            }
185            Value::Identifier(id) => id.clone(),
186            _ => format!("{:?}", value),
187        }
188    }
189
190    /// Execute if statement with condition evaluation
191    pub fn execute_if(
192        &mut self,
193        condition: &Value,
194        body: &[Statement],
195        else_body: &Option<Vec<Statement>>,
196    ) -> Result<()> {
197        handler::execute_if(self, condition, body, else_body)
198    }
199
200    /// Evaluate a condition to a boolean
201    /// Supports: ==, !=, <, >, <=, >=
202    pub fn evaluate_condition(&self, condition: &Value) -> Result<bool> {
203        // Condition is stored as a Map with operator and operands
204        if let Value::Map(map) = condition {
205            let operator = map
206                .get("operator")
207                .and_then(|v| {
208                    if let Value::String(s) = v {
209                        Some(s.as_str())
210                    } else {
211                        None
212                    }
213                })
214                .unwrap_or("==");
215
216            let left = map
217                .get("left")
218                .ok_or_else(|| anyhow::anyhow!("Missing left operand"))?;
219            let right = map
220                .get("right")
221                .ok_or_else(|| anyhow::anyhow!("Missing right operand"))?;
222
223            // Resolve values (replace identifiers with their values)
224            let left_val = self.resolve_value(left);
225            let right_val = self.resolve_value(right);
226
227            // Compare based on operator
228            match operator {
229                "==" => Ok(self.values_equal(&left_val, &right_val)),
230                "!=" => Ok(!self.values_equal(&left_val, &right_val)),
231                "<" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less),
232                ">" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater),
233                "<=" => {
234                    let less =
235                        self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less)?;
236                    let equal = self.values_equal(&left_val, &right_val);
237                    Ok(less || equal)
238                }
239                ">=" => {
240                    let greater =
241                        self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater)?;
242                    let equal = self.values_equal(&left_val, &right_val);
243                    Ok(greater || equal)
244                }
245                _ => Err(anyhow::anyhow!("Unknown operator: {}", operator)),
246            }
247        } else {
248            // Direct boolean value
249            match condition {
250                Value::Boolean(b) => Ok(*b),
251                Value::Number(n) => Ok(*n != 0.0),
252                Value::String(s) => Ok(!s.is_empty()),
253                _ => Ok(false),
254            }
255        }
256    }
257
258    /// Resolve a value (replace identifiers with their values from variables)
259    pub fn resolve_value(&self, value: &Value) -> Value {
260        match value {
261            Value::Identifier(name) => {
262                // Check if it's a special variable
263                if is_special_var(name) {
264                    if let Some(special_val) = resolve_special_var(name, &self.special_vars) {
265                        return special_val;
266                    }
267                }
268
269                // Otherwise, look in variables
270                self.variables.get(name).cloned().unwrap_or(Value::Null)
271            }
272            _ => value.clone(),
273        }
274    }
275
276    /// Execute event handlers matching the event name
277    pub fn execute_event_handlers(&mut self, event_name: &str) -> Result<()> {
278        handler::execute_event_handlers(self, event_name)
279    }
280
281    /// Check if two values are equal
282    pub fn values_equal(&self, left: &Value, right: &Value) -> bool {
283        match (left, right) {
284            (Value::Number(a), Value::Number(b)) => (a - b).abs() < 0.0001,
285            (Value::String(a), Value::String(b)) => a == b,
286            (Value::Boolean(a), Value::Boolean(b)) => a == b,
287            (Value::Null, Value::Null) => true,
288            _ => false,
289        }
290    }
291
292    /// Compare two values
293    pub fn compare_values(
294        &self,
295        left: &Value,
296        right: &Value,
297        ordering: std::cmp::Ordering,
298    ) -> Result<bool> {
299        match (left, right) {
300            (Value::Number(a), Value::Number(b)) => {
301                Ok(a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) == ordering)
302            }
303            (Value::String(a), Value::String(b)) => Ok(a.cmp(b) == ordering),
304            _ => Err(anyhow::anyhow!("Cannot compare {:?} and {:?}", left, right)),
305        }
306    }
307
308    /// Handle property assignment: target.property = value
309    pub fn handle_assign(&mut self, target: &str, property: &str, value: &Value) -> Result<()> {
310        handler::handle_assign(self, target, property, value)
311    }
312
313    /// Extract synth definition from a map
314    pub fn extract_synth_def_from_map(&self, map: &HashMap<String, Value>) -> Result<SynthDefinition> {
315        handler::extract_synth_def_from_map(self, map)
316    }
317
318    /// Handle MIDI file loading: @load "path.mid" as alias
319    pub fn handle_load(&mut self, source: &str, alias: &str) -> Result<()> {
320        handler::handle_load(self, source, alias)
321    }
322
323    /// Handle MIDI binding: bind source -> target { options }
324    pub fn handle_bind(&mut self, source: &str, target: &str, options: &Value) -> Result<()> {
325        handler::handle_bind(self, source, target, options)
326    }
327
328    /// Extract pattern string and options from pattern value
329    pub fn extract_pattern_data(&self, value: &Value) -> (Option<String>, Option<HashMap<String, f32>>) {
330        handler::extract_pattern_data(self, value)
331    }
332
333    /// Execute a pattern with given target and pattern string
334    pub fn execute_pattern(
335        &mut self,
336        target: &str,
337        pattern: &str,
338        options: Option<HashMap<String, f32>>,
339    ) -> Result<()> {
340        handler::execute_pattern(self, target, pattern, options)
341    }
342
343    /// Resolve sample URI from bank.trigger notation (e.g., myBank.kick -> devalang://bank/devaloop.808/kick)
344    pub fn resolve_sample_uri(&self, target: &str) -> String {
345        handler::resolve_sample_uri(self, target)
346    }
347}