@devaloop/devalang 0.0.1-alpha.16-hotfix.3 → 0.0.1-alpha.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cargo/config.toml +2 -0
- package/.devalang +10 -10
- package/.github/workflows/ci.yml +0 -1
- package/Cargo.toml +18 -2
- package/README.md +82 -34
- package/docs/CHANGELOG.md +91 -0
- package/docs/ROADMAP.md +7 -4
- package/docs/TODO.md +1 -1
- package/examples/index.deva +55 -35
- package/examples/pattern.deva +5 -5
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/core/functions/index.d.ts +37 -0
- package/out-tsc/core/functions/index.js +76 -0
- package/out-tsc/core/index.d.ts +6 -0
- package/out-tsc/core/index.js +22 -0
- package/out-tsc/core/types/index.d.ts +4 -0
- package/out-tsc/core/types/index.js +20 -0
- package/out-tsc/core/types/plugin.d.ts +18 -0
- package/out-tsc/core/types/plugin.js +2 -0
- package/out-tsc/core/types/result.d.ts +27 -0
- package/out-tsc/core/types/result.js +2 -0
- package/out-tsc/core/types/statement.d.ts +106 -0
- package/out-tsc/core/types/statement.js +2 -0
- package/out-tsc/core/types/value.d.ts +43 -0
- package/out-tsc/core/types/value.js +2 -0
- package/out-tsc/index.d.ts +7 -0
- package/out-tsc/index.js +41 -2
- package/out-tsc/pkg/devalang_core.d.ts +7 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
- package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
- package/out-tsc/scripts/copy-wasm-dts.js +73 -0
- package/out-tsc/scripts/postinstall.d.ts +1 -0
- package/out-tsc/scripts/postinstall.js +33 -23
- package/out-tsc/scripts/version/bump.d.ts +1 -0
- package/out-tsc/scripts/version/fetch.d.ts +1 -0
- package/out-tsc/scripts/version/index.d.ts +1 -0
- package/out-tsc/scripts/version/sync.d.ts +1 -0
- package/package.json +16 -4
- package/project-version.json +3 -3
- package/rust/cli/bank/api.rs +122 -0
- package/rust/cli/bank/commands.rs +275 -0
- package/rust/cli/bank/mod.rs +29 -0
- package/rust/cli/build/commands.rs +107 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/{check.rs → check/mod.rs} +18 -31
- package/rust/cli/discover/commands.rs +253 -0
- package/rust/cli/discover/config.rs +111 -0
- package/rust/cli/discover/fs.rs +19 -0
- package/rust/cli/discover/install.rs +103 -0
- package/rust/cli/discover/metadata.rs +48 -0
- package/rust/cli/discover/mod.rs +5 -0
- package/rust/cli/{init.rs → init/commands.rs} +88 -87
- package/rust/cli/init/mod.rs +1 -0
- package/rust/cli/install/addon.rs +126 -0
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/{install.rs → install/commands.rs} +9 -9
- package/rust/{installer → cli/install}/mod.rs +2 -3
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/{login.rs → login/commands.rs} +8 -11
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +2 -2
- package/rust/cli/{driver.rs → parser.rs} +7 -2
- package/rust/cli/play/commands.rs +324 -0
- package/rust/cli/play/io.rs +17 -0
- package/rust/cli/play/mod.rs +5 -0
- package/rust/cli/play/process.rs +150 -0
- package/rust/cli/play/realtime.rs +91 -0
- package/rust/cli/play/utils.rs +23 -0
- package/rust/cli/{telemetry.rs → telemetry/commands.rs} +4 -4
- package/rust/cli/telemetry/event_creator.rs +80 -0
- package/rust/cli/telemetry/mod.rs +3 -0
- package/rust/cli/telemetry/send.rs +51 -0
- package/rust/cli/{template.rs → template/commands.rs} +1 -1
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/{update.rs → update/commands.rs} +6 -6
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +57 -72
- package/rust/config/mod.rs +1 -2
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +40 -42
- package/rust/core/audio/engine/helpers.rs +158 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +359 -0
- package/rust/core/audio/engine/synth.rs +325 -0
- package/rust/core/audio/evaluator.rs +68 -27
- package/rust/core/audio/interpreter/arrow_call.rs +113 -33
- package/rust/core/audio/interpreter/call.rs +232 -56
- package/rust/core/audio/interpreter/condition.rs +3 -2
- package/rust/core/audio/interpreter/driver.rs +206 -151
- package/rust/core/audio/interpreter/let_.rs +1 -1
- package/rust/core/audio/interpreter/load.rs +2 -1
- package/rust/core/audio/interpreter/loop_.rs +7 -6
- package/rust/core/audio/interpreter/sleep.rs +2 -1
- package/rust/core/audio/interpreter/spawn.rs +186 -54
- package/rust/core/audio/interpreter/tempo.rs +31 -10
- package/rust/core/audio/interpreter/trigger.rs +2 -2
- package/rust/core/audio/loader/trigger.rs +4 -7
- package/rust/core/audio/player.rs +6 -0
- package/rust/core/audio/renderer.rs +5 -7
- package/rust/core/audio/special/env.rs +3 -1
- package/rust/core/audio/special/math.rs +26 -6
- package/rust/core/audio/special/modulator.rs +2 -2
- package/rust/core/builder/mod.rs +9 -3
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +6 -0
- package/rust/core/debugger/module.rs +4 -4
- package/rust/core/debugger/preprocessor.rs +1 -1
- package/rust/core/debugger/store.rs +2 -2
- package/rust/core/error/mod.rs +189 -0
- package/rust/core/lexer/driver.rs +61 -0
- package/rust/core/lexer/handler/arrow.rs +1 -1
- package/rust/core/lexer/handler/at.rs +1 -1
- package/rust/core/lexer/handler/brace.rs +2 -2
- package/rust/core/lexer/handler/colon.rs +1 -1
- package/rust/core/lexer/handler/comment.rs +1 -1
- package/rust/core/lexer/handler/dot.rs +1 -1
- package/rust/core/lexer/handler/driver.rs +1 -1
- package/rust/core/lexer/handler/identifier.rs +4 -3
- package/rust/core/lexer/handler/mod.rs +1 -2
- package/rust/core/lexer/handler/number.rs +1 -1
- package/rust/core/lexer/handler/operator.rs +1 -1
- package/rust/core/lexer/handler/parenthesis.rs +2 -2
- package/rust/core/lexer/handler/slash.rs +1 -1
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +1 -52
- package/rust/core/lexer/token.rs +91 -97
- package/rust/core/mod.rs +0 -1
- package/rust/core/parser/driver.rs +78 -22
- package/rust/core/parser/handler/arrow_call.rs +28 -8
- package/rust/core/parser/handler/at.rs +55 -21
- package/rust/core/parser/handler/bank.rs +14 -4
- package/rust/core/parser/handler/condition.rs +6 -3
- package/rust/core/parser/handler/dot.rs +5 -3
- package/rust/core/parser/handler/identifier/automate.rs +13 -16
- package/rust/core/parser/handler/identifier/call.rs +4 -4
- package/rust/core/parser/handler/identifier/emit.rs +9 -5
- package/rust/core/parser/handler/identifier/function.rs +20 -7
- package/rust/core/parser/handler/identifier/group.rs +11 -7
- package/rust/core/parser/handler/identifier/let_.rs +24 -9
- package/rust/core/parser/handler/identifier/mod.rs +6 -5
- package/rust/core/parser/handler/identifier/on.rs +16 -7
- package/rust/core/parser/handler/identifier/print.rs +6 -9
- package/rust/core/parser/handler/identifier/sleep.rs +12 -5
- package/rust/core/parser/handler/identifier/spawn.rs +4 -4
- package/rust/core/parser/handler/identifier/synth.rs +79 -9
- package/rust/core/parser/handler/loop_.rs +38 -13
- package/rust/core/parser/handler/mod.rs +1 -0
- package/rust/core/parser/handler/pattern.rs +74 -0
- package/rust/core/parser/handler/tempo.rs +9 -5
- package/rust/core/parser/mod.rs +0 -1
- package/rust/core/parser/statement.rs +6 -137
- package/rust/core/plugin/loader.rs +41 -27
- package/rust/core/plugin/runner.rs +68 -17
- package/rust/core/preprocessor/loader.rs +181 -99
- package/rust/core/preprocessor/processor.rs +9 -9
- package/rust/core/preprocessor/resolver/bank.rs +6 -8
- package/rust/core/preprocessor/resolver/call.rs +47 -23
- package/rust/core/preprocessor/resolver/condition.rs +6 -8
- package/rust/core/preprocessor/resolver/driver.rs +28 -28
- package/rust/core/preprocessor/resolver/function.rs +6 -6
- package/rust/core/preprocessor/resolver/group.rs +6 -8
- package/rust/core/preprocessor/resolver/loop_.rs +8 -10
- package/rust/core/preprocessor/resolver/mod.rs +1 -0
- package/rust/core/preprocessor/resolver/pattern.rs +75 -0
- package/rust/core/preprocessor/resolver/spawn.rs +45 -22
- package/rust/core/preprocessor/resolver/synth.rs +6 -8
- package/rust/core/preprocessor/resolver/tempo.rs +6 -8
- package/rust/core/preprocessor/resolver/trigger.rs +22 -19
- package/rust/core/preprocessor/resolver/value.rs +99 -4
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +6 -0
- package/rust/core/store/global.rs +7 -1
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/variable.rs +16 -2
- package/rust/core/utils/mod.rs +0 -1
- package/rust/lib.rs +102 -9
- package/rust/main.rs +159 -45
- package/rust/types/Cargo.toml +11 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +202 -0
- package/rust/types/src/config.rs +74 -0
- package/rust/types/src/lib.rs +12 -0
- package/rust/types/src/telemetry.rs +85 -0
- package/rust/utils/Cargo.toml +26 -0
- package/rust/utils/{error.rs → src/error.rs} +186 -200
- package/rust/utils/src/file.rs +94 -0
- package/rust/utils/src/first_usage.rs +97 -0
- package/rust/utils/{mod.rs → src/lib.rs} +1 -1
- package/rust/utils/{logger.rs → src/logger.rs} +17 -12
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
- package/rust/web/cdn.rs +34 -0
- package/templates/minimal/README.md +98 -54
- package/templates/welcome/README.md +98 -54
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/rust/TODO.md +0 -0
- package/tests/typescript/index.spec.ts +136 -0
- package/tests/typescript/playhead.spec.ts +36 -0
- package/tests/typescript/render_e2e.spec.ts +77 -0
- package/tsconfig.json +1 -1
- package/typescript/core/functions/index.ts +83 -0
- package/typescript/core/index.ts +6 -0
- package/typescript/core/types/index.ts +4 -0
- package/typescript/core/types/plugin.ts +19 -0
- package/typescript/core/types/result.ts +29 -0
- package/typescript/core/types/statement.ts +47 -0
- package/typescript/core/types/value.ts +29 -0
- package/typescript/index.ts +7 -2
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/rust/cli/bank.rs +0 -462
- package/rust/cli/build.rs +0 -252
- package/rust/cli/play.rs +0 -1123
- package/rust/common/cdn.rs +0 -5
- package/rust/config/loader.rs +0 -165
- package/rust/config/stats.rs +0 -257
- package/rust/core/audio/engine.rs +0 -696
- package/rust/core/shared/bank.rs +0 -21
- package/rust/core/shared/duration.rs +0 -9
- package/rust/core/shared/mod.rs +0 -3
- package/rust/core/shared/value.rs +0 -35
- package/rust/core/utils/validation.rs +0 -35
- package/rust/installer/addon.rs +0 -84
- package/rust/installer/bank.rs +0 -62
- package/rust/installer/plugin.rs +0 -54
- package/rust/installer/utils.rs +0 -56
- package/rust/utils/file.rs +0 -38
- package/rust/utils/first_usage.rs +0 -83
- package/rust/utils/signature.rs +0 -19
- package/rust/utils/telemetry.rs +0 -292
- package/rust/utils/version.rs +0 -15
- /package/rust/{common → web}/api.rs +0 -0
- /package/rust/{common → web}/mod.rs +0 -0
- /package/rust/{common → web}/sso.rs +0 -0
|
@@ -2,7 +2,8 @@ use crate::core::audio::special::{
|
|
|
2
2
|
find_and_eval_first_easing_call, find_and_eval_first_math_call, find_and_eval_first_mod_call,
|
|
3
3
|
resolve_env_atom,
|
|
4
4
|
};
|
|
5
|
-
use crate::core::
|
|
5
|
+
use crate::core::store::variable::VariableTable;
|
|
6
|
+
use devalang_types::Value;
|
|
6
7
|
|
|
7
8
|
pub fn evaluate_condition_string(expr: &str, vars: &VariableTable) -> bool {
|
|
8
9
|
let tokens: Vec<&str> = expr.split_whitespace().collect();
|
|
@@ -14,22 +15,46 @@ pub fn evaluate_condition_string(expr: &str, vars: &VariableTable) -> bool {
|
|
|
14
15
|
let op = tokens[1];
|
|
15
16
|
let right = tokens[2];
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return
|
|
18
|
+
// Resolve left and right to numeric values where possible. Accept numbers, variables or env atoms.
|
|
19
|
+
fn resolve_for_cond(s: &str, vars: &VariableTable) -> Option<f32> {
|
|
20
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
21
|
+
return Some(n);
|
|
22
|
+
}
|
|
23
|
+
if let Some(Value::Number(n)) = vars.get(s) {
|
|
24
|
+
return Some(*n);
|
|
21
25
|
}
|
|
26
|
+
if let Some(v) = resolve_env_atom(s, 120.0, 1.0) {
|
|
27
|
+
return Some(v);
|
|
28
|
+
}
|
|
29
|
+
None
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let left_val = match resolve_for_cond(left, vars) {
|
|
33
|
+
Some(v) => v,
|
|
34
|
+
None => return false,
|
|
22
35
|
};
|
|
23
36
|
|
|
24
|
-
let right_val
|
|
37
|
+
let right_val = match resolve_for_cond(right, vars) {
|
|
38
|
+
Some(v) => v,
|
|
39
|
+
None => return false,
|
|
40
|
+
};
|
|
25
41
|
|
|
26
42
|
match op {
|
|
27
43
|
">" => left_val > right_val,
|
|
28
44
|
"<" => left_val < right_val,
|
|
29
45
|
">=" => left_val >= right_val,
|
|
30
46
|
"<=" => left_val <= right_val,
|
|
31
|
-
"==" =>
|
|
32
|
-
|
|
47
|
+
"==" => {
|
|
48
|
+
// relative epsilon for floating comparisons
|
|
49
|
+
let diff = (left_val - right_val).abs();
|
|
50
|
+
let largest = left_val.abs().max(right_val.abs()).max(1.0);
|
|
51
|
+
diff <= (f32::EPSILON * largest)
|
|
52
|
+
}
|
|
53
|
+
"!=" => {
|
|
54
|
+
let diff = (left_val - right_val).abs();
|
|
55
|
+
let largest = left_val.abs().max(right_val.abs()).max(1.0);
|
|
56
|
+
diff > (f32::EPSILON * largest)
|
|
57
|
+
}
|
|
33
58
|
_ => false,
|
|
34
59
|
}
|
|
35
60
|
}
|
|
@@ -61,25 +86,39 @@ pub fn evaluate_numeric_expression(
|
|
|
61
86
|
// Shunting-like, simplified: first evaluate any $math.func(...) calls anywhere in the expression,
|
|
62
87
|
// then fold remaining parentheses and evaluate left-to-right.
|
|
63
88
|
fn eval(expr: &str, vars: &VariableTable, bpm: f32, beat: f32) -> Option<f32> {
|
|
64
|
-
// 1) Replace $math
|
|
89
|
+
// 1) Replace $math/$easing/$mod calls progressively with a max iteration guard
|
|
65
90
|
let mut s = expr.to_string();
|
|
91
|
+
let mut iterations = 0u32;
|
|
92
|
+
const MAX_ITER: u32 = 64;
|
|
93
|
+
|
|
66
94
|
// Evaluate modulators first (they may feed easing/math)
|
|
67
|
-
while
|
|
68
|
-
find_and_eval_first_mod_call(&s, evaluate_numeric_expression, vars, bpm, beat)
|
|
69
|
-
|
|
70
|
-
|
|
95
|
+
while iterations < MAX_ITER {
|
|
96
|
+
if let Some(next) = find_and_eval_first_mod_call(&s, evaluate_numeric_expression, vars, bpm, beat) {
|
|
97
|
+
s = next;
|
|
98
|
+
iterations += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
71
102
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
103
|
+
|
|
104
|
+
iterations = 0;
|
|
105
|
+
while iterations < MAX_ITER {
|
|
106
|
+
if let Some(next) = find_and_eval_first_easing_call(&s, evaluate_numeric_expression, vars, bpm, beat) {
|
|
107
|
+
s = next;
|
|
108
|
+
iterations += 1;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
77
112
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
113
|
+
|
|
114
|
+
iterations = 0;
|
|
115
|
+
while iterations < MAX_ITER {
|
|
116
|
+
if let Some(next) = find_and_eval_first_math_call(&s, evaluate_numeric_expression, vars, bpm, beat) {
|
|
117
|
+
s = next;
|
|
118
|
+
iterations += 1;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
83
122
|
}
|
|
84
123
|
|
|
85
124
|
// 2) Evaluate remaining (pure) parentheses starting from innermost
|
|
@@ -148,7 +187,9 @@ pub fn evaluate_numeric_expression(
|
|
|
148
187
|
}
|
|
149
188
|
}
|
|
150
189
|
(Some(_), None) => val,
|
|
151
|
-
_ =>
|
|
190
|
+
_ => {
|
|
191
|
+
return None;
|
|
192
|
+
}
|
|
152
193
|
});
|
|
153
194
|
}
|
|
154
195
|
|
|
@@ -243,9 +284,9 @@ pub fn evaluate_string_expression(
|
|
|
243
284
|
// Try variables first
|
|
244
285
|
if let Some(val) = vars.get(&p) {
|
|
245
286
|
match val {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
287
|
+
Value::String(s) => out.push_str(s),
|
|
288
|
+
Value::Number(n) => out.push_str(&format!("{}", n)),
|
|
289
|
+
Value::Boolean(b) => out.push_str(&format!("{}", b)),
|
|
249
290
|
other => out.push_str(&format!("{:?}", other)),
|
|
250
291
|
}
|
|
251
292
|
continue;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
2
|
audio::engine::AudioEngine,
|
|
3
3
|
parser::statement::{Statement, StatementKind},
|
|
4
|
-
|
|
5
|
-
store::variable::VariableTable,
|
|
4
|
+
plugin::runner::WasmPluginRunner,
|
|
5
|
+
store::{global::GlobalStore, variable::VariableTable},
|
|
6
6
|
};
|
|
7
|
+
use devalang_types::Value;
|
|
8
|
+
use devalang_utils::logger::{Logger, LogLevel};
|
|
7
9
|
|
|
8
10
|
use std::collections::HashMap;
|
|
9
11
|
|
|
@@ -11,6 +13,7 @@ pub fn interprete_call_arrow_statement(
|
|
|
11
13
|
stmt: &Statement,
|
|
12
14
|
audio_engine: &mut AudioEngine,
|
|
13
15
|
variable_table: &VariableTable,
|
|
16
|
+
global_store: &GlobalStore,
|
|
14
17
|
base_bpm: f32,
|
|
15
18
|
base_duration: f32,
|
|
16
19
|
max_end_time: &mut f32,
|
|
@@ -26,38 +29,44 @@ pub fn interprete_call_arrow_statement(
|
|
|
26
29
|
} = &stmt.kind
|
|
27
30
|
{
|
|
28
31
|
let Some(Value::Statement(synth_stmt)) = variable_table.get(target) else {
|
|
29
|
-
|
|
32
|
+
let logger = Logger::new();
|
|
33
|
+
logger.log_message(LogLevel::Error, &format!("Synth '{}' not found in variable table", target));
|
|
30
34
|
return (*max_end_time, cursor_copy);
|
|
31
35
|
};
|
|
32
36
|
|
|
33
37
|
let Value::Map(synth_map) = &synth_stmt.value else {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
target
|
|
37
|
-
);
|
|
38
|
+
let logger = Logger::new();
|
|
39
|
+
logger.log_message(LogLevel::Error, &format!("Invalid synth statement for '{}', expected a map.", target));
|
|
38
40
|
return (*max_end_time, cursor_copy);
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
let Some(Value::String(entity)) = synth_map.get("entity") else {
|
|
42
|
-
|
|
44
|
+
let logger = Logger::new();
|
|
45
|
+
logger.log_message(LogLevel::Error, &format!("Missing 'entity' key in synth '{}'.", target));
|
|
43
46
|
return (*max_end_time, cursor_copy);
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
if entity != "synth" {
|
|
47
|
-
|
|
50
|
+
let logger = Logger::new();
|
|
51
|
+
logger.log_message(LogLevel::Error, &format!("'{}' is not a synth, entity is '{}'.", target, entity));
|
|
48
52
|
return (*max_end_time, cursor_copy);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
let Some(Value::Map(value_map)) = synth_map.get("value") else {
|
|
52
|
-
|
|
56
|
+
let logger = Logger::new();
|
|
57
|
+
logger.log_message(LogLevel::Error, &format!("Missing 'value' map in synth '{}'.", target));
|
|
53
58
|
return (*max_end_time, cursor_copy);
|
|
54
59
|
};
|
|
55
60
|
|
|
56
|
-
let
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
let waveform_str = match value_map.get("waveform") {
|
|
62
|
+
Some(Value::String(s)) => s.clone(),
|
|
63
|
+
Some(Value::Identifier(s)) => s.clone(),
|
|
64
|
+
_ => {
|
|
65
|
+
let logger = Logger::new();
|
|
66
|
+
logger.log_message(LogLevel::Error, &format!("Missing or invalid 'waveform' in synth '{}'.", target));
|
|
67
|
+
return (*max_end_time, cursor_copy);
|
|
68
|
+
}
|
|
59
69
|
};
|
|
60
|
-
|
|
61
70
|
let Some(Value::Map(params)) = value_map.get("parameters") else {
|
|
62
71
|
println!("❌ Missing or invalid 'parameters' in synth '{}'.", target);
|
|
63
72
|
return (*max_end_time, cursor_copy);
|
|
@@ -73,7 +82,7 @@ pub fn interprete_call_arrow_statement(
|
|
|
73
82
|
.filter(|arg| !matches!(arg, Value::Unknown))
|
|
74
83
|
.collect();
|
|
75
84
|
|
|
76
|
-
let Some(Value::Identifier(note_name)) = filtered_args.
|
|
85
|
+
let Some(Value::Identifier(note_name)) = filtered_args.first().map(|v| (*v).clone())
|
|
77
86
|
else {
|
|
78
87
|
println!(
|
|
79
88
|
"❌ Invalid or missing argument for 'note' method on '{}'.",
|
|
@@ -84,13 +93,10 @@ pub fn interprete_call_arrow_statement(
|
|
|
84
93
|
|
|
85
94
|
let mut note_params = HashMap::new();
|
|
86
95
|
if let Some(arg1) = filtered_args.get(1) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
note_params.insert(key, value);
|
|
91
|
-
}
|
|
96
|
+
if let Value::Map(map) = (*arg1).clone() {
|
|
97
|
+
for (key, value) in map {
|
|
98
|
+
note_params.insert(key, value);
|
|
92
99
|
}
|
|
93
|
-
_ => {}
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
|
|
@@ -134,16 +140,89 @@ pub fn interprete_call_arrow_statement(
|
|
|
134
140
|
_ => None,
|
|
135
141
|
};
|
|
136
142
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
// If waveform references a plugin alias (e.g., alias.synth), use the WASM plugin runner
|
|
144
|
+
if waveform_str.contains('.') && waveform_str.ends_with(".synth") {
|
|
145
|
+
let alias = waveform_str.split('.').next().unwrap_or("");
|
|
146
|
+
if let Some(Value::String(uri)) = variable_table.get(alias) {
|
|
147
|
+
if let Some(id) = uri.strip_prefix("devalang://plugin/") {
|
|
148
|
+
let mut parts = id.split('.');
|
|
149
|
+
let author = parts.next().unwrap_or("");
|
|
150
|
+
let name = parts.next().unwrap_or("");
|
|
151
|
+
let key = format!("{}:{}", author, name);
|
|
152
|
+
if let Some((_info, wasm_bytes)) = global_store.plugins.get(&key) {
|
|
153
|
+
// Prepare buffer (stereo f32)
|
|
154
|
+
let sample_rate = 44100.0_f32;
|
|
155
|
+
let total_samples = ((duration_ms / 1000.0) * sample_rate) as usize;
|
|
156
|
+
let channels = 2usize;
|
|
157
|
+
let start_index = ((start_time * sample_rate) as usize) * channels;
|
|
158
|
+
let required_len = start_index + total_samples * channels;
|
|
159
|
+
if audio_engine.buffer.len() < required_len {
|
|
160
|
+
audio_engine.buffer.resize(required_len, 0);
|
|
161
|
+
}
|
|
162
|
+
let mut fbuf = vec![0.0f32; total_samples * channels];
|
|
163
|
+
let runner = WasmPluginRunner::new();
|
|
164
|
+
let mut params_num: std::collections::HashMap<String, f32> =
|
|
165
|
+
std::collections::HashMap::new();
|
|
166
|
+
let mut params_str: std::collections::HashMap<String, String> =
|
|
167
|
+
std::collections::HashMap::new();
|
|
168
|
+
for (k, v) in synth_params.iter() {
|
|
169
|
+
match v {
|
|
170
|
+
Value::Number(n) => {
|
|
171
|
+
params_num.insert(k.clone(), *n);
|
|
172
|
+
}
|
|
173
|
+
Value::String(s) => {
|
|
174
|
+
params_str.insert(k.clone(), s.clone());
|
|
175
|
+
}
|
|
176
|
+
Value::Identifier(s) => {
|
|
177
|
+
params_str.insert(k.clone(), s.clone());
|
|
178
|
+
}
|
|
179
|
+
_ => {}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
let _ = runner.render_note_with_params_in_place(
|
|
183
|
+
wasm_bytes,
|
|
184
|
+
&mut fbuf,
|
|
185
|
+
None,
|
|
186
|
+
final_freq,
|
|
187
|
+
amp_note,
|
|
188
|
+
duration_ms as i32,
|
|
189
|
+
44100,
|
|
190
|
+
2,
|
|
191
|
+
¶ms_num,
|
|
192
|
+
Some(¶ms_str),
|
|
193
|
+
);
|
|
194
|
+
for (i, sample) in
|
|
195
|
+
fbuf.iter().enumerate().take(total_samples * channels)
|
|
196
|
+
{
|
|
197
|
+
let s = (sample.clamp(-1.0, 1.0) * (i16::MAX as f32)) as i16;
|
|
198
|
+
let idx = start_index + i;
|
|
199
|
+
audio_engine.buffer[idx] =
|
|
200
|
+
audio_engine.buffer[idx].saturating_add(s);
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
let logger = Logger::new();
|
|
204
|
+
logger.log_message(LogLevel::Warning, &format!("Plugin bytes not found for key '{}' (alias '{}').", key, alias));
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
let logger = Logger::new();
|
|
208
|
+
logger.log_message(LogLevel::Warning, &format!("Invalid plugin URI in alias '{}': {}", alias, uri));
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
let logger = Logger::new();
|
|
212
|
+
logger.log_message(LogLevel::Warning, &format!("Plugin alias '{}' not found in variable table.", alias));
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
audio_engine.insert_note(
|
|
216
|
+
waveform_str.clone(),
|
|
217
|
+
final_freq,
|
|
218
|
+
amp_note,
|
|
219
|
+
start_time * 1000.0,
|
|
220
|
+
duration_ms,
|
|
221
|
+
synth_params,
|
|
222
|
+
note_params,
|
|
223
|
+
automation,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
147
226
|
|
|
148
227
|
*max_end_time = (*max_end_time).max(end_time);
|
|
149
228
|
|
|
@@ -155,7 +234,8 @@ pub fn interprete_call_arrow_statement(
|
|
|
155
234
|
|
|
156
235
|
return (*max_end_time, end_time);
|
|
157
236
|
} else {
|
|
158
|
-
|
|
237
|
+
let logger = Logger::new();
|
|
238
|
+
logger.log_message(LogLevel::Error, &format!("Unknown method '{}' on synth '{}'.", method, target));
|
|
159
239
|
}
|
|
160
240
|
}
|
|
161
241
|
|
|
@@ -181,7 +261,7 @@ fn extract_f32(map: &HashMap<String, Value>, key: &str, base_bpm: f32) -> Option
|
|
|
181
261
|
}
|
|
182
262
|
|
|
183
263
|
fn note_to_freq(note: &str) -> f32 {
|
|
184
|
-
let notes =
|
|
264
|
+
let notes = [
|
|
185
265
|
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
|
|
186
266
|
];
|
|
187
267
|
|