@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.1
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 -4
- package/.github/workflows/ci.yml +103 -0
- package/Cargo.toml +80 -48
- package/README.md +135 -154
- package/docs/CHANGELOG.md +386 -1
- package/docs/CONTRIBUTING.md +101 -0
- package/docs/ROADMAP.md +10 -7
- package/docs/TODO.md +21 -9
- package/examples/automation.deva +42 -0
- package/examples/bank.deva +7 -0
- package/examples/duration.deva +9 -0
- package/examples/events.deva +12 -0
- package/examples/function.deva +15 -0
- package/examples/index.deva +57 -12
- package/examples/loop.deva +5 -12
- package/examples/pattern.deva +8 -0
- package/examples/plugin.deva +16 -0
- package/examples/variables.deva +1 -1
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/bin/index.js +51 -7
- 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 +42 -1
- package/out-tsc/pkg/devalang_core.d.ts +13 -0
- package/out-tsc/pkg/devalang_core.js +50 -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 +83 -0
- 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 +28 -7
- package/project-version.json +4 -4
- 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 +103 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/check/mod.rs +208 -0
- 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} +32 -23
- package/rust/cli/init/mod.rs +1 -0
- package/rust/cli/install/addon.rs +118 -0
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/install/commands.rs +35 -0
- package/rust/cli/install/mod.rs +4 -0
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/login/commands.rs +124 -0
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +12 -205
- package/rust/cli/parser.rs +314 -0
- 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/commands.rs +22 -0
- 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} +69 -57
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/update/commands.rs +6 -0
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +103 -0
- package/rust/config/mod.rs +3 -16
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +101 -0
- package/rust/core/audio/engine/helpers.rs +170 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +366 -0
- package/rust/core/audio/engine/synth.rs +325 -0
- package/rust/core/audio/evaluator.rs +310 -31
- package/rust/core/audio/interpreter/arrow_call.rs +311 -129
- package/rust/core/audio/interpreter/automate.rs +18 -0
- package/rust/core/audio/interpreter/call.rs +294 -64
- package/rust/core/audio/interpreter/condition.rs +71 -69
- package/rust/core/audio/interpreter/driver.rs +542 -216
- package/rust/core/audio/interpreter/function.rs +26 -0
- package/rust/core/audio/interpreter/let_.rs +38 -19
- package/rust/core/audio/interpreter/load.rs +19 -18
- package/rust/core/audio/interpreter/loop_.rs +114 -67
- package/rust/core/audio/interpreter/mod.rs +14 -12
- package/rust/core/audio/interpreter/sleep.rs +28 -36
- package/rust/core/audio/interpreter/spawn.rs +252 -66
- package/rust/core/audio/interpreter/tempo.rs +40 -16
- package/rust/core/audio/interpreter/trigger.rs +239 -69
- package/rust/core/audio/loader/mod.rs +1 -1
- package/rust/core/audio/loader/trigger.rs +97 -52
- package/rust/core/audio/mod.rs +7 -6
- package/rust/core/audio/player.rs +70 -54
- package/rust/core/audio/renderer.rs +54 -54
- package/rust/core/audio/special/easing.rs +189 -0
- package/rust/core/audio/special/env.rs +45 -0
- package/rust/core/audio/special/math.rs +134 -0
- package/rust/core/audio/special/mod.rs +9 -0
- package/rust/core/audio/special/modulator.rs +143 -0
- package/rust/core/builder/mod.rs +86 -80
- package/rust/core/debugger/lexer.rs +27 -27
- package/rust/core/debugger/mod.rs +30 -21
- package/rust/core/debugger/module.rs +55 -0
- package/rust/core/debugger/preprocessor.rs +27 -27
- package/rust/core/debugger/store.rs +40 -25
- package/rust/core/error/mod.rs +269 -60
- package/rust/core/lexer/driver.rs +61 -0
- package/rust/core/lexer/handler/arrow.rs +82 -31
- package/rust/core/lexer/handler/at.rs +21 -21
- package/rust/core/lexer/handler/brace.rs +41 -41
- package/rust/core/lexer/handler/colon.rs +21 -21
- package/rust/core/lexer/handler/comment.rs +30 -30
- package/rust/core/lexer/handler/dot.rs +21 -21
- package/rust/core/lexer/handler/driver.rs +337 -226
- package/rust/core/lexer/handler/identifier.rs +47 -41
- package/rust/core/lexer/handler/indent.rs +66 -52
- package/rust/core/lexer/handler/mod.rs +15 -14
- package/rust/core/lexer/handler/newline.rs +23 -23
- package/rust/core/lexer/handler/number.rs +31 -31
- package/rust/core/lexer/handler/operator.rs +46 -44
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/handler/slash.rs +21 -0
- package/rust/core/lexer/handler/string.rs +63 -63
- package/rust/core/lexer/mod.rs +3 -51
- package/rust/core/lexer/token.rs +17 -12
- package/rust/core/mod.rs +10 -10
- package/rust/core/parser/driver.rs +584 -331
- package/rust/core/parser/handler/arrow_call.rs +253 -126
- package/rust/core/parser/handler/at.rs +279 -162
- package/rust/core/parser/handler/bank.rs +104 -41
- package/rust/core/parser/handler/condition.rs +83 -74
- package/rust/core/parser/handler/dot.rs +148 -112
- package/rust/core/parser/handler/identifier/automate.rs +254 -0
- package/rust/core/parser/handler/identifier/call.rs +91 -41
- package/rust/core/parser/handler/identifier/emit.rs +70 -0
- package/rust/core/parser/handler/identifier/function.rs +113 -0
- package/rust/core/parser/handler/identifier/group.rs +89 -75
- package/rust/core/parser/handler/identifier/let_.rs +173 -133
- package/rust/core/parser/handler/identifier/mod.rs +55 -51
- package/rust/core/parser/handler/identifier/on.rs +107 -0
- package/rust/core/parser/handler/identifier/print.rs +49 -0
- package/rust/core/parser/handler/identifier/sleep.rs +43 -33
- package/rust/core/parser/handler/identifier/spawn.rs +91 -41
- package/rust/core/parser/handler/identifier/synth.rs +135 -65
- package/rust/core/parser/handler/loop_.rs +194 -72
- package/rust/core/parser/handler/mod.rs +9 -8
- package/rust/core/parser/handler/pattern.rs +74 -0
- package/rust/core/parser/handler/tempo.rs +57 -47
- package/rust/core/parser/mod.rs +3 -4
- package/rust/core/parser/statement.rs +11 -96
- package/rust/core/plugin/loader.rs +137 -0
- package/rust/core/plugin/mod.rs +2 -0
- package/rust/core/plugin/runner.rs +347 -0
- package/rust/core/preprocessor/loader.rs +637 -193
- package/rust/core/preprocessor/mod.rs +4 -4
- package/rust/core/preprocessor/module.rs +60 -50
- package/rust/core/preprocessor/processor.rs +114 -76
- package/rust/core/preprocessor/resolver/bank.rs +49 -47
- package/rust/core/preprocessor/resolver/call.rs +124 -123
- package/rust/core/preprocessor/resolver/condition.rs +95 -92
- package/rust/core/preprocessor/resolver/driver.rs +324 -227
- package/rust/core/preprocessor/resolver/function.rs +69 -0
- package/rust/core/preprocessor/resolver/group.rs +94 -61
- package/rust/core/preprocessor/resolver/let_.rs +32 -31
- package/rust/core/preprocessor/resolver/loop_.rs +318 -91
- package/rust/core/preprocessor/resolver/mod.rs +16 -14
- package/rust/core/preprocessor/resolver/pattern.rs +83 -0
- package/rust/core/preprocessor/resolver/spawn.rs +99 -58
- package/rust/core/preprocessor/resolver/synth.rs +54 -50
- package/rust/core/preprocessor/resolver/tempo.rs +48 -49
- package/rust/core/preprocessor/resolver/trigger.rs +116 -112
- package/rust/core/preprocessor/resolver/value.rs +176 -78
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +40 -0
- package/rust/core/store/global.rs +61 -39
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/mod.rs +5 -4
- package/rust/core/store/variable.rs +51 -28
- package/rust/core/utils/mod.rs +1 -2
- package/rust/core/utils/path.rs +37 -31
- package/rust/lib.rs +308 -117
- package/rust/main.rs +364 -65
- 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/src/error.rs +186 -0
- 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} +9 -6
- package/rust/utils/{logger.rs → src/logger.rs} +200 -123
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +20 -21
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +46 -33
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/rust/web/mod.rs +3 -0
- package/rust/web/sso.rs +5 -0
- package/templates/minimal/README.md +143 -127
- package/templates/welcome/README.md +143 -127
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/integration.rs +21 -0
- package/tests/rust/cli_check_build.rs +21 -0
- package/tests/rust/cli_help.rs +12 -0
- package/tests/rust/cli_template_list.rs +10 -0
- package/tests/rust/cli_version.rs +11 -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 +12 -10
- package/typescript/bin/index.ts +19 -5
- 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 +8 -1
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/pkg/devalang_core.ts +49 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/typescript/scripts/postinstall.ts +85 -0
- package/typescript/scripts/version/bump.ts +0 -1
- package/typescript/scripts/version/index.ts +0 -1
- package/docs/COMMANDS.md +0 -85
- package/docs/CONFIG.md +0 -30
- package/docs/SYNTAX.md +0 -210
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/postbuild.js +0 -11
- package/rust/cli/build.rs +0 -137
- package/rust/cli/check.rs +0 -117
- package/rust/cli/play.rs +0 -193
- package/rust/config/loader.rs +0 -13
- package/rust/core/audio/engine.rs +0 -203
- package/rust/core/shared/duration.rs +0 -8
- package/rust/core/shared/mod.rs +0 -2
- package/rust/core/shared/value.rs +0 -18
- package/rust/core/utils/validation.rs +0 -37
- package/rust/utils/file.rs +0 -35
- package/rust/utils/signature.rs +0 -17
- package/rust/utils/version.rs +0 -15
- package/typescript/scripts/postbuild.ts +0 -8
package/rust/cli/play.rs
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
config::Config,
|
|
3
|
-
core::{
|
|
4
|
-
builder::Builder,
|
|
5
|
-
debugger::{ lexer::write_lexer_log_file, preprocessor::write_preprocessor_log_file },
|
|
6
|
-
preprocessor::loader::ModuleLoader,
|
|
7
|
-
store::global::GlobalStore,
|
|
8
|
-
utils::path::{ find_entry_file, normalize_path },
|
|
9
|
-
},
|
|
10
|
-
utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
use std::{ path::Path, sync::mpsc::channel, thread, time::Duration };
|
|
14
|
-
use std::fs;
|
|
15
|
-
use std::collections::HashMap;
|
|
16
|
-
|
|
17
|
-
#[cfg(feature = "cli")]
|
|
18
|
-
pub fn handle_play_command(
|
|
19
|
-
config: Option<Config>,
|
|
20
|
-
entry: Option<String>,
|
|
21
|
-
output: Option<String>,
|
|
22
|
-
watch: bool,
|
|
23
|
-
repeat: bool
|
|
24
|
-
) {
|
|
25
|
-
use crate::core::audio::player::AudioPlayer;
|
|
26
|
-
|
|
27
|
-
let logger = Logger::new();
|
|
28
|
-
|
|
29
|
-
let entry_path = entry
|
|
30
|
-
.or_else(|| config.as_ref().and_then(|c| c.defaults.entry.clone()))
|
|
31
|
-
.unwrap_or_else(|| "".to_string());
|
|
32
|
-
|
|
33
|
-
let output_path = output
|
|
34
|
-
.or_else(|| config.as_ref().and_then(|c| c.defaults.output.clone()))
|
|
35
|
-
.unwrap_or_else(|| "".to_string());
|
|
36
|
-
|
|
37
|
-
let fetched_repeat = if repeat {
|
|
38
|
-
true
|
|
39
|
-
} else {
|
|
40
|
-
config
|
|
41
|
-
.as_ref()
|
|
42
|
-
.and_then(|c| c.defaults.repeat)
|
|
43
|
-
.unwrap_or(false)
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
if entry_path.is_empty() || output_path.is_empty() {
|
|
47
|
-
logger.log_message(LogLevel::Error, "Entry or output path not specified.");
|
|
48
|
-
std::process::exit(1);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
let entry_file = find_entry_file(&entry_path).unwrap_or_else(|| {
|
|
52
|
-
logger.log_message(LogLevel::Error, "index.deva not found");
|
|
53
|
-
std::process::exit(1);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
let audio_file = format!("{}/audio/index.wav", normalize_path(&output_path));
|
|
57
|
-
let mut audio_player = AudioPlayer::new();
|
|
58
|
-
|
|
59
|
-
if watch && fetched_repeat {
|
|
60
|
-
logger.log_message(
|
|
61
|
-
LogLevel::Error,
|
|
62
|
-
"Watch and repeat cannot be used together. Use repeat instead."
|
|
63
|
-
);
|
|
64
|
-
std::process::exit(1);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if watch {
|
|
68
|
-
let (tx, rx) = channel::<()>();
|
|
69
|
-
|
|
70
|
-
// Thread 1 : Watcher sending changes
|
|
71
|
-
let entry_clone = entry_path.clone();
|
|
72
|
-
thread::spawn(move || {
|
|
73
|
-
let _ = watch_directory(entry_clone, move || {
|
|
74
|
-
let _ = tx.send(()); // signal a change
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Main thread: build + play in a loop
|
|
79
|
-
begin_play(&config, &entry_file, &output_path);
|
|
80
|
-
audio_player.play_file_once(&audio_file);
|
|
81
|
-
|
|
82
|
-
logger.log_message(LogLevel::Watcher, "Watching for changes... Press Ctrl+C to exit.");
|
|
83
|
-
|
|
84
|
-
while let Ok(_) = rx.recv() {
|
|
85
|
-
logger.log_message(LogLevel::Watcher, "Change detected, rebuilding...");
|
|
86
|
-
|
|
87
|
-
begin_play(&config, &entry_file, &output_path);
|
|
88
|
-
|
|
89
|
-
logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
|
|
90
|
-
|
|
91
|
-
audio_player.play_file_once(&audio_file);
|
|
92
|
-
}
|
|
93
|
-
} else if fetched_repeat {
|
|
94
|
-
// Initial build to start from a clean slate
|
|
95
|
-
begin_play(&config, &entry_file, &output_path);
|
|
96
|
-
|
|
97
|
-
logger.log_message(LogLevel::Info, "🎵 Playback started (repeat mode)...");
|
|
98
|
-
|
|
99
|
-
let mut last_snapshot = snapshot_files(&entry_path);
|
|
100
|
-
let mut audio_player = AudioPlayer::new();
|
|
101
|
-
audio_player.play_file_once(&audio_file);
|
|
102
|
-
|
|
103
|
-
loop {
|
|
104
|
-
let current_snapshot = snapshot_files(&entry_path);
|
|
105
|
-
let has_changed = files_changed(&last_snapshot, ¤t_snapshot);
|
|
106
|
-
|
|
107
|
-
if has_changed {
|
|
108
|
-
logger.log_message(LogLevel::Info, "Change detected, rebuilding in background...");
|
|
109
|
-
let entry_file = entry_file.clone();
|
|
110
|
-
let output_path = output_path.clone();
|
|
111
|
-
let config_clone = config.clone();
|
|
112
|
-
|
|
113
|
-
// Rebuild in a separate thread
|
|
114
|
-
std::thread::spawn(move || {
|
|
115
|
-
begin_play(&config_clone, &entry_file, &output_path);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
last_snapshot = current_snapshot;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Wait for the audio to finish without blocking the current playback
|
|
122
|
-
audio_player.wait_until_end();
|
|
123
|
-
|
|
124
|
-
// Then replay the audio (rebuilt or not)
|
|
125
|
-
audio_player.play_file_once(&audio_file);
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
// Single execution
|
|
129
|
-
begin_play(&config, &entry_file, &output_path);
|
|
130
|
-
|
|
131
|
-
logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
|
|
132
|
-
|
|
133
|
-
audio_player.play_file_once(&audio_file);
|
|
134
|
-
audio_player.wait_until_end();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
|
|
139
|
-
let spinner = with_spinner("Building...", || {
|
|
140
|
-
thread::sleep(Duration::from_millis(800));
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
let normalized_entry = normalize_path(entry_file);
|
|
144
|
-
let normalized_output_dir = normalize_path(&output);
|
|
145
|
-
|
|
146
|
-
let duration = std::time::Instant::now();
|
|
147
|
-
let mut global_store = GlobalStore::new();
|
|
148
|
-
let loader = ModuleLoader::new(&normalized_entry, &normalized_output_dir);
|
|
149
|
-
let (modules_tokens, modules_statements) = loader.load_all_modules(&mut global_store);
|
|
150
|
-
|
|
151
|
-
// SECTION Write logs
|
|
152
|
-
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
153
|
-
write_preprocessor_log_file(
|
|
154
|
-
&normalized_output_dir,
|
|
155
|
-
"resolved_statements.log",
|
|
156
|
-
modules_statements.clone()
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
// SECTION Building AST and Audio
|
|
160
|
-
let builder = Builder::new();
|
|
161
|
-
builder.build_ast(&modules_statements, &output);
|
|
162
|
-
builder.build_audio(&modules_statements, &output, &mut global_store);
|
|
163
|
-
|
|
164
|
-
// SECTION Logging
|
|
165
|
-
let logger = Logger::new();
|
|
166
|
-
let success_message = format!(
|
|
167
|
-
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
168
|
-
duration.elapsed(),
|
|
169
|
-
normalized_output_dir
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
logger.log_message(LogLevel::Success, &success_message);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
fn snapshot_files<P: AsRef<Path>>(dir: P) -> HashMap<String, u64> {
|
|
176
|
-
let mut map = HashMap::new();
|
|
177
|
-
if let Ok(entries) = fs::read_dir(dir) {
|
|
178
|
-
for entry in entries.flatten() {
|
|
179
|
-
if let Ok(meta) = entry.metadata() {
|
|
180
|
-
if let Ok(mtime) = meta.modified() {
|
|
181
|
-
if let Ok(duration) = mtime.duration_since(std::time::UNIX_EPOCH) {
|
|
182
|
-
map.insert(entry.path().display().to_string(), duration.as_secs());
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
map
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
fn files_changed(old: &HashMap<String, u64>, new: &HashMap<String, u64>) -> bool {
|
|
192
|
-
old != new
|
|
193
|
-
}
|
package/rust/config/loader.rs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
use std::{ fs, path::Path };
|
|
2
|
-
use crate::config::Config;
|
|
3
|
-
|
|
4
|
-
pub fn load_config(path: Option<&Path>) -> Option<Config> {
|
|
5
|
-
let config_path = path.unwrap_or_else(|| Path::new(".devalang"));
|
|
6
|
-
|
|
7
|
-
if config_path.exists() {
|
|
8
|
-
let content = fs::read_to_string(config_path).ok()?;
|
|
9
|
-
toml::from_str(&content).ok()
|
|
10
|
-
} else {
|
|
11
|
-
None
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
use std::{ collections::HashMap, fs::File, io::BufReader };
|
|
2
|
-
use hound::{ SampleFormat, WavSpec, WavWriter };
|
|
3
|
-
use rodio::{ Decoder, Source };
|
|
4
|
-
|
|
5
|
-
use crate::core::{
|
|
6
|
-
store::variable::VariableTable,
|
|
7
|
-
utils::path::{ normalize_path, resolve_relative_path },
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const SAMPLE_RATE: u32 = 44100;
|
|
11
|
-
const CHANNELS: u16 = 2;
|
|
12
|
-
|
|
13
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
14
|
-
pub struct AudioEngine {
|
|
15
|
-
pub volume: f32,
|
|
16
|
-
pub variables: VariableTable,
|
|
17
|
-
pub buffer: Vec<i16>,
|
|
18
|
-
pub module_name: String,
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
impl AudioEngine {
|
|
22
|
-
pub fn new(module_name: String) -> Self {
|
|
23
|
-
AudioEngine {
|
|
24
|
-
volume: 1.0,
|
|
25
|
-
buffer: vec![],
|
|
26
|
-
variables: VariableTable::new(),
|
|
27
|
-
module_name,
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
pub fn mix(&mut self, other: &AudioEngine) {
|
|
32
|
-
let max_len = self.buffer.len().max(other.buffer.len());
|
|
33
|
-
self.buffer.resize(max_len, 0);
|
|
34
|
-
|
|
35
|
-
for (i, &sample) in other.buffer.iter().enumerate() {
|
|
36
|
-
self.buffer[i] = self.buffer[i].saturating_add(sample);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
pub fn merge_with(&mut self, other: AudioEngine) {
|
|
41
|
-
if other.buffer.iter().all(|&s| s == 0) {
|
|
42
|
-
eprintln!("⚠️ Skipping merge: other buffer is silent");
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if self.buffer.iter().all(|&s| s == 0) {
|
|
47
|
-
self.buffer = other.buffer;
|
|
48
|
-
self.variables.variables.extend(other.variables.variables);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
self.mix(&other);
|
|
53
|
-
self.variables.variables.extend(other.variables.variables);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
pub fn set_duration(&mut self, duration_secs: f32) {
|
|
57
|
-
let total_samples = (duration_secs * (SAMPLE_RATE as f32) * (CHANNELS as f32)) as usize;
|
|
58
|
-
|
|
59
|
-
if self.buffer.len() < total_samples {
|
|
60
|
-
self.buffer.resize(total_samples, 0);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
pub fn set_variables(&mut self, variables: VariableTable) {
|
|
65
|
-
self.variables = variables;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
pub fn generate_wav_file(&mut self, output_dir: &String) -> Result<(), String> {
|
|
69
|
-
if self.buffer.len() % (CHANNELS as usize) != 0 {
|
|
70
|
-
self.buffer.push(0);
|
|
71
|
-
println!("Completed buffer to respect stereo format.");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let spec = WavSpec {
|
|
75
|
-
channels: CHANNELS,
|
|
76
|
-
sample_rate: SAMPLE_RATE,
|
|
77
|
-
bits_per_sample: 16,
|
|
78
|
-
sample_format: SampleFormat::Int,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
let mut writer = WavWriter::create(output_dir, spec).map_err(|e|
|
|
82
|
-
format!("Error creating WAV file: {}", e)
|
|
83
|
-
)?;
|
|
84
|
-
|
|
85
|
-
for sample in &self.buffer {
|
|
86
|
-
writer.write_sample(*sample).map_err(|e| format!("Error writing sample: {:?}", e))?;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
writer.finalize().map_err(|e| format!("Error finalizing WAV: {:?}", e))?;
|
|
90
|
-
|
|
91
|
-
Ok(())
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
pub fn insert_note(
|
|
95
|
-
&mut self,
|
|
96
|
-
waveform: String,
|
|
97
|
-
freq: f32,
|
|
98
|
-
amp: f32,
|
|
99
|
-
start_time_ms: f32,
|
|
100
|
-
duration_ms: f32
|
|
101
|
-
) {
|
|
102
|
-
let sample_rate = SAMPLE_RATE as f32;
|
|
103
|
-
let channels = CHANNELS as usize;
|
|
104
|
-
|
|
105
|
-
let total_samples = ((duration_ms / 1000.0) * sample_rate) as usize;
|
|
106
|
-
let start_sample = ((start_time_ms / 1000.0) * sample_rate) as usize;
|
|
107
|
-
let amplitude = (i16::MAX as f32) * amp.clamp(0.0, 1.0);
|
|
108
|
-
|
|
109
|
-
let mut samples = Vec::with_capacity(total_samples);
|
|
110
|
-
let fade_len = (sample_rate * 0.01) as usize; // 10 ms fade
|
|
111
|
-
|
|
112
|
-
for i in 0..total_samples {
|
|
113
|
-
let t = ((start_sample + i) as f32) / sample_rate;
|
|
114
|
-
let phase = 2.0 * std::f32::consts::PI * freq * t;
|
|
115
|
-
|
|
116
|
-
let mut value = match waveform.as_str() {
|
|
117
|
-
"sine" => phase.sin(),
|
|
118
|
-
"square" => if phase.sin() >= 0.0 { 1.0 } else { -1.0 }
|
|
119
|
-
"saw" => 2.0 * (freq * t - (freq * t + 0.5).floor()),
|
|
120
|
-
"triangle" => (2.0 * (2.0 * (freq * t).fract() - 1.0)).abs() * 2.0 - 1.0,
|
|
121
|
-
_ => 0.0,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Fade in/out
|
|
125
|
-
if i < fade_len {
|
|
126
|
-
value *= (i as f32) / (fade_len as f32);
|
|
127
|
-
} else if i >= total_samples - fade_len {
|
|
128
|
-
value *= ((total_samples - i) as f32) / (fade_len as f32);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
samples.push((value * amplitude) as i16);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Convert to stereo
|
|
135
|
-
let stereo_samples: Vec<i16> = samples
|
|
136
|
-
.iter()
|
|
137
|
-
.flat_map(|s| vec![*s, *s])
|
|
138
|
-
.collect();
|
|
139
|
-
|
|
140
|
-
let offset = start_sample * channels;
|
|
141
|
-
let required_len = offset + stereo_samples.len();
|
|
142
|
-
|
|
143
|
-
if self.buffer.len() < required_len {
|
|
144
|
-
self.buffer.resize(required_len, 0);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
for (i, sample) in stereo_samples.iter().enumerate() {
|
|
148
|
-
if *sample != 0 {
|
|
149
|
-
}
|
|
150
|
-
self.buffer[offset + i] = self.buffer[offset + i].saturating_add(*sample);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
pub fn insert_sample(
|
|
155
|
-
&mut self,
|
|
156
|
-
filepath: &str,
|
|
157
|
-
time_secs: f32,
|
|
158
|
-
dur_sec: f32,
|
|
159
|
-
effects: Option<HashMap<String, f32>>
|
|
160
|
-
) {
|
|
161
|
-
let resolved = resolve_relative_path(&self.module_name.clone(), filepath);
|
|
162
|
-
|
|
163
|
-
let file = BufReader::new(File::open(resolved).expect("Failed to open audio file"));
|
|
164
|
-
let decoder = Decoder::new(file).expect("Failed to decode audio file");
|
|
165
|
-
|
|
166
|
-
// Mono or stereo reading possible here, we will duplicate in L/R
|
|
167
|
-
let max_mono_samples = (dur_sec * (SAMPLE_RATE as f32)) as usize;
|
|
168
|
-
let samples: Vec<i16> = decoder.convert_samples().take(max_mono_samples).collect();
|
|
169
|
-
|
|
170
|
-
if samples.is_empty() {
|
|
171
|
-
eprintln!("No samples found in the audio file: {}", filepath);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// TODO Apply effects here if needed
|
|
176
|
-
let offset = (time_secs * (SAMPLE_RATE as f32) * (CHANNELS as f32)) as usize;
|
|
177
|
-
let required_len = offset + samples.len() * (CHANNELS as usize);
|
|
178
|
-
let padded_required_len = if required_len % 2 == 1 {
|
|
179
|
-
required_len + 1
|
|
180
|
-
} else {
|
|
181
|
-
required_len
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
self.buffer.resize(padded_required_len, 0);
|
|
185
|
-
self.pad_samples(&samples, time_secs);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
fn pad_samples(&mut self, samples: &[i16], time_secs: f32) {
|
|
189
|
-
let offset = (time_secs * (SAMPLE_RATE as f32) * (CHANNELS as f32)) as usize;
|
|
190
|
-
|
|
191
|
-
for (i, &sample) in samples.iter().enumerate() {
|
|
192
|
-
let adjusted_sample = ((sample as f32) * self.volume).round() as i16;
|
|
193
|
-
|
|
194
|
-
let left_pos = offset + i * 2;
|
|
195
|
-
let right_pos = left_pos + 1;
|
|
196
|
-
|
|
197
|
-
if right_pos < self.buffer.len() {
|
|
198
|
-
self.buffer[left_pos] = self.buffer[left_pos].saturating_add(adjusted_sample); // gauche
|
|
199
|
-
self.buffer[right_pos] = self.buffer[right_pos].saturating_add(adjusted_sample); // droite
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
package/rust/core/shared/mod.rs
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
use std::collections::HashMap;
|
|
2
|
-
use serde::{ Deserialize, Serialize };
|
|
3
|
-
|
|
4
|
-
use crate::core::parser::statement::Statement;
|
|
5
|
-
|
|
6
|
-
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
7
|
-
pub enum Value {
|
|
8
|
-
Boolean(bool),
|
|
9
|
-
Number(f32),
|
|
10
|
-
Identifier(String),
|
|
11
|
-
String(String),
|
|
12
|
-
Array(Vec<Value>),
|
|
13
|
-
Map(HashMap<String, Value>),
|
|
14
|
-
Block(Vec<Statement>),
|
|
15
|
-
Sample(String),
|
|
16
|
-
Unknown,
|
|
17
|
-
Null,
|
|
18
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
use crate::core::{ preprocessor::module::Module, shared::value::Value, store::global::GlobalStore };
|
|
2
|
-
|
|
3
|
-
// NOTE: Deprecated functions, kept for reference
|
|
4
|
-
|
|
5
|
-
// pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
|
|
6
|
-
// let built_ins = ["kick", "snare", "hat", "clap"];
|
|
7
|
-
|
|
8
|
-
// if built_ins.contains(&entity) {
|
|
9
|
-
// return true;
|
|
10
|
-
// }
|
|
11
|
-
|
|
12
|
-
// if let Some(val) = module.variable_table.get(entity) {
|
|
13
|
-
// match val {
|
|
14
|
-
// Value::Sample(_) => true,
|
|
15
|
-
// _ => false,
|
|
16
|
-
// }
|
|
17
|
-
// } else {
|
|
18
|
-
// false
|
|
19
|
-
// }
|
|
20
|
-
// }
|
|
21
|
-
|
|
22
|
-
// pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
|
|
23
|
-
// let built_ins = ["auto"];
|
|
24
|
-
|
|
25
|
-
// if built_ins.contains(&ident) {
|
|
26
|
-
// return true;
|
|
27
|
-
// }
|
|
28
|
-
|
|
29
|
-
// if let Some(val) = module.variable_table.get(ident) {
|
|
30
|
-
// match val {
|
|
31
|
-
// Value::Identifier(_) => true,
|
|
32
|
-
// _ => false,
|
|
33
|
-
// }
|
|
34
|
-
// } else {
|
|
35
|
-
// false
|
|
36
|
-
// }
|
|
37
|
-
// }
|
package/rust/utils/file.rs
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
use std::{ fs::{ self }, path::Path };
|
|
2
|
-
use include_dir::{ Dir, DirEntry };
|
|
3
|
-
|
|
4
|
-
pub fn copy_dir_recursive(dir: &Dir, target_root: &Path, base_path: &Path) {
|
|
5
|
-
for entry in dir.entries() {
|
|
6
|
-
match entry {
|
|
7
|
-
DirEntry::Dir(subdir) => {
|
|
8
|
-
copy_dir_recursive(subdir, target_root, base_path);
|
|
9
|
-
}
|
|
10
|
-
DirEntry::File(file) => {
|
|
11
|
-
let rel_path = file.path().strip_prefix(base_path).unwrap();
|
|
12
|
-
let dest_path = target_root.join(rel_path);
|
|
13
|
-
|
|
14
|
-
if let Some(parent) = dest_path.parent() {
|
|
15
|
-
fs::create_dir_all(parent).unwrap();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
fs::write(&dest_path, file.contents()).expect("Error writing file");
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
pub fn format_file_size(bytes: u64) -> String {
|
|
25
|
-
const KB: u64 = 1024;
|
|
26
|
-
const MB: u64 = 1024 * 1024;
|
|
27
|
-
|
|
28
|
-
if bytes >= MB {
|
|
29
|
-
format!("{:.2} Mb", (bytes as f64) / (MB as f64))
|
|
30
|
-
} else if bytes >= KB {
|
|
31
|
-
format!("{:.2} Kb", (bytes as f64) / (KB as f64))
|
|
32
|
-
} else {
|
|
33
|
-
format!("{} bytes", bytes)
|
|
34
|
-
}
|
|
35
|
-
}
|
package/rust/utils/signature.rs
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
pub fn get_signature(version: &str) -> String {
|
|
2
|
-
let signature =
|
|
3
|
-
format!(r#"
|
|
4
|
-
/|_/|
|
|
5
|
-
/ ^ ^(_o 🦊 Devalang
|
|
6
|
-
/ __.'
|
|
7
|
-
/ \ A programming language for music and sound.
|
|
8
|
-
/ _ \_ Part of Devaloop project.
|
|
9
|
-
(_) (_) '._
|
|
10
|
-
'.__ '. .-''-'. https://devaloop.com
|
|
11
|
-
( '. ('.____.''
|
|
12
|
-
_) )'_, ) v{}
|
|
13
|
-
(__/ (__/
|
|
14
|
-
"#, version);
|
|
15
|
-
|
|
16
|
-
signature
|
|
17
|
-
}
|
package/rust/utils/version.rs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
use crate::utils::signature::get_signature;
|
|
2
|
-
|
|
3
|
-
pub fn get_version() -> &'static str {
|
|
4
|
-
let version: &str = env!("CARGO_PKG_VERSION");
|
|
5
|
-
version
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
pub fn get_version_with_signature() -> &'static str {
|
|
9
|
-
let version = get_version();
|
|
10
|
-
let signature = get_signature(version);
|
|
11
|
-
|
|
12
|
-
println!("{}", signature);
|
|
13
|
-
|
|
14
|
-
"(c) 2025 Devaloop. All rights reserved."
|
|
15
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
const source = path.join(__dirname, "..", "..", "target", "release", "devalang.exe");
|
|
5
|
-
const destination = path.join(__dirname, "..", "bin", "devalang.exe");
|
|
6
|
-
|
|
7
|
-
fs.copyFileSync(source, destination);
|
|
8
|
-
fs.chmodSync(destination, 0o755);
|