1use crate::engine::audio::events::AudioEventList;
2use crate::engine::audio::events::SynthDefinition;
3#[cfg(feature = "cli")]
4use crate::engine::audio::midi_native::MidiManager;
5use crate::engine::events::EventRegistry;
6use crate::engine::functions::FunctionRegistry;
7use crate::engine::special_vars::{SpecialVarContext, is_special_var, resolve_special_var};
8#[cfg(feature = "cli")]
9use crate::language::addons::registry::BankRegistry;
10use crate::language::syntax::ast::{Statement, Value};
11
12#[cfg(not(feature = "cli"))]
14#[allow(dead_code)]
15#[derive(Clone)]
16pub struct BankRegistry;
17
18#[cfg(not(feature = "cli"))]
19impl BankRegistry {
20 pub fn new() -> Self {
21 BankRegistry
22 }
23 pub fn list_banks(&self) -> Vec<(String, StubBank)> {
24 Vec::new()
25 }
26 pub fn resolve_trigger(&self, _var: &str, _prop: &str) -> Option<std::path::PathBuf> {
27 None
28 }
29 pub fn register_bank(
30 &self,
31 _alias: String,
32 _name: &str,
33 _cwd: &std::path::Path,
34 _cwd2: &std::path::Path,
35 ) -> Result<(), anyhow::Error> {
36 Ok(())
37 }
38}
39
40#[cfg(not(feature = "cli"))]
41#[allow(dead_code)]
42#[derive(Clone)]
43pub struct StubBank;
44
45#[cfg(not(feature = "cli"))]
46impl StubBank {
47 pub fn list_triggers(&self) -> Vec<String> {
48 Vec::new()
49 }
50}
51
52#[derive(Clone, Debug)]
54pub struct NoteAutomationContext {
55 pub templates: Vec<crate::engine::audio::automation::AutomationParamTemplate>,
56 pub start_time: f32,
57 pub end_time: f32,
58}
59
60impl NoteAutomationContext {
61 pub fn duration(&self) -> f32 {
63 (self.end_time - self.start_time).max(0.001) }
65
66 pub fn progress_at_time(&self, time: f32) -> f32 {
68 ((time - self.start_time) / self.duration()).clamp(0.0, 1.0)
69 }
70}
71
72use anyhow::Result;
74use std::collections::HashMap;
75
76pub mod collector;
77pub mod extractor;
78pub mod handler;
79pub mod renderer;
80
81pub struct AudioInterpreter {
82 pub sample_rate: u32,
83 pub bpm: f32,
84 pub function_registry: FunctionRegistry,
85 pub events: AudioEventList,
86 pub variables: HashMap<String, Value>,
87 pub groups: HashMap<String, Vec<Statement>>,
88 pub banks: BankRegistry,
89 pub automation_registry: crate::engine::audio::automation::AutomationRegistry,
91 pub note_automation_templates: std::collections::HashMap<String, NoteAutomationContext>,
93 pub cursor_time: f32,
94 pub special_vars: SpecialVarContext,
95 pub event_registry: EventRegistry,
96 #[cfg(feature = "cli")]
97 pub midi_manager: Option<std::sync::Arc<std::sync::Mutex<MidiManager>>>,
98 current_statement_location: Option<(usize, usize)>, pub suppress_beat_emit: bool,
102}
103
104impl AudioInterpreter {
105 pub fn new(sample_rate: u32) -> Self {
106 Self {
107 sample_rate,
108 bpm: 120.0,
109 function_registry: FunctionRegistry::new(),
110 events: AudioEventList::new(),
111 variables: HashMap::new(),
112 groups: HashMap::new(),
113 banks: BankRegistry::new(),
114 automation_registry: crate::engine::audio::automation::AutomationRegistry::new(),
115 note_automation_templates: std::collections::HashMap::new(),
116 cursor_time: 0.0,
117 special_vars: SpecialVarContext::new(120.0, sample_rate),
118 event_registry: EventRegistry::new(),
119 #[cfg(feature = "cli")]
120 midi_manager: None,
121 current_statement_location: None,
122 suppress_beat_emit: false,
123 }
124 }
125
126 fn handle_trigger(&mut self, entity: &str) -> Result<()> {
128 handler::handle_trigger(self, entity)
130 }
131
132 fn debug_list_banks(&self) {
134 println!("🔍 Available triggers in BankRegistry:");
135 for (bank_name, bank) in self.banks.list_banks() {
136 println!(" Bank: {}", bank_name);
137 for trigger in bank.list_triggers() {
138 println!(" Trigger: {}", trigger);
139 }
140 }
141 }
142
143 pub fn interpret(&mut self, statements: &[Statement]) -> Result<Vec<f32>> {
144 let total_duration = self.calculate_total_duration(statements)?;
146 self.special_vars.total_duration = total_duration;
147 self.special_vars.update_bpm(self.bpm);
148
149 self.collect_events(statements)?;
151
152 self.render_audio()
156 }
157
158 pub fn events(&self) -> &AudioEventList {
160 &self.events
161 }
162
163 pub fn current_statement_location(&self) -> Option<(usize, usize)> {
165 self.current_statement_location
166 }
167
168 pub fn calculate_total_duration(&self, _statements: &[Statement]) -> Result<f32> {
170 Ok(60.0) }
173
174 pub fn collect_events(&mut self, statements: &[Statement]) -> Result<()> {
175 collector::collect_events(self, statements)
177 }
178 pub fn handle_let(&mut self, name: &str, value: &Value) -> Result<()> {
179 handler::handle_let(self, name, value)
180 }
181
182 pub fn extract_audio_event(
183 &mut self,
184 target: &str,
185 context: &crate::engine::functions::FunctionContext,
186 ) -> Result<()> {
187 extractor::extract_audio_event(self, target, context)
189 }
190
191 pub fn render_audio(&self) -> Result<Vec<f32>> {
192 renderer::render_audio(self)
194 }
195
196 pub fn set_bpm(&mut self, bpm: f32) {
197 self.bpm = bpm.max(1.0).min(999.0);
198 }
199
200 pub fn samples_per_beat(&self) -> usize {
201 ((60.0 / self.bpm) * self.sample_rate as f32) as usize
202 }
203
204 pub fn beat_duration(&self) -> f32 {
206 60.0 / self.bpm
207 }
208
209 pub fn execute_print(&self, value: &Value) -> Result<()> {
212 handler::execute_print(self, value)
213 }
214
215 pub fn interpolate_string(&self, template: &str) -> String {
218 let mut result = template.to_string();
219
220 let re = regex::Regex::new(r"\{([a-zA-Z_][a-zA-Z0-9_]*)\}").unwrap();
222
223 for cap in re.captures_iter(template) {
224 let full_match = &cap[0]; let var_name = &cap[1]; if let Some(value) = self.variables.get(var_name) {
228 let replacement = self.value_to_string(value);
229 result = result.replace(full_match, &replacement);
230 } else {
231 result = result.replace(full_match, &format!("<undefined:{}>", var_name));
233 }
234 }
235
236 result
237 }
238
239 fn value_to_string(&self, value: &Value) -> String {
241 match value {
242 Value::String(s) => {
243 s.trim_matches('"').trim_matches('\'').to_string()
245 }
246 Value::Number(n) => {
247 if n.fract() == 0.0 {
249 format!("{:.0}", n)
250 } else {
251 format!("{}", n)
252 }
253 }
254 Value::Boolean(b) => b.to_string(),
255 Value::Array(arr) => {
256 let items: Vec<String> = arr.iter().map(|v| self.value_to_string(v)).collect();
257 format!("[{}]", items.join(", "))
258 }
259 Value::Identifier(id) => id.clone(),
260 _ => format!("{:?}", value),
261 }
262 }
263
264 pub fn execute_if(
266 &mut self,
267 condition: &Value,
268 body: &[Statement],
269 else_body: &Option<Vec<Statement>>,
270 ) -> Result<()> {
271 handler::execute_if(self, condition, body, else_body)
272 }
273
274 pub fn evaluate_condition(&self, condition: &Value) -> Result<bool> {
277 if let Value::Map(map) = condition {
279 let operator = map
280 .get("operator")
281 .and_then(|v| {
282 if let Value::String(s) = v {
283 Some(s.as_str())
284 } else {
285 None
286 }
287 })
288 .unwrap_or("==");
289
290 let left = map
291 .get("left")
292 .ok_or_else(|| anyhow::anyhow!("Missing left operand"))?;
293 let right = map
294 .get("right")
295 .ok_or_else(|| anyhow::anyhow!("Missing right operand"))?;
296
297 let left_val = self.resolve_value(left);
299 let right_val = self.resolve_value(right);
300
301 match operator {
303 "==" => Ok(self.values_equal(&left_val, &right_val)),
304 "!=" => Ok(!self.values_equal(&left_val, &right_val)),
305 "<" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less),
306 ">" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater),
307 "<=" => {
308 let less =
309 self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less)?;
310 let equal = self.values_equal(&left_val, &right_val);
311 Ok(less || equal)
312 }
313 ">=" => {
314 let greater =
315 self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater)?;
316 let equal = self.values_equal(&left_val, &right_val);
317 Ok(greater || equal)
318 }
319 _ => Err(anyhow::anyhow!("Unknown operator: {}", operator)),
320 }
321 } else {
322 match condition {
324 Value::Boolean(b) => Ok(*b),
325 Value::Number(n) => Ok(*n != 0.0),
326 Value::String(s) => Ok(!s.is_empty()),
327 _ => Ok(false),
328 }
329 }
330 }
331
332 pub fn resolve_value(&self, value: &Value) -> Value {
334 match value {
335 Value::Identifier(name) => {
336 if is_special_var(name) {
338 if let Some(special_val) = resolve_special_var(name, &self.special_vars) {
339 return special_val;
340 }
341 }
342
343 self.variables.get(name).cloned().unwrap_or(Value::Null)
345 }
346 _ => value.clone(),
347 }
348 }
349
350 pub fn execute_event_handlers(&mut self, event_name: &str) -> Result<()> {
352 handler::execute_event_handlers(self, event_name)
353 }
354
355 pub fn values_equal(&self, left: &Value, right: &Value) -> bool {
357 match (left, right) {
358 (Value::Number(a), Value::Number(b)) => (a - b).abs() < 0.0001,
359 (Value::String(a), Value::String(b)) => a == b,
360 (Value::Boolean(a), Value::Boolean(b)) => a == b,
361 (Value::Null, Value::Null) => true,
362 _ => false,
363 }
364 }
365
366 pub fn compare_values(
368 &self,
369 left: &Value,
370 right: &Value,
371 ordering: std::cmp::Ordering,
372 ) -> Result<bool> {
373 match (left, right) {
374 (Value::Number(a), Value::Number(b)) => {
375 Ok(a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) == ordering)
376 }
377 (Value::String(a), Value::String(b)) => Ok(a.cmp(b) == ordering),
378 _ => Err(anyhow::anyhow!("Cannot compare {:?} and {:?}", left, right)),
379 }
380 }
381
382 pub fn handle_assign(&mut self, target: &str, property: &str, value: &Value) -> Result<()> {
384 handler::handle_assign(self, target, property, value)
385 }
386
387 pub fn extract_synth_def_from_map(
389 &self,
390 map: &HashMap<String, Value>,
391 ) -> Result<SynthDefinition> {
392 handler::extract_synth_def_from_map(self, map)
393 }
394
395 pub fn handle_load(&mut self, source: &str, alias: &str) -> Result<()> {
397 handler::handle_load(self, source, alias)
398 }
399
400 pub fn handle_bind(&mut self, source: &str, target: &str, options: &Value) -> Result<()> {
402 handler::handle_bind(self, source, target, options)
403 }
404
405 pub fn extract_pattern_data(
407 &self,
408 value: &Value,
409 ) -> (Option<String>, Option<HashMap<String, f32>>) {
410 handler::extract_pattern_data(self, value)
411 }
412
413 pub fn execute_pattern(
415 &mut self,
416 target: &str,
417 pattern: &str,
418 options: Option<HashMap<String, f32>>,
419 ) -> Result<()> {
420 handler::execute_pattern(self, target, pattern, options)
421 }
422
423 pub fn resolve_sample_uri(&self, target: &str) -> String {
425 handler::resolve_sample_uri(self, target)
426 }
427}