@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
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
use devalang_types::{Duration, Value};
|
|
2
|
+
|
|
1
3
|
use crate::core::{
|
|
2
4
|
audio::{engine::AudioEngine, interpreter::driver::execute_audio_block},
|
|
3
5
|
parser::statement::{Statement, StatementKind},
|
|
4
|
-
shared::value::Value,
|
|
5
6
|
store::{function::FunctionTable, global::GlobalStore, variable::VariableTable},
|
|
6
7
|
};
|
|
7
8
|
|
|
@@ -16,71 +17,152 @@ pub fn interprete_spawn_statement(
|
|
|
16
17
|
max_end_time: f32,
|
|
17
18
|
cursor_time: f32,
|
|
18
19
|
) -> (f32, f32) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
if let StatementKind::Spawn { name, args } = &stmt.kind {
|
|
21
|
+
let mut local_engine = AudioEngine::new(audio_engine.module_name.clone());
|
|
22
|
+
|
|
23
|
+
// Function case
|
|
24
|
+
if let Some(func) = functions.functions.get(name) {
|
|
25
|
+
if func.parameters.len() != args.len() {
|
|
26
|
+
return (max_end_time, cursor_time);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let mut local_vars = VariableTable::with_parent(variable_table.clone());
|
|
30
|
+
for (param, arg) in func.parameters.iter().zip(args) {
|
|
31
|
+
local_vars.set(param.clone(), arg.clone());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let (spawn_max, _) = execute_audio_block(
|
|
35
|
+
&mut local_engine,
|
|
36
|
+
global_store,
|
|
37
|
+
local_vars,
|
|
38
|
+
functions.clone(),
|
|
39
|
+
&func.body,
|
|
40
|
+
base_bpm,
|
|
41
|
+
base_duration,
|
|
42
|
+
0.0,
|
|
43
|
+
0.0,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
audio_engine.merge_with(local_engine);
|
|
47
|
+
return (spawn_max.max(max_end_time), cursor_time);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Group case
|
|
51
|
+
if let Some(group_stmt) = find_group(name, variable_table, global_store) {
|
|
52
|
+
if let Value::Map(map) = &group_stmt.value {
|
|
53
|
+
if let Some(Value::Block(body)) = map.get("body") {
|
|
54
|
+
let (spawn_max, _) = execute_audio_block(
|
|
55
|
+
&mut local_engine,
|
|
56
|
+
global_store,
|
|
57
|
+
variable_table.clone(),
|
|
58
|
+
functions.clone(),
|
|
59
|
+
body,
|
|
60
|
+
base_bpm,
|
|
61
|
+
base_duration,
|
|
62
|
+
0.0,
|
|
63
|
+
0.0,
|
|
31
64
|
);
|
|
32
|
-
|
|
65
|
+
audio_engine.merge_with(local_engine);
|
|
66
|
+
return (spawn_max.max(max_end_time), cursor_time);
|
|
33
67
|
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
34
70
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
// Pattern case: allow spawning a pattern similar to call
|
|
72
|
+
if let Some(pattern_stmt) = find_pattern(name, variable_table, global_store) {
|
|
73
|
+
if let Value::String(pat) = &pattern_stmt.value {
|
|
74
|
+
let mut target_entity = name.clone();
|
|
75
|
+
if let StatementKind::Pattern { name: _n, target } = &pattern_stmt.kind {
|
|
76
|
+
if let Some(t) = target {
|
|
77
|
+
target_entity = t.clone();
|
|
78
|
+
}
|
|
38
79
|
}
|
|
39
80
|
|
|
40
|
-
let (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
0.0,
|
|
49
|
-
0.0,
|
|
50
|
-
);
|
|
81
|
+
let final_variable_table = if let Some(parent) = &variable_table.parent {
|
|
82
|
+
crate::core::store::variable::VariableTable {
|
|
83
|
+
variables: parent.variables.clone(),
|
|
84
|
+
parent: None,
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
variable_table.clone()
|
|
88
|
+
};
|
|
51
89
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
90
|
+
let pattern_str: String = pat.chars().filter(|c| !c.is_whitespace()).collect();
|
|
91
|
+
if pattern_str.is_empty() {
|
|
92
|
+
return (max_end_time, cursor_time);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let step_count = pattern_str.len() as f32;
|
|
96
|
+
let total_bar = 4.0 * base_duration;
|
|
97
|
+
let step_duration = total_bar / step_count;
|
|
98
|
+
|
|
99
|
+
let mut updated_max = max_end_time;
|
|
100
|
+
|
|
101
|
+
for (i, ch) in pattern_str.chars().enumerate() {
|
|
102
|
+
if ch == '-' {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let event_time = cursor_time + (i as f32) * step_duration;
|
|
107
|
+
|
|
108
|
+
let mut trigger_val = Value::String(target_entity.clone());
|
|
109
|
+
if let Some(val) = variable_table.variables.get(&target_entity) {
|
|
110
|
+
match val {
|
|
111
|
+
Value::Identifier(id) => {
|
|
112
|
+
if let Some(parent) = &variable_table.parent {
|
|
113
|
+
if let Some(v) = parent.get(id) {
|
|
114
|
+
trigger_val = v.clone();
|
|
115
|
+
}
|
|
116
|
+
} else if let Some(v) = variable_table.get(id) {
|
|
117
|
+
trigger_val = v.clone();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
Value::Map(map) => {
|
|
121
|
+
if let Some(Value::String(src)) = map.get("entity") {
|
|
122
|
+
trigger_val = Value::String(src.clone());
|
|
123
|
+
} else if let Some(Value::Identifier(src)) = map.get("entity") {
|
|
124
|
+
trigger_val = Value::Identifier(src.clone());
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
Value::Sample(sample_src) => {
|
|
128
|
+
trigger_val = Value::Sample(sample_src.clone());
|
|
129
|
+
}
|
|
130
|
+
_ => {}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
55
133
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
&
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
134
|
+
let (src, sample_length) =
|
|
135
|
+
crate::core::audio::loader::trigger::load_trigger(&trigger_val, &Duration::Number(step_duration), &None, base_duration, final_variable_table.clone());
|
|
136
|
+
|
|
137
|
+
let play_length = step_duration.min(sample_length);
|
|
138
|
+
|
|
139
|
+
let trigger_src = match trigger_val.get("entity") {
|
|
140
|
+
Some(Value::String(s)) => s.clone(),
|
|
141
|
+
Some(Value::Identifier(id)) => id.clone(),
|
|
142
|
+
Some(Value::Statement(stmt)) => {
|
|
143
|
+
if let StatementKind::Trigger { entity, .. } = &stmt.kind {
|
|
144
|
+
entity.clone()
|
|
145
|
+
} else {
|
|
146
|
+
src.clone()
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
_ => src.clone(),
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
audio_engine.insert_sample(&trigger_src, event_time, play_length, None, &final_variable_table);
|
|
153
|
+
|
|
154
|
+
let end_time = event_time + play_length;
|
|
155
|
+
if end_time > updated_max {
|
|
156
|
+
updated_max = end_time;
|
|
73
157
|
}
|
|
74
158
|
}
|
|
75
|
-
}
|
|
76
159
|
|
|
77
|
-
|
|
160
|
+
audio_engine.merge_with(local_engine);
|
|
161
|
+
return (updated_max.max(max_end_time), cursor_time);
|
|
162
|
+
}
|
|
78
163
|
}
|
|
79
164
|
|
|
80
|
-
|
|
81
|
-
"❌ interprete_spawn_statement expected Spawn, got {:?}",
|
|
82
|
-
stmt.kind
|
|
83
|
-
),
|
|
165
|
+
// Function or group not found
|
|
84
166
|
}
|
|
85
167
|
|
|
86
168
|
(max_end_time, cursor_time)
|
|
@@ -103,3 +185,53 @@ fn find_group<'a>(
|
|
|
103
185
|
}
|
|
104
186
|
None
|
|
105
187
|
}
|
|
188
|
+
|
|
189
|
+
fn find_pattern(
|
|
190
|
+
name: &str,
|
|
191
|
+
variable_table: &VariableTable,
|
|
192
|
+
global_store: &GlobalStore,
|
|
193
|
+
) -> Option<Statement> {
|
|
194
|
+
use crate::core::parser::statement::Statement;
|
|
195
|
+
use crate::core::parser::statement::StatementKind;
|
|
196
|
+
|
|
197
|
+
if let Some(Value::Statement(stmt_box)) = variable_table.get(name) {
|
|
198
|
+
if let StatementKind::Pattern { .. } = stmt_box.kind {
|
|
199
|
+
return Some(*stmt_box.clone());
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if let Some(val) = global_store.variables.variables.get(name) {
|
|
204
|
+
match val {
|
|
205
|
+
Value::Statement(stmt_box) => {
|
|
206
|
+
if let StatementKind::Pattern { .. } = stmt_box.kind {
|
|
207
|
+
return Some(*stmt_box.clone());
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
Value::Map(map) => {
|
|
211
|
+
if let Some(Value::String(_pat)) = map.get("pattern") {
|
|
212
|
+
// Rebuild a Pattern statement from stored map if possible
|
|
213
|
+
let stmt = Statement {
|
|
214
|
+
kind: StatementKind::Pattern {
|
|
215
|
+
name: name.to_string(),
|
|
216
|
+
target: map.get("target").and_then(|v| match v {
|
|
217
|
+
Value::String(s) => Some(s.clone()),
|
|
218
|
+
_ => None,
|
|
219
|
+
}),
|
|
220
|
+
},
|
|
221
|
+
value: Value::String(map.get("pattern").and_then(|v| match v {
|
|
222
|
+
Value::String(s) => Some(s.clone()),
|
|
223
|
+
_ => None,
|
|
224
|
+
}).unwrap_or_default()),
|
|
225
|
+
indent: 0,
|
|
226
|
+
line: 0,
|
|
227
|
+
column: 0,
|
|
228
|
+
};
|
|
229
|
+
return Some(stmt);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
_ => {}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
None
|
|
237
|
+
}
|
|
@@ -1,17 +1,38 @@
|
|
|
1
|
-
use crate::core::{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
1
|
+
use crate::core::parser::statement::{Statement, StatementKind};
|
|
2
|
+
use devalang_types::Value;
|
|
3
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
5
4
|
|
|
6
5
|
pub fn interprete_tempo_statement(stmt: &Statement) -> Option<(f32, f32)> {
|
|
7
6
|
if let StatementKind::Tempo = &stmt.kind {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
match &stmt.value {
|
|
8
|
+
Value::Number(bpm) => {
|
|
9
|
+
let bpm = { *bpm };
|
|
10
|
+
let duration = 60.0 / bpm;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
return Some((bpm, duration));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Value::String(bpm_str) => {
|
|
16
|
+
if let Ok(bpm) = bpm_str.parse::<f32>() {
|
|
17
|
+
let duration = 60.0 / bpm;
|
|
18
|
+
return Some((bpm, duration));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Value::Identifier(bpm_ident) => {
|
|
23
|
+
if let Ok(bpm) = bpm_ident.parse::<f32>() {
|
|
24
|
+
let duration = 60.0 / bpm;
|
|
25
|
+
return Some((bpm, duration));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_ => {
|
|
30
|
+
let logger = Logger::new();
|
|
31
|
+
logger.log_message(
|
|
32
|
+
LogLevel::Warning,
|
|
33
|
+
format!("Invalid tempo value: {:?}", stmt.value).as_str(),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
15
36
|
}
|
|
16
37
|
}
|
|
17
38
|
|
|
@@ -3,10 +3,10 @@ use std::collections::HashMap;
|
|
|
3
3
|
use crate::core::{
|
|
4
4
|
audio::{engine::AudioEngine, loader::trigger::load_trigger},
|
|
5
5
|
parser::statement::{Statement, StatementKind},
|
|
6
|
-
shared::{duration::Duration, value::Value},
|
|
7
6
|
store::variable::VariableTable,
|
|
8
7
|
};
|
|
9
|
-
use
|
|
8
|
+
use devalang_types::{Duration, Value};
|
|
9
|
+
use devalang_utils::logger::Logger;
|
|
10
10
|
|
|
11
11
|
pub fn interprete_trigger_statement(
|
|
12
12
|
stmt: &Statement,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
use crate::core::{
|
|
2
|
-
|
|
3
|
-
shared::{duration::Duration, value::Value},
|
|
4
|
-
store::variable::VariableTable,
|
|
5
|
-
};
|
|
1
|
+
use crate::core::{parser::statement::StatementKind, store::variable::VariableTable};
|
|
2
|
+
use devalang_types::{Duration, Value};
|
|
6
3
|
|
|
7
4
|
pub fn load_trigger(
|
|
8
5
|
trigger: &Value,
|
|
@@ -24,9 +21,9 @@ pub fn load_trigger(
|
|
|
24
21
|
|
|
25
22
|
Value::Map(map) => {
|
|
26
23
|
if let Some(Value::String(src)) = map.get("entity") {
|
|
27
|
-
trigger_path = format!("devalang://bank/{}", src
|
|
24
|
+
trigger_path = format!("devalang://bank/{}", src);
|
|
28
25
|
} else if let Some(Value::Identifier(src)) = map.get("entity") {
|
|
29
|
-
trigger_path = format!("devalang://bank/{}", src
|
|
26
|
+
trigger_path = format!("devalang://bank/{}", src);
|
|
30
27
|
} else {
|
|
31
28
|
eprintln!(
|
|
32
29
|
"❌ Trigger map must contain an 'entity' key with a string or identifier value."
|
|
@@ -8,6 +8,12 @@ pub struct AudioPlayer {
|
|
|
8
8
|
last_path: Option<String>,
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
impl Default for AudioPlayer {
|
|
12
|
+
fn default() -> Self {
|
|
13
|
+
Self::new()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
impl AudioPlayer {
|
|
12
18
|
pub fn new() -> Self {
|
|
13
19
|
let (stream, handle) = OutputStream::try_default().unwrap();
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
store::global::GlobalStore,
|
|
6
|
-
},
|
|
7
|
-
utils::logger::{LogLevel, Logger},
|
|
1
|
+
use crate::core::{
|
|
2
|
+
audio::{engine::AudioEngine, interpreter::driver::run_audio_program},
|
|
3
|
+
parser::statement::Statement,
|
|
4
|
+
store::global::GlobalStore,
|
|
8
5
|
};
|
|
6
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
9
7
|
use std::collections::HashMap;
|
|
10
8
|
|
|
11
9
|
pub fn render_audio_with_modules(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
use devalang_types::Value;
|
|
2
|
+
|
|
1
3
|
use crate::core::store::variable::VariableTable;
|
|
2
4
|
use std::sync::OnceLock;
|
|
3
5
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
@@ -36,7 +38,7 @@ pub fn resolve_atom_or_var(atom: &str, vars: &VariableTable, bpm: f32, beat: f32
|
|
|
36
38
|
if let Ok(n) = atom.parse::<f32>() {
|
|
37
39
|
return Some(n);
|
|
38
40
|
}
|
|
39
|
-
if let Some(
|
|
41
|
+
if let Some(Value::Number(n)) = vars.get(atom) {
|
|
40
42
|
return Some(*n);
|
|
41
43
|
}
|
|
42
44
|
None
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
use crate::core::store::variable::VariableTable;
|
|
2
|
+
use devalang_utils::logger::{Logger, LogLevel};
|
|
2
3
|
|
|
3
4
|
// Parse comma-separated arguments at top level (no nested parentheses split)
|
|
4
5
|
fn parse_top_level_args(s: &str) -> Vec<&str> {
|
|
@@ -25,12 +26,12 @@ fn parse_top_level_args(s: &str) -> Vec<&str> {
|
|
|
25
26
|
|
|
26
27
|
fn eval_math_func(func: &str, args: &[f32], fallback_seed: f32) -> Option<f32> {
|
|
27
28
|
match func {
|
|
28
|
-
"sin" => args.
|
|
29
|
-
"cos" => args.
|
|
29
|
+
"sin" => args.first().copied().map(f32::sin),
|
|
30
|
+
"cos" => args.first().copied().map(f32::cos),
|
|
30
31
|
"random" => {
|
|
31
32
|
// deterministic pseudo-random based on provided seed or a fallback session seed
|
|
32
|
-
let seed = args.
|
|
33
|
-
let x = (seed * 12.9898).sin() *
|
|
33
|
+
let seed = args.first().copied().unwrap_or(fallback_seed);
|
|
34
|
+
let x = (seed * 12.9898).sin() * 43_758.547;
|
|
34
35
|
Some((x.fract() * 2.0 - 1.0).clamp(-1.0, 1.0))
|
|
35
36
|
}
|
|
36
37
|
"lerp" => {
|
|
@@ -56,9 +57,21 @@ pub fn find_and_eval_first_math_call<EvalFn>(
|
|
|
56
57
|
where
|
|
57
58
|
EvalFn: Fn(&str, &VariableTable, f32, f32) -> Option<f32>,
|
|
58
59
|
{
|
|
60
|
+
let logger = Logger::new();
|
|
61
|
+
|
|
59
62
|
let start = s.find("$math.")?;
|
|
60
|
-
let open_rel = s[start..].find('(')
|
|
63
|
+
let open_rel = match s[start..].find('(') {
|
|
64
|
+
Some(i) => i,
|
|
65
|
+
None => {
|
|
66
|
+
logger.log_message(LogLevel::Error, &format!("Malformed $math call: missing '(' in '{}'", s));
|
|
67
|
+
return None;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
61
70
|
let open = start + open_rel;
|
|
71
|
+
if open <= start + 6 {
|
|
72
|
+
logger.log_message(LogLevel::Error, &format!("Malformed $math call: missing function name in '{}'", s));
|
|
73
|
+
return None;
|
|
74
|
+
}
|
|
62
75
|
let func = &s[start + 6..open];
|
|
63
76
|
|
|
64
77
|
// Find matching close parenthesis, handling nesting
|
|
@@ -77,7 +90,13 @@ where
|
|
|
77
90
|
_ => {}
|
|
78
91
|
}
|
|
79
92
|
}
|
|
80
|
-
let close = close_abs
|
|
93
|
+
let close = match close_abs {
|
|
94
|
+
Some(c) => c,
|
|
95
|
+
None => {
|
|
96
|
+
logger.log_message(LogLevel::Error, &format!("Malformed $math call: missing closing ')' in '{}'", s));
|
|
97
|
+
return None;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
81
100
|
|
|
82
101
|
let inner = &s[open + 1..close];
|
|
83
102
|
let raw_args = parse_top_level_args(inner);
|
|
@@ -86,6 +105,7 @@ where
|
|
|
86
105
|
if let Some(v) = eval(a, vars, bpm, beat) {
|
|
87
106
|
args.push(v);
|
|
88
107
|
} else {
|
|
108
|
+
logger.log_message(LogLevel::Error, &format!("Failed to evaluate argument '{}' for $math.{}", a, func));
|
|
89
109
|
return None;
|
|
90
110
|
}
|
|
91
111
|
}
|
|
@@ -44,11 +44,11 @@ fn adsr_envelope_value_t(attack: f32, decay: f32, sustain: f32, release: f32, t:
|
|
|
44
44
|
fn eval_mod_func(func: &str, args: &[f32], beat: f32) -> Option<f32> {
|
|
45
45
|
match func {
|
|
46
46
|
"lfo.sine" => {
|
|
47
|
-
let rate = args.
|
|
47
|
+
let rate = args.first().copied().unwrap_or(1.0);
|
|
48
48
|
Some(lfo_sine(rate, beat))
|
|
49
49
|
}
|
|
50
50
|
"lfo.tri" | "lfo.triangle" => {
|
|
51
|
-
let rate = args.
|
|
51
|
+
let rate = args.first().copied().unwrap_or(1.0);
|
|
52
52
|
Some(lfo_triangle(rate, beat))
|
|
53
53
|
}
|
|
54
54
|
// ADSR envelope normalized over t in [0,1]
|
package/rust/core/builder/mod.rs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
use crate::core::audio::renderer::render_audio_with_modules;
|
|
2
2
|
use crate::core::parser::statement::Statement;
|
|
3
3
|
use crate::core::store::global::GlobalStore;
|
|
4
|
-
use
|
|
4
|
+
use devalang_utils::logger::Logger;
|
|
5
5
|
use std::io::Write;
|
|
6
6
|
use std::{collections::HashMap, fs::create_dir_all};
|
|
7
7
|
|
|
8
8
|
pub struct Builder {}
|
|
9
9
|
|
|
10
|
+
impl Default for Builder {
|
|
11
|
+
fn default() -> Self {
|
|
12
|
+
Self::new()
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
impl Builder {
|
|
11
17
|
pub fn new() -> Self {
|
|
12
18
|
Builder {}
|
|
@@ -46,7 +52,7 @@ impl Builder {
|
|
|
46
52
|
let logger = Logger::new();
|
|
47
53
|
|
|
48
54
|
let audio_engines =
|
|
49
|
-
render_audio_with_modules(modules.clone(),
|
|
55
|
+
render_audio_with_modules(modules.clone(), normalized_output_dir, global_store);
|
|
50
56
|
|
|
51
57
|
create_dir_all(format!("{}/audio", normalized_output_dir))
|
|
52
58
|
.expect("Failed to create audio directory");
|
|
@@ -54,7 +60,7 @@ impl Builder {
|
|
|
54
60
|
for (module_name, mut audio_engine) in audio_engines {
|
|
55
61
|
let formatted_module_name = module_name
|
|
56
62
|
.split('/')
|
|
57
|
-
.
|
|
63
|
+
.next_back()
|
|
58
64
|
.unwrap_or(&module_name)
|
|
59
65
|
.replace(".deva", "");
|
|
60
66
|
|
|
@@ -13,7 +13,7 @@ pub fn write_module_variable_log_file(
|
|
|
13
13
|
let mut content = String::new();
|
|
14
14
|
let module_name = module_path
|
|
15
15
|
.split('/')
|
|
16
|
-
.
|
|
16
|
+
.next_back()
|
|
17
17
|
.unwrap_or("index")
|
|
18
18
|
.replace(".deva", "");
|
|
19
19
|
|
|
@@ -24,7 +24,7 @@ pub fn write_module_variable_log_file(
|
|
|
24
24
|
content.push_str(&format!("{:?} = {:?}\n", var_name, var_data));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
content.
|
|
27
|
+
content.push('\n');
|
|
28
28
|
|
|
29
29
|
debugger.write_log_file(&log_directory, "variables.log", &content);
|
|
30
30
|
}
|
|
@@ -38,7 +38,7 @@ pub fn write_module_function_log_file(
|
|
|
38
38
|
let mut content = String::new();
|
|
39
39
|
let module_name = module_path
|
|
40
40
|
.split('/')
|
|
41
|
-
.
|
|
41
|
+
.next_back()
|
|
42
42
|
.unwrap_or("index")
|
|
43
43
|
.replace(".deva", "");
|
|
44
44
|
|
|
@@ -49,7 +49,7 @@ pub fn write_module_function_log_file(
|
|
|
49
49
|
content.push_str(&format!("{:?} = {:?}\n", func_name, func_data));
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
content.
|
|
52
|
+
content.push('\n');
|
|
53
53
|
|
|
54
54
|
debugger.write_log_file(&log_directory, "functions.log", &content);
|
|
55
55
|
}
|
|
@@ -15,7 +15,7 @@ pub fn write_variables_log_file(output_dir: &str, file_name: &str, variables: Va
|
|
|
15
15
|
content.push_str(&format!("{:?} = {:?}\n", var_name, var_data));
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
content.
|
|
18
|
+
content.push('\n');
|
|
19
19
|
|
|
20
20
|
debugger.write_log_file(&log_directory, file_name, &content);
|
|
21
21
|
}
|
|
@@ -34,7 +34,7 @@ pub fn write_function_log_file(output_dir: &str, file_name: &str, functions: Fun
|
|
|
34
34
|
));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
content.
|
|
37
|
+
content.push('\n');
|
|
38
38
|
|
|
39
39
|
debugger.write_log_file(&log_directory, file_name, &content);
|
|
40
40
|
}
|