1use crate::engine::audio::effects::processors::{
2 DelayProcessor, DriveProcessor, EffectProcessor, ReverbProcessor,
3};
4use crate::engine::audio::events::{
5 AudioEventList, SynthDefinition, extract_filters, extract_number, extract_string,
6};
7use crate::engine::audio::generator::{
8 SynthParams, generate_chord_with_options, generate_note_with_options,
9};
10use crate::engine::events::{EventHandler, EventRegistry};
11use crate::engine::functions::FunctionRegistry;
12use crate::engine::functions::note::parse_note_to_midi;
13use crate::engine::special_vars::{SpecialVarContext, is_special_var, resolve_special_var};
14use crate::language::syntax::ast::{Statement, StatementKind, Value};
15use anyhow::Result;
17use rayon::prelude::*;
18use std::collections::HashMap;
19
20pub struct AudioInterpreter {
21 pub sample_rate: u32,
22 pub bpm: f32,
23 function_registry: FunctionRegistry,
24 events: AudioEventList,
25 pub(crate) variables: HashMap<String, Value>,
26 groups: HashMap<String, Vec<Statement>>,
27 cursor_time: f32,
28 pub special_vars: SpecialVarContext,
29 pub event_registry: EventRegistry,
30 current_statement_location: Option<(usize, usize)>, }
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 cursor_time: 0.0,
44 special_vars: SpecialVarContext::new(120.0, sample_rate),
45 event_registry: EventRegistry::new(),
46 current_statement_location: None,
47 }
48 }
49
50 pub fn interpret(&mut self, statements: &[Statement]) -> Result<Vec<f32>> {
51 let total_duration = self.calculate_total_duration(statements)?;
53 self.special_vars.total_duration = total_duration;
54 self.special_vars.update_bpm(self.bpm);
55
56 self.collect_events(statements)?;
58
59 self.render_audio()
61 }
62
63 pub fn events(&self) -> &AudioEventList {
65 &self.events
66 }
67
68 pub fn current_statement_location(&self) -> Option<(usize, usize)> {
70 self.current_statement_location
71 }
72
73 fn calculate_total_duration(&self, _statements: &[Statement]) -> Result<f32> {
75 Ok(60.0) }
78
79 pub(crate) fn collect_events(&mut self, statements: &[Statement]) -> Result<()> {
80 let (spawns, others): (Vec<_>, Vec<_>) = statements
82 .iter()
83 .partition(|stmt| matches!(stmt.kind, StatementKind::Spawn { .. }));
84
85 for stmt in &others {
87 self.current_statement_location = Some((stmt.line, stmt.column));
89
90 self.special_vars.update_time(self.cursor_time);
92
93 match &stmt.kind {
94 StatementKind::Let { name, value } => {
95 if let Some(val) = value {
96 self.handle_let(name, val)?;
97 }
98 }
99
100 StatementKind::ArrowCall {
101 target,
102 method,
103 args,
104 } => {
105 let chain = if let Value::Map(map) = &stmt.value {
107 map.get("chain").and_then(|v| {
108 if let Value::Array(arr) = v {
109 Some(arr.as_slice())
110 } else {
111 None
112 }
113 })
114 } else {
115 None
116 };
117
118 let context = super::statements::arrow_call::execute_arrow_call(
120 &self.function_registry,
121 target,
122 method,
123 args,
124 chain,
125 self.cursor_time,
126 self.bpm,
127 )
128 .map_err(|e| {
129 #[cfg(target_arch = "wasm32")]
131 {
132 use crate::web::registry::debug;
133 if debug::is_debug_errors_enabled() {
134 debug::push_parse_error_from_parts(
135 format!("{}", e),
136 stmt.line,
137 stmt.column,
138 "RuntimeError".to_string(),
139 );
140 }
141 }
142 e
143 })?;
144
145 self.extract_audio_event(target, &context)?;
147
148 self.cursor_time += context.duration;
150 }
151
152 StatementKind::Tempo => {
153 if let Value::Number(bpm_value) = &stmt.value {
154 self.set_bpm(*bpm_value);
155 }
156 }
157
158 StatementKind::Sleep => {
159 if let Value::Number(duration) = &stmt.value {
161 self.cursor_time += duration / 1000.0; }
163 }
164
165 StatementKind::Group { name, body } => {
166 self.groups.insert(name.clone(), body.clone());
168 }
169
170 StatementKind::Call { name, args: _ } => {
171 if let Some(body) = self.groups.get(name).cloned() {
173 println!("📞 Call: {}", name);
174 self.collect_events(&body)?;
175 } else {
176 println!("⚠️ Warning: Group '{}' not found", name);
177 }
178 }
179
180 StatementKind::Spawn { .. } => {
181 unreachable!("Spawn statements should be handled in parallel section");
184 }
185
186 StatementKind::Loop { count, body } => {
187 self.execute_loop(count, body)?;
189 }
190
191 StatementKind::For {
192 variable,
193 iterable,
194 body,
195 } => {
196 self.execute_for(variable, iterable, body)?;
198 }
199
200 StatementKind::Print => {
201 self.execute_print(&stmt.value)?;
203 }
204
205 StatementKind::If {
206 condition,
207 body,
208 else_body,
209 } => {
210 self.execute_if(condition, body, else_body)?;
212 }
213
214 StatementKind::On { event, args, body } => {
215 let once = args
217 .as_ref()
218 .and_then(|a| a.first())
219 .and_then(|v| {
220 if let Value::String(s) = v {
221 Some(s == "once")
222 } else {
223 None
224 }
225 })
226 .unwrap_or(false);
227
228 let handler = EventHandler {
229 event_name: event.clone(),
230 body: body.clone(),
231 once,
232 };
233
234 self.event_registry.register_handler(handler);
235 println!("📡 Event handler registered: {} (once={})", event, once);
236 }
237
238 StatementKind::Emit { event, payload } => {
239 let data = if let Some(Value::Map(map)) = payload {
241 map.clone()
242 } else {
243 HashMap::new()
244 };
245
246 self.event_registry
247 .emit(event.clone(), data, self.cursor_time);
248
249 self.execute_event_handlers(event)?;
251
252 println!("📤 Event emitted: {}", event);
253 }
254
255 StatementKind::Assign { target, property } => {
256 self.handle_assign(target, property, &stmt.value)?;
258 }
259
260 StatementKind::Load { source, alias } => {
261 self.handle_load(source, alias)?;
263 }
264
265 StatementKind::Bank { name, alias } => {
266 let target_alias = alias.clone().unwrap_or_else(|| {
271 name.split('.').last().unwrap_or(name).to_string()
273 });
274
275 let mut bank_found = false;
277
278 if let Some(existing_value) = self.variables.get(name) {
280 self.variables
282 .insert(target_alias.clone(), existing_value.clone());
283 bank_found = true;
284
285 #[cfg(target_arch = "wasm32")]
286 web_sys::console::log_1(
287 &format!("🏦 Bank alias created: {} -> {}", name, target_alias).into(),
288 );
289 #[cfg(not(target_arch = "wasm32"))]
290 println!("🏦 Bank alias created: {} -> {}", name, target_alias);
291 } else {
292 #[cfg(target_arch = "wasm32")]
294 {
295 use crate::web::registry::banks::REGISTERED_BANKS;
296
297 REGISTERED_BANKS.with(|banks| {
298 for bank in banks.borrow().iter() {
299 if bank.full_name == *name {
300 if let Some(Value::Map(bank_map)) =
302 self.variables.get(&bank.alias)
303 {
304 self.variables.insert(
305 target_alias.clone(),
306 Value::Map(bank_map.clone()),
307 );
308 bank_found = true;
309
310 web_sys::console::log_1(
311 &format!(
312 "🏦 Bank alias created: {} ({}) -> {}",
313 name, bank.alias, target_alias
314 )
315 .into(),
316 );
317 }
318 }
319 }
320 });
321 }
322 }
323
324 if !bank_found {
325 #[cfg(target_arch = "wasm32")]
326 web_sys::console::warn_1(&format!("⚠️ Bank not found: {}", name).into());
327 #[cfg(not(target_arch = "wasm32"))]
328 println!("⚠️ Bank not found: {}", name);
329 }
330 }
331
332 StatementKind::Bind { source, target } => {
333 self.handle_bind(source, target, &stmt.value)?;
335 }
336
337 StatementKind::Trigger {
338 entity,
339 duration: _,
340 effects: _,
341 } => {
342 let resolved_entity = if entity.starts_with('.') {
345 &entity[1..]
346 } else {
347 entity
348 };
349
350 if resolved_entity.contains('.') {
352 let parts: Vec<&str> = resolved_entity.split('.').collect();
353 if parts.len() == 2 {
354 let (var_name, property) = (parts[0], parts[1]);
355
356 if let Some(Value::Map(map)) = self.variables.get(var_name) {
358 if let Some(Value::String(sample_uri)) = map.get(property) {
359 let uri = sample_uri.trim_matches('"').trim_matches('\'');
360
361 #[cfg(target_arch = "wasm32")]
362 web_sys::console::log_1(
363 &format!(
364 "🎵 Trigger: {}.{} -> {} at {:.3}s",
365 var_name, property, uri, self.cursor_time
366 )
367 .into(),
368 );
369 #[cfg(not(target_arch = "wasm32"))]
370 println!(
371 "🎵 Trigger: {}.{} -> {} at {:.3}s",
372 var_name, property, uri, self.cursor_time
373 );
374
375 self.events.add_sample_event(
377 uri,
378 self.cursor_time,
379 1.0, );
381
382 let beat_duration = self.beat_duration();
384 self.cursor_time += beat_duration;
385
386 #[cfg(target_arch = "wasm32")]
387 web_sys::console::log_1(&format!(" Next trigger at {:.3}s (advanced by 1 beat = {:.3}s)",
388 self.cursor_time, beat_duration).into());
389 }
390 }
391 }
392 } else {
393 if let Some(Value::String(sample_uri)) = self.variables.get(resolved_entity)
395 {
396 let uri = sample_uri.trim_matches('"').trim_matches('\'');
397
398 #[cfg(target_arch = "wasm32")]
399 web_sys::console::log_1(
400 &format!(
401 "🎵 Trigger: {} -> {} at {:.3}s",
402 resolved_entity, uri, self.cursor_time
403 )
404 .into(),
405 );
406 #[cfg(not(target_arch = "wasm32"))]
407 println!(
408 "🎵 Trigger: {} -> {} at {:.3}s",
409 resolved_entity, uri, self.cursor_time
410 );
411
412 self.events.add_sample_event(
414 uri,
415 self.cursor_time,
416 1.0, );
418
419 let beat_duration = self.beat_duration();
421 self.cursor_time += beat_duration;
422
423 #[cfg(target_arch = "wasm32")]
424 web_sys::console::log_1(
425 &format!(
426 " Next trigger at {:.3}s (advanced by 1 beat = {:.3}s)",
427 self.cursor_time, beat_duration
428 )
429 .into(),
430 );
431 }
432 }
433 }
434
435 _ => {
436 }
438 }
439 }
440
441 if !spawns.is_empty() {
443 println!("🚀 Executing {} spawn(s) in parallel", spawns.len());
444
445 let current_time = self.cursor_time;
447 let current_bpm = self.bpm;
448 let groups_snapshot = self.groups.clone();
449 let variables_snapshot = self.variables.clone();
450 let special_vars_snapshot = self.special_vars.clone();
451
452 let spawn_results: Vec<Result<AudioEventList>> = spawns
454 .par_iter()
455 .map(|stmt| {
456 if let StatementKind::Spawn { name, args: _ } = &stmt.kind {
457 let resolved_name = if name.starts_with('.') {
459 &name[1..]
460 } else {
461 name
462 };
463 if resolved_name.contains('.') {
465 let parts: Vec<&str> = resolved_name.split('.').collect();
466 if parts.len() == 2 {
467 let (var_name, property) = (parts[0], parts[1]);
468 if let Some(Value::Map(map)) = variables_snapshot.get(var_name) {
470 if let Some(Value::String(sample_uri)) = map.get(property) {
471 println!("🎵 Spawn nested sample: {}.{} -> {}", var_name, property, sample_uri);
472 let mut event_list = AudioEventList::new();
473 event_list.add_sample_event(
474 sample_uri.trim_matches('"').trim_matches('\''),
475 current_time,
476 1.0, );
478 return Ok(event_list);
479 }
480 }
481 }
482 }
483 if let Some(sample_value) = variables_snapshot.get(resolved_name) {
485 if let Value::String(sample_uri) = sample_value {
486 println!("🎵 Spawn sample: {} -> {}", resolved_name, sample_uri);
487 let mut event_list = AudioEventList::new();
489 event_list.add_sample_event(
490 sample_uri.trim_matches('"').trim_matches('\''),
491 current_time,
492 1.0, );
494 return Ok(event_list);
495 }
496 }
497 let mut local_interpreter = AudioInterpreter {
499 sample_rate: self.sample_rate,
500 bpm: current_bpm,
501 function_registry: FunctionRegistry::new(), events: AudioEventList::new(),
503 variables: variables_snapshot.clone(),
504 groups: groups_snapshot.clone(),
505 cursor_time: current_time,
506 special_vars: special_vars_snapshot.clone(),
507 event_registry: EventRegistry::new(),
508 current_statement_location: None, };
510 if let Some(body) = groups_snapshot.get(resolved_name) {
512 println!("🎬 Spawn group: {} (parallel)", resolved_name);
513 local_interpreter.collect_events(body)?;
514 Ok(local_interpreter.events)
515 } else {
516 println!("⚠️ Warning: Spawn target '{}' not found (neither sample nor group)", resolved_name);
517 Ok(AudioEventList::new())
518 }
519 } else {
520 Ok(AudioEventList::new())
521 }
522 })
523 .collect();
524
525 for result in spawn_results {
527 match result {
528 Ok(spawn_events) => {
529 self.events.merge(spawn_events);
530 }
531 Err(e) => {
532 println!("⚠️ Error in spawn execution: {}", e);
533 }
535 }
536 }
537
538 println!("✅ Parallel spawn execution completed");
539 }
540
541 Ok(())
542 }
543
544 fn handle_let(&mut self, name: &str, value: &Value) -> Result<()> {
545 if let Value::Map(map) = value {
547 if map.contains_key("waveform") {
548 let waveform = extract_string(map, "waveform", "sine");
550 let attack = extract_number(map, "attack", 0.01);
551 let decay = extract_number(map, "decay", 0.1);
552 let sustain = extract_number(map, "sustain", 0.7);
553 let release = extract_number(map, "release", 0.2);
554
555 let synth_type = if let Some(Value::String(t)) = map.get("type") {
557 let clean = t.trim_matches('"').trim_matches('\'');
559 if clean.is_empty() || clean == "synth" {
560 None
561 } else {
562 Some(clean.to_string())
563 }
564 } else {
565 None
566 };
567
568 let filters = if let Some(Value::Array(filters_arr)) = map.get("filters") {
570 extract_filters(filters_arr)
571 } else {
572 Vec::new()
573 };
574
575 let mut options = std::collections::HashMap::new();
577 for (key, val) in map.iter() {
578 if ![
579 "waveform", "attack", "decay", "sustain", "release", "type", "filters",
580 ]
581 .contains(&key.as_str())
582 {
583 if let Value::Number(n) = val {
584 options.insert(key.clone(), *n);
585 }
586 }
587 }
588
589 let type_info = synth_type
590 .as_ref()
591 .map(|t| format!(" [{}]", t))
592 .unwrap_or_default();
593 let opts_info = if !options.is_empty() {
594 let opts: Vec<String> = options
595 .iter()
596 .map(|(k, v)| format!("{}={:.2}", k, v))
597 .collect();
598 format!(" (options: {})", opts.join(", "))
599 } else {
600 String::new()
601 };
602
603 let synth_def = SynthDefinition {
604 waveform,
605 attack,
606 decay,
607 sustain,
608 release,
609 synth_type,
610 filters,
611 options,
612 };
613
614 self.events.add_synth(name.to_string(), synth_def);
615
616 println!("🎹 Synth registered: {}{}{}", name, type_info, opts_info);
617 }
618 }
619
620 self.variables.insert(name.to_string(), value.clone());
622 Ok(())
623 }
624
625 fn extract_audio_event(
626 &mut self,
627 target: &str,
628 context: &crate::engine::functions::FunctionContext,
629 ) -> Result<()> {
630 if let Some(Value::String(note_name)) = context.get("note") {
632 let midi = parse_note_to_midi(note_name)?;
633 let duration = if let Some(Value::Number(d)) = context.get("duration") {
634 d / 1000.0 } else {
636 0.5
637 };
638 let velocity = if let Some(Value::Number(v)) = context.get("velocity") {
639 v / 100.0 } else {
641 0.8
642 };
643
644 let pan = if let Some(Value::Number(p)) = context.get("pan") {
646 *p
647 } else {
648 0.0
649 };
650
651 let detune = if let Some(Value::Number(d)) = context.get("detune") {
652 *d
653 } else {
654 0.0
655 };
656
657 let gain = if let Some(Value::Number(g)) = context.get("gain") {
658 *g
659 } else {
660 1.0
661 };
662
663 let attack = if let Some(Value::Number(a)) = context.get("attack") {
664 Some(*a)
665 } else {
666 None
667 };
668
669 let release = if let Some(Value::Number(r)) = context.get("release") {
670 Some(*r)
671 } else {
672 None
673 };
674
675 let delay_time = if let Some(Value::Number(t)) = context.get("delay_time") {
677 Some(*t)
678 } else {
679 None
680 };
681
682 let delay_feedback = if let Some(Value::Number(f)) = context.get("delay_feedback") {
683 Some(*f)
684 } else {
685 None
686 };
687
688 let delay_mix = if let Some(Value::Number(m)) = context.get("delay_mix") {
689 Some(*m)
690 } else {
691 None
692 };
693
694 let reverb_amount = if let Some(Value::Number(a)) = context.get("reverb_amount") {
695 Some(*a)
696 } else {
697 None
698 };
699
700 let drive_amount = if let Some(Value::Number(a)) = context.get("drive_amount") {
701 Some(*a)
702 } else {
703 None
704 };
705
706 let drive_color = if let Some(Value::Number(c)) = context.get("drive_color") {
707 Some(*c)
708 } else {
709 None
710 };
711
712 self.events.add_note_event(
713 target,
714 midi,
715 context.start_time,
716 duration,
717 velocity,
718 pan,
719 detune,
720 gain,
721 attack,
722 release,
723 delay_time,
724 delay_feedback,
725 delay_mix,
726 reverb_amount,
727 drive_amount,
728 drive_color,
729 );
730
731 #[cfg(target_arch = "wasm32")]
733 {
734 use crate::web::registry::playhead::{PlayheadEvent, push_event};
735
736 push_event(PlayheadEvent {
738 event_type: "note_on".to_string(),
739 midi: vec![midi],
740 time: context.start_time,
741 velocity,
742 synth_id: target.to_string(),
743 });
744
745 push_event(PlayheadEvent {
747 event_type: "note_off".to_string(),
748 midi: vec![midi],
749 time: context.start_time + duration,
750 velocity,
751 synth_id: target.to_string(),
752 });
753 }
754 }
755
756 if let Some(Value::Array(notes)) = context.get("notes") {
758 let mut midis = Vec::new();
759 for note_val in notes {
760 if let Value::String(note_name) = note_val {
761 midis.push(parse_note_to_midi(note_name)?);
762 }
763 }
764
765 let duration = if let Some(Value::Number(d)) = context.get("duration") {
766 d / 1000.0
767 } else {
768 0.5
769 };
770 let velocity = if let Some(Value::Number(v)) = context.get("velocity") {
771 v / 100.0
772 } else {
773 0.8
774 };
775
776 let pan = if let Some(Value::Number(p)) = context.get("pan") {
778 *p
779 } else {
780 0.0
781 };
782
783 let detune = if let Some(Value::Number(d)) = context.get("detune") {
784 *d
785 } else {
786 0.0
787 };
788
789 let spread = if let Some(Value::Number(s)) = context.get("spread") {
790 *s
791 } else {
792 0.0
793 };
794
795 let gain = if let Some(Value::Number(g)) = context.get("gain") {
796 *g
797 } else {
798 1.0
799 };
800
801 let attack = if let Some(Value::Number(a)) = context.get("attack") {
802 Some(*a)
803 } else {
804 None
805 };
806
807 let release = if let Some(Value::Number(r)) = context.get("release") {
808 Some(*r)
809 } else {
810 None
811 };
812
813 let delay_time = if let Some(Value::Number(t)) = context.get("delay_time") {
815 Some(*t)
816 } else {
817 None
818 };
819
820 let delay_feedback = if let Some(Value::Number(f)) = context.get("delay_feedback") {
821 Some(*f)
822 } else {
823 None
824 };
825
826 let delay_mix = if let Some(Value::Number(m)) = context.get("delay_mix") {
827 Some(*m)
828 } else {
829 None
830 };
831
832 let reverb_amount = if let Some(Value::Number(a)) = context.get("reverb_amount") {
833 Some(*a)
834 } else {
835 None
836 };
837
838 let drive_amount = if let Some(Value::Number(a)) = context.get("drive_amount") {
839 Some(*a)
840 } else {
841 None
842 };
843
844 let drive_color = if let Some(Value::Number(c)) = context.get("drive_color") {
845 Some(*c)
846 } else {
847 None
848 };
849
850 self.events.add_chord_event(
851 target,
852 midis.clone(),
853 context.start_time,
854 duration,
855 velocity,
856 pan,
857 detune,
858 spread,
859 gain,
860 attack,
861 release,
862 delay_time,
863 delay_feedback,
864 delay_mix,
865 reverb_amount,
866 drive_amount,
867 drive_color,
868 );
869
870 #[cfg(target_arch = "wasm32")]
872 {
873 use crate::web::registry::playhead::{PlayheadEvent, push_event};
874
875 push_event(PlayheadEvent {
877 event_type: "chord_on".to_string(),
878 midi: midis.clone(),
879 time: context.start_time,
880 velocity,
881 synth_id: target.to_string(),
882 });
883
884 push_event(PlayheadEvent {
886 event_type: "chord_off".to_string(),
887 midi: midis,
888 time: context.start_time + duration,
889 velocity,
890 synth_id: target.to_string(),
891 });
892 }
893 }
894
895 Ok(())
896 }
897
898 fn render_audio(&self) -> Result<Vec<f32>> {
899 let total_duration = self.events.total_duration();
900 if total_duration <= 0.0 {
901 return Ok(Vec::new());
902 }
903
904 let total_samples = (total_duration * self.sample_rate as f32).ceil() as usize;
905 let mut buffer = vec![0.0f32; total_samples * 2]; let mut _note_count = 0;
909 let mut _chord_count = 0;
910 let mut _sample_count = 0;
911 for event in &self.events.events {
912 match event {
913 crate::engine::audio::events::AudioEvent::Note { .. } => _note_count += 1,
914 crate::engine::audio::events::AudioEvent::Chord { .. } => _chord_count += 1,
915 crate::engine::audio::events::AudioEvent::Sample { .. } => _sample_count += 1,
916 }
917 }
918
919 for event in &self.events.events {
921 match event {
922 crate::engine::audio::events::AudioEvent::Note {
923 midi,
924 start_time,
925 duration,
926 velocity,
927 synth_id,
928 pan,
929 detune,
930 gain,
931 attack,
932 release,
933 delay_time,
934 delay_feedback,
935 delay_mix,
936 reverb_amount,
937 drive_amount,
938 drive_color,
939 } => {
940 let synth_def = self.events.get_synth(synth_id).cloned().unwrap_or_default();
941
942 let mut params = SynthParams {
943 waveform: synth_def.waveform,
944 attack: synth_def.attack,
945 decay: synth_def.decay,
946 sustain: synth_def.sustain,
947 release: synth_def.release,
948 synth_type: synth_def.synth_type.clone(),
949 filters: synth_def.filters.clone(),
950 options: synth_def.options.clone(),
951 };
952
953 if let Some(a) = attack {
955 params.attack = a / 1000.0; }
957 if let Some(r) = release {
958 params.release = r / 1000.0; }
960
961 let mut samples = generate_note_with_options(
962 *midi,
963 duration * 1000.0,
964 velocity * gain, ¶ms,
966 self.sample_rate,
967 *pan,
968 *detune,
969 )?;
970
971 if let Some(amount) = drive_amount {
975 let color = drive_color.unwrap_or(0.5);
976 let mix = 0.7; let mut processor = DriveProcessor::new(*amount, color, mix);
978 processor.process(&mut samples, self.sample_rate);
979 }
980
981 if let Some(amount) = reverb_amount {
983 let room_size = *amount; let damping = 0.5; let mix = *amount * 0.5; let mut processor = ReverbProcessor::new(room_size, damping, mix);
987 processor.process(&mut samples, self.sample_rate);
988 }
989
990 if let Some(time) = delay_time {
992 let feedback = delay_feedback.unwrap_or(0.3);
993 let mix = delay_mix.unwrap_or(0.5);
994 let mut processor = DelayProcessor::new(*time, feedback, mix);
995 processor.process(&mut samples, self.sample_rate);
996 }
997
998 let start_sample = (*start_time * self.sample_rate as f32) as usize * 2;
1000 for (i, &sample) in samples.iter().enumerate() {
1001 let buf_idx = start_sample + i;
1002 if buf_idx < buffer.len() {
1003 buffer[buf_idx] += sample;
1004 }
1005 }
1006 }
1007
1008 crate::engine::audio::events::AudioEvent::Chord {
1009 midis,
1010 start_time,
1011 duration,
1012 velocity,
1013 synth_id,
1014 pan,
1015 detune,
1016 spread,
1017 gain,
1018 attack,
1019 release,
1020 delay_time,
1021 delay_feedback,
1022 delay_mix,
1023 reverb_amount,
1024 drive_amount,
1025 drive_color,
1026 } => {
1027 let synth_def = self.events.get_synth(synth_id).cloned().unwrap_or_default();
1028
1029 let mut params = SynthParams {
1030 waveform: synth_def.waveform,
1031 attack: synth_def.attack,
1032 decay: synth_def.decay,
1033 sustain: synth_def.sustain,
1034 release: synth_def.release,
1035 synth_type: synth_def.synth_type.clone(),
1036 filters: synth_def.filters.clone(),
1037 options: synth_def.options.clone(),
1038 };
1039
1040 if let Some(a) = attack {
1042 params.attack = a / 1000.0; }
1044 if let Some(r) = release {
1045 params.release = r / 1000.0; }
1047
1048 let mut samples = generate_chord_with_options(
1049 midis,
1050 duration * 1000.0,
1051 velocity * gain, ¶ms,
1053 self.sample_rate,
1054 *pan,
1055 *detune,
1056 *spread,
1057 )?;
1058
1059 if let Some(amount) = drive_amount {
1063 let color = drive_color.unwrap_or(0.5);
1064 let mix = 0.7; let mut processor = DriveProcessor::new(*amount, color, mix);
1066 processor.process(&mut samples, self.sample_rate);
1067 }
1068
1069 if let Some(amount) = reverb_amount {
1071 let room_size = *amount; let damping = 0.5; let mix = *amount * 0.5; let mut processor = ReverbProcessor::new(room_size, damping, mix);
1075 processor.process(&mut samples, self.sample_rate);
1076 }
1077
1078 if let Some(time) = delay_time {
1080 let feedback = delay_feedback.unwrap_or(0.3);
1081 let mix = delay_mix.unwrap_or(0.5);
1082 let mut processor = DelayProcessor::new(*time, feedback, mix);
1083 processor.process(&mut samples, self.sample_rate);
1084 }
1085
1086 let start_sample = (*start_time * self.sample_rate as f32) as usize * 2;
1088 for (i, &sample) in samples.iter().enumerate() {
1089 let buf_idx = start_sample + i;
1090 if buf_idx < buffer.len() {
1091 buffer[buf_idx] += sample;
1092 }
1093 }
1094 }
1095
1096 crate::engine::audio::events::AudioEvent::Sample {
1097 uri,
1098 start_time,
1099 velocity,
1100 } => {
1101 #[cfg(target_arch = "wasm32")]
1103 {
1104 use crate::web::registry::samples::get_sample;
1105
1106 if let Some(pcm_data) = get_sample(uri) {
1107 let start_sample_idx = (*start_time * self.sample_rate as f32) as usize;
1109
1110 web_sys::console::log_1(
1111 &format!(
1112 "🔊 Rendering sample: {} at {:.3}s, {} frames, velocity {:.2}",
1113 uri,
1114 start_time,
1115 pcm_data.len(),
1116 velocity
1117 )
1118 .into(),
1119 );
1120 web_sys::console::log_1(
1121 &format!(
1122 " Start buffer index: {} (stereo pos: {})",
1123 start_sample_idx,
1124 start_sample_idx * 2
1125 )
1126 .into(),
1127 );
1128
1129 for (i, &pcm_value) in pcm_data.iter().enumerate() {
1131 let sample = (pcm_value as f32 / 32768.0) * velocity;
1133
1134 let stereo_pos = (start_sample_idx + i) * 2;
1136 let buf_idx_l = stereo_pos;
1137 let buf_idx_r = stereo_pos + 1;
1138
1139 if buf_idx_l < buffer.len() {
1141 buffer[buf_idx_l] += sample;
1142 }
1143 if buf_idx_r < buffer.len() {
1144 buffer[buf_idx_r] += sample;
1145 }
1146 }
1147 } else {
1148 println!("⚠️ Sample not found in registry: {}", uri);
1149 }
1150 }
1151
1152 #[cfg(not(target_arch = "wasm32"))]
1154 {
1155 let _ = (start_time, velocity); println!("⚠️ Sample playback not supported in native build: {}", uri);
1157 }
1158 }
1159 }
1160 }
1161
1162 let max_amplitude = buffer.iter().map(|&s| s.abs()).fold(0.0f32, f32::max);
1164 if max_amplitude > 1.0 {
1165 for sample in buffer.iter_mut() {
1166 *sample /= max_amplitude;
1167 }
1168 }
1169
1170 Ok(buffer)
1171 }
1172
1173 pub fn set_bpm(&mut self, bpm: f32) {
1174 self.bpm = bpm.max(1.0).min(999.0);
1175 }
1176
1177 pub fn samples_per_beat(&self) -> usize {
1178 ((60.0 / self.bpm) * self.sample_rate as f32) as usize
1179 }
1180
1181 pub fn beat_duration(&self) -> f32 {
1183 60.0 / self.bpm
1184 }
1185
1186 fn execute_print(&self, value: &Value) -> Result<()> {
1189 let message = match value {
1190 Value::String(s) => {
1191 if s.contains('{') && s.contains('}') {
1193 self.interpolate_string(s)
1194 } else {
1195 s.clone()
1196 }
1197 }
1198 Value::Number(n) => n.to_string(),
1199 Value::Boolean(b) => b.to_string(),
1200 Value::Array(arr) => format!("{:?}", arr),
1201 Value::Map(map) => format!("{:?}", map),
1202 _ => format!("{:?}", value),
1203 };
1204
1205 println!("💬 {}", message);
1206 Ok(())
1207 }
1208
1209 fn interpolate_string(&self, template: &str) -> String {
1212 let mut result = template.to_string();
1213
1214 let re = regex::Regex::new(r"\{([a-zA-Z_][a-zA-Z0-9_]*)\}").unwrap();
1216
1217 for cap in re.captures_iter(template) {
1218 let full_match = &cap[0]; let var_name = &cap[1]; if let Some(value) = self.variables.get(var_name) {
1222 let replacement = self.value_to_string(value);
1223 result = result.replace(full_match, &replacement);
1224 } else {
1225 result = result.replace(full_match, &format!("<undefined:{}>", var_name));
1227 }
1228 }
1229
1230 result
1231 }
1232
1233 fn value_to_string(&self, value: &Value) -> String {
1235 match value {
1236 Value::String(s) => {
1237 s.trim_matches('"').trim_matches('\'').to_string()
1239 }
1240 Value::Number(n) => {
1241 if n.fract() == 0.0 {
1243 format!("{:.0}", n)
1244 } else {
1245 format!("{}", n)
1246 }
1247 }
1248 Value::Boolean(b) => b.to_string(),
1249 Value::Array(arr) => {
1250 let items: Vec<String> = arr.iter().map(|v| self.value_to_string(v)).collect();
1251 format!("[{}]", items.join(", "))
1252 }
1253 Value::Identifier(id) => id.clone(),
1254 _ => format!("{:?}", value),
1255 }
1256 }
1257
1258 fn execute_if(
1260 &mut self,
1261 condition: &Value,
1262 body: &[Statement],
1263 else_body: &Option<Vec<Statement>>,
1264 ) -> Result<()> {
1265 let condition_result = self.evaluate_condition(condition)?;
1266
1267 if condition_result {
1268 self.collect_events(body)?;
1270 } else if let Some(else_stmts) = else_body {
1271 self.collect_events(else_stmts)?;
1273 }
1274
1275 Ok(())
1276 }
1277
1278 fn evaluate_condition(&self, condition: &Value) -> Result<bool> {
1281 if let Value::Map(map) = condition {
1283 let operator = map
1284 .get("operator")
1285 .and_then(|v| {
1286 if let Value::String(s) = v {
1287 Some(s.as_str())
1288 } else {
1289 None
1290 }
1291 })
1292 .unwrap_or("==");
1293
1294 let left = map
1295 .get("left")
1296 .ok_or_else(|| anyhow::anyhow!("Missing left operand"))?;
1297 let right = map
1298 .get("right")
1299 .ok_or_else(|| anyhow::anyhow!("Missing right operand"))?;
1300
1301 let left_val = self.resolve_value(left);
1303 let right_val = self.resolve_value(right);
1304
1305 match operator {
1307 "==" => Ok(self.values_equal(&left_val, &right_val)),
1308 "!=" => Ok(!self.values_equal(&left_val, &right_val)),
1309 "<" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less),
1310 ">" => self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater),
1311 "<=" => {
1312 let less =
1313 self.compare_values(&left_val, &right_val, std::cmp::Ordering::Less)?;
1314 let equal = self.values_equal(&left_val, &right_val);
1315 Ok(less || equal)
1316 }
1317 ">=" => {
1318 let greater =
1319 self.compare_values(&left_val, &right_val, std::cmp::Ordering::Greater)?;
1320 let equal = self.values_equal(&left_val, &right_val);
1321 Ok(greater || equal)
1322 }
1323 _ => Err(anyhow::anyhow!("Unknown operator: {}", operator)),
1324 }
1325 } else {
1326 match condition {
1328 Value::Boolean(b) => Ok(*b),
1329 Value::Number(n) => Ok(*n != 0.0),
1330 Value::String(s) => Ok(!s.is_empty()),
1331 _ => Ok(false),
1332 }
1333 }
1334 }
1335
1336 fn resolve_value(&self, value: &Value) -> Value {
1338 match value {
1339 Value::Identifier(name) => {
1340 if is_special_var(name) {
1342 if let Some(special_val) = resolve_special_var(name, &self.special_vars) {
1343 return special_val;
1344 }
1345 }
1346
1347 self.variables.get(name).cloned().unwrap_or(Value::Null)
1349 }
1350 _ => value.clone(),
1351 }
1352 }
1353
1354 fn execute_event_handlers(&mut self, event_name: &str) -> Result<()> {
1356 let handlers = self.event_registry.get_handlers_matching(event_name);
1357
1358 for (index, handler) in handlers.iter().enumerate() {
1359 if handler.once && !self.event_registry.should_execute_once(event_name, index) {
1361 continue;
1362 }
1363
1364 let body_clone = handler.body.clone();
1366 self.collect_events(&body_clone)?;
1367 }
1368
1369 Ok(())
1370 }
1371
1372 fn values_equal(&self, left: &Value, right: &Value) -> bool {
1374 match (left, right) {
1375 (Value::Number(a), Value::Number(b)) => (a - b).abs() < 0.0001,
1376 (Value::String(a), Value::String(b)) => a == b,
1377 (Value::Boolean(a), Value::Boolean(b)) => a == b,
1378 (Value::Null, Value::Null) => true,
1379 _ => false,
1380 }
1381 }
1382
1383 fn compare_values(
1385 &self,
1386 left: &Value,
1387 right: &Value,
1388 ordering: std::cmp::Ordering,
1389 ) -> Result<bool> {
1390 match (left, right) {
1391 (Value::Number(a), Value::Number(b)) => {
1392 Ok(a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal) == ordering)
1393 }
1394 (Value::String(a), Value::String(b)) => Ok(a.cmp(b) == ordering),
1395 _ => Err(anyhow::anyhow!("Cannot compare {:?} and {:?}", left, right)),
1396 }
1397 }
1398
1399 fn handle_assign(&mut self, target: &str, property: &str, value: &Value) -> Result<()> {
1401 if let Some(var) = self.variables.get_mut(target) {
1403 if let Value::Map(map) = var {
1404 map.insert(property.to_string(), value.clone());
1406
1407 if self.events.synths.contains_key(target) {
1409 let map_clone = map.clone();
1411 let updated_def = self.extract_synth_def_from_map(&map_clone)?;
1413 self.events.synths.insert(target.to_string(), updated_def);
1414 println!("🔧 Updated {}.{} = {:?}", target, property, value);
1415 }
1416 } else {
1417 return Err(anyhow::anyhow!(
1418 "Cannot assign property '{}' to non-map variable '{}'",
1419 property,
1420 target
1421 ));
1422 }
1423 } else {
1424 return Err(anyhow::anyhow!("Variable '{}' not found", target));
1425 }
1426
1427 Ok(())
1428 }
1429
1430 fn extract_synth_def_from_map(&self, map: &HashMap<String, Value>) -> Result<SynthDefinition> {
1432 use crate::engine::audio::events::extract_filters;
1433
1434 let waveform = extract_string(map, "waveform", "sine");
1435 let attack = extract_number(map, "attack", 0.01);
1436 let decay = extract_number(map, "decay", 0.1);
1437 let sustain = extract_number(map, "sustain", 0.7);
1438 let release = extract_number(map, "release", 0.2);
1439
1440 let synth_type = if let Some(Value::String(t)) = map.get("type") {
1441 let clean = t.trim_matches('"').trim_matches('\'');
1442 if clean.is_empty() || clean == "synth" {
1443 None
1444 } else {
1445 Some(clean.to_string())
1446 }
1447 } else {
1448 None
1449 };
1450
1451 let filters = if let Some(Value::Array(filters_arr)) = map.get("filters") {
1452 extract_filters(filters_arr)
1453 } else {
1454 Vec::new()
1455 };
1456
1457 let mut options = HashMap::new();
1458 for (key, val) in map.iter() {
1459 if ![
1460 "waveform", "attack", "decay", "sustain", "release", "type", "filters",
1461 ]
1462 .contains(&key.as_str())
1463 {
1464 if let Value::Number(n) = val {
1465 options.insert(key.clone(), *n);
1466 }
1467 }
1468 }
1469
1470 Ok(SynthDefinition {
1471 waveform,
1472 attack,
1473 decay,
1474 sustain,
1475 release,
1476 synth_type,
1477 filters,
1478 options,
1479 })
1480 }
1481
1482 fn handle_load(&mut self, source: &str, alias: &str) -> Result<()> {
1484 use crate::engine::audio::midi::load_midi_file;
1485 use std::path::Path;
1486
1487 let path = Path::new(source);
1489 let midi_data = load_midi_file(path)?;
1490
1491 self.variables.insert(alias.to_string(), midi_data);
1493
1494 println!("🎵 Loaded MIDI file: {} as {}", source, alias);
1495
1496 Ok(())
1497 }
1498
1499 fn handle_bind(&mut self, source: &str, target: &str, options: &Value) -> Result<()> {
1501 let midi_data = self
1503 .variables
1504 .get(source)
1505 .ok_or_else(|| anyhow::anyhow!("MIDI source '{}' not found", source))?
1506 .clone();
1507
1508 if let Value::Map(midi_map) = &midi_data {
1510 let notes = midi_map
1511 .get("notes")
1512 .ok_or_else(|| anyhow::anyhow!("MIDI data has no notes"))?;
1513
1514 if let Value::Array(notes_array) = notes {
1515 let _synth_def = self
1517 .events
1518 .synths
1519 .get(target)
1520 .ok_or_else(|| anyhow::anyhow!("Synth '{}' not found", target))?
1521 .clone();
1522
1523 let default_velocity = 100;
1525 let mut velocity = default_velocity;
1526
1527 if let Value::Map(opts) = options {
1528 if let Some(Value::Number(v)) = opts.get("velocity") {
1529 velocity = *v as u8;
1530 }
1531 }
1532
1533 for note_val in notes_array {
1535 if let Value::Map(note_map) = note_val {
1536 let time = extract_number(note_map, "time", 0.0);
1537 let note = extract_number(note_map, "note", 60.0) as u8;
1538 let note_velocity =
1539 extract_number(note_map, "velocity", velocity as f32) as u8;
1540
1541 use crate::engine::audio::events::AudioEvent;
1543 let event = AudioEvent::Note {
1544 midi: note,
1545 start_time: time / 1000.0, duration: 0.5, velocity: note_velocity as f32,
1548 synth_id: target.to_string(),
1549 pan: 0.0,
1550 detune: 0.0,
1551 gain: 1.0,
1552 attack: None,
1553 release: None,
1554 delay_time: None,
1555 delay_feedback: None,
1556 delay_mix: None,
1557 reverb_amount: None,
1558 drive_amount: None,
1559 drive_color: None,
1560 };
1561
1562 self.events.events.push(event);
1563 }
1564 }
1565
1566 println!(
1567 "🔗 Bound {} notes from {} to {}",
1568 notes_array.len(),
1569 source,
1570 target
1571 );
1572 }
1573 }
1574
1575 Ok(())
1576 }
1577}