@devaloop/devalang 0.0.1-alpha.15 → 0.0.1-alpha.16
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/.devalang +2 -0
- package/.github/workflows/ci.yml +92 -0
- package/Cargo.toml +60 -58
- package/README.md +1 -1
- package/docs/CHANGELOG.md +34 -1
- package/docs/CONTRIBUTING.md +101 -1
- package/docs/ROADMAP.md +1 -1
- package/docs/TODO.md +1 -1
- package/examples/automation.deva +1 -3
- package/examples/bank.deva +4 -4
- package/examples/events.deva +12 -0
- package/examples/function.deva +4 -4
- package/examples/index.deva +3 -5
- package/examples/loop.deva +5 -11
- package/examples/pattern.deva +8 -0
- package/examples/plugin.deva +12 -11
- package/examples/variables.deva +1 -1
- package/out-tsc/bin/index.js +51 -7
- package/out-tsc/index.js +3 -1
- package/out-tsc/scripts/postbuild.js +9 -10
- package/out-tsc/scripts/postinstall.js +49 -0
- package/package.json +12 -4
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +462 -455
- package/rust/cli/build.rs +252 -199
- package/rust/cli/check.rs +221 -180
- package/rust/cli/driver.rs +297 -292
- package/rust/cli/generator.rs +1 -0
- package/rust/cli/init.rs +87 -79
- package/rust/cli/install.rs +35 -32
- package/rust/cli/login.rs +127 -134
- package/rust/cli/mod.rs +13 -11
- package/rust/cli/play.rs +1123 -218
- package/rust/cli/telemetry.rs +19 -0
- package/rust/cli/template.rs +69 -57
- package/rust/cli/update.rs +6 -4
- package/rust/common/api.rs +5 -5
- package/rust/common/mod.rs +3 -3
- package/rust/config/driver.rs +118 -94
- package/rust/config/loader.rs +165 -156
- package/rust/config/mod.rs +4 -2
- package/rust/config/settings.rs +91 -0
- package/rust/config/stats.rs +257 -0
- package/rust/core/audio/engine.rs +696 -659
- package/rust/core/audio/evaluator.rs +263 -132
- package/rust/core/audio/interpreter/arrow_call.rs +198 -187
- package/rust/core/audio/interpreter/call.rs +98 -95
- package/rust/core/audio/interpreter/condition.rs +70 -71
- package/rust/core/audio/interpreter/driver.rs +487 -231
- package/rust/core/audio/interpreter/function.rs +26 -21
- package/rust/core/audio/interpreter/let_.rs +38 -26
- package/rust/core/audio/interpreter/load.rs +18 -18
- package/rust/core/audio/interpreter/loop_.rs +113 -106
- package/rust/core/audio/interpreter/mod.rs +14 -14
- package/rust/core/audio/interpreter/sleep.rs +27 -28
- package/rust/core/audio/interpreter/spawn.rs +105 -102
- package/rust/core/audio/interpreter/tempo.rs +19 -16
- package/rust/core/audio/interpreter/trigger.rs +239 -210
- package/rust/core/audio/loader/mod.rs +1 -1
- package/rust/core/audio/loader/trigger.rs +100 -94
- package/rust/core/audio/mod.rs +7 -7
- package/rust/core/audio/player.rs +64 -64
- package/rust/core/audio/renderer.rs +56 -53
- package/rust/core/audio/special/easing.rs +189 -120
- package/rust/core/audio/special/env.rs +43 -41
- package/rust/core/audio/special/math.rs +102 -92
- package/rust/core/audio/special/mod.rs +9 -9
- package/rust/core/audio/special/modulator.rs +143 -120
- package/rust/core/builder/mod.rs +80 -85
- package/rust/core/debugger/lexer.rs +27 -27
- package/rust/core/debugger/mod.rs +24 -23
- package/rust/core/debugger/module.rs +55 -47
- package/rust/core/debugger/preprocessor.rs +27 -27
- package/rust/core/debugger/store.rs +40 -39
- package/rust/core/error/mod.rs +80 -69
- package/rust/core/lexer/handler/arrow.rs +82 -82
- 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 -292
- package/rust/core/lexer/handler/identifier.rs +46 -43
- package/rust/core/lexer/handler/indent.rs +66 -66
- package/rust/core/lexer/handler/mod.rs +16 -16
- 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 -46
- package/rust/core/lexer/handler/parenthesis.rs +41 -41
- package/rust/core/lexer/handler/slash.rs +21 -21
- package/rust/core/lexer/handler/string.rs +63 -63
- package/rust/core/lexer/mod.rs +54 -51
- package/rust/core/lexer/token.rs +97 -94
- package/rust/core/mod.rs +11 -11
- package/rust/core/parser/driver.rs +513 -490
- package/rust/core/parser/handler/arrow_call.rs +233 -227
- package/rust/core/parser/handler/at.rs +245 -162
- package/rust/core/parser/handler/bank.rs +94 -69
- package/rust/core/parser/handler/condition.rs +80 -74
- package/rust/core/parser/handler/dot.rs +143 -135
- package/rust/core/parser/handler/identifier/automate.rs +257 -194
- package/rust/core/parser/handler/identifier/call.rs +91 -88
- package/rust/core/parser/handler/identifier/emit.rs +66 -0
- package/rust/core/parser/handler/identifier/function.rs +100 -91
- package/rust/core/parser/handler/identifier/group.rs +85 -75
- package/rust/core/parser/handler/identifier/let_.rs +158 -143
- package/rust/core/parser/handler/identifier/mod.rs +54 -56
- package/rust/core/parser/handler/identifier/on.rs +98 -0
- package/rust/core/parser/handler/identifier/print.rs +52 -29
- package/rust/core/parser/handler/identifier/sleep.rs +36 -33
- package/rust/core/parser/handler/identifier/spawn.rs +91 -88
- package/rust/core/parser/handler/identifier/synth.rs +65 -63
- package/rust/core/parser/handler/loop_.rs +170 -89
- package/rust/core/parser/handler/mod.rs +8 -8
- package/rust/core/parser/handler/tempo.rs +53 -47
- package/rust/core/parser/mod.rs +4 -4
- package/rust/core/parser/statement.rs +142 -113
- package/rust/core/plugin/loader.rs +123 -48
- package/rust/core/plugin/mod.rs +2 -1
- package/rust/core/plugin/runner.rs +296 -0
- package/rust/core/preprocessor/loader.rs +515 -326
- package/rust/core/preprocessor/mod.rs +4 -4
- package/rust/core/preprocessor/module.rs +60 -58
- package/rust/core/preprocessor/processor.rs +99 -101
- package/rust/core/preprocessor/resolver/bank.rs +51 -48
- package/rust/core/preprocessor/resolver/call.rs +100 -101
- package/rust/core/preprocessor/resolver/condition.rs +97 -97
- package/rust/core/preprocessor/resolver/driver.rs +310 -280
- package/rust/core/preprocessor/resolver/function.rs +69 -68
- package/rust/core/preprocessor/resolver/group.rs +96 -91
- package/rust/core/preprocessor/resolver/let_.rs +32 -28
- package/rust/core/preprocessor/resolver/loop_.rs +320 -121
- package/rust/core/preprocessor/resolver/mod.rs +15 -15
- package/rust/core/preprocessor/resolver/spawn.rs +76 -73
- package/rust/core/preprocessor/resolver/synth.rs +56 -50
- package/rust/core/preprocessor/resolver/tempo.rs +50 -49
- package/rust/core/preprocessor/resolver/trigger.rs +113 -115
- package/rust/core/preprocessor/resolver/value.rs +81 -81
- package/rust/core/shared/duration.rs +9 -9
- package/rust/core/shared/mod.rs +3 -3
- package/rust/core/shared/value.rs +35 -32
- package/rust/core/store/function.rs +34 -34
- package/rust/core/store/global.rs +55 -38
- package/rust/core/store/mod.rs +5 -5
- package/rust/core/store/variable.rs +37 -34
- package/rust/core/utils/mod.rs +2 -2
- package/rust/core/utils/path.rs +37 -31
- package/rust/core/utils/validation.rs +35 -36
- package/rust/installer/addon.rs +84 -80
- package/rust/installer/bank.rs +62 -65
- package/rust/installer/mod.rs +5 -5
- package/rust/installer/plugin.rs +54 -55
- package/rust/installer/utils.rs +56 -56
- package/rust/lib.rs +156 -164
- package/rust/main.rs +250 -144
- package/rust/utils/error.rs +200 -51
- package/rust/utils/file.rs +38 -35
- package/rust/utils/first_usage.rs +76 -0
- package/rust/utils/logger.rs +195 -143
- package/rust/utils/mod.rs +9 -7
- package/rust/utils/signature.rs +19 -17
- package/rust/utils/spinner.rs +22 -19
- package/rust/utils/telemetry.rs +292 -0
- package/rust/utils/watcher.rs +34 -33
- package/templates/minimal/README.md +97 -121
- package/templates/welcome/README.md +97 -121
- package/typescript/bin/index.ts +19 -5
- package/typescript/index.ts +3 -1
- package/typescript/scripts/postbuild.ts +10 -6
- package/typescript/scripts/postinstall.ts +56 -0
- package/typescript/scripts/version/bump.ts +0 -1
- package/typescript/scripts/version/index.ts +0 -1
- package/out-tsc/bin/devalang.exe +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
common::api::get_api_url,
|
|
3
|
+
config::{driver::ProjectConfig, settings::get_user_config, stats::ProjectStats},
|
|
4
|
+
};
|
|
5
|
+
use serde::{Deserialize, Serialize};
|
|
6
|
+
use std::time::Duration;
|
|
7
|
+
|
|
8
|
+
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
9
|
+
pub enum TelemetryErrorLevel {
|
|
10
|
+
#[default]
|
|
11
|
+
None,
|
|
12
|
+
Warning,
|
|
13
|
+
Critical,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
17
|
+
pub struct TelemetryProjectInfo {
|
|
18
|
+
config: Option<TelemetryProjectInfoConfig>,
|
|
19
|
+
stats: Option<TelemetryProjectInfoStats>,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
|
23
|
+
pub struct TelemetryProjectInfoStats {
|
|
24
|
+
counts: TelemetryProjectInfoStatsCounts,
|
|
25
|
+
features: TelemetryProjectInfoStatsFeatures,
|
|
26
|
+
audio: TelemetryProjectInfoStatsAudio,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
|
30
|
+
pub struct TelemetryProjectInfoStatsCounts {
|
|
31
|
+
pub nb_files: usize,
|
|
32
|
+
pub nb_modules: usize,
|
|
33
|
+
pub nb_lines: usize,
|
|
34
|
+
pub nb_banks: usize,
|
|
35
|
+
pub nb_plugins: usize,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
|
39
|
+
pub struct TelemetryProjectInfoStatsFeatures {
|
|
40
|
+
pub uses_imports: bool,
|
|
41
|
+
pub uses_functions: bool,
|
|
42
|
+
pub uses_groups: bool,
|
|
43
|
+
pub uses_automations: bool,
|
|
44
|
+
pub uses_loops: bool,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
|
48
|
+
pub struct TelemetryProjectInfoStatsAudio {
|
|
49
|
+
pub avg_bpm: Option<u32>,
|
|
50
|
+
pub has_synths: bool,
|
|
51
|
+
pub has_samples: bool,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
|
55
|
+
pub struct TelemetryProjectInfoConfig {
|
|
56
|
+
pub entry_defined: bool,
|
|
57
|
+
pub output_defined: bool,
|
|
58
|
+
pub watch_defined: bool,
|
|
59
|
+
pub repeat_defined: bool,
|
|
60
|
+
pub debug_defined: bool,
|
|
61
|
+
pub compress_defined: bool,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#[derive(Serialize, Deserialize, Default, Clone)]
|
|
65
|
+
pub struct TelemetryEvent {
|
|
66
|
+
pub uuid: String,
|
|
67
|
+
pub cli_version: String,
|
|
68
|
+
pub os: String,
|
|
69
|
+
pub command: Vec<String>,
|
|
70
|
+
pub project_info: Option<TelemetryProjectInfo>,
|
|
71
|
+
pub error_level: TelemetryErrorLevel,
|
|
72
|
+
pub error_message: Option<String>,
|
|
73
|
+
pub exit_code: Option<i32>,
|
|
74
|
+
pub timestamp: String,
|
|
75
|
+
pub duration: u64,
|
|
76
|
+
pub success: bool,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
impl TelemetryEvent {
|
|
80
|
+
pub fn set_timestamp(&mut self, timestamp: String) {
|
|
81
|
+
self.timestamp = timestamp;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pub fn set_duration(&mut self, duration: u64) {
|
|
85
|
+
self.duration = duration;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn set_success(&mut self, success: bool) {
|
|
89
|
+
self.success = success;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pub fn set_error(
|
|
93
|
+
&mut self,
|
|
94
|
+
level: TelemetryErrorLevel,
|
|
95
|
+
message: Option<String>,
|
|
96
|
+
exit_code: Option<i32>,
|
|
97
|
+
) {
|
|
98
|
+
self.error_level = level;
|
|
99
|
+
self.error_message = message;
|
|
100
|
+
self.exit_code = exit_code;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
pub struct TelemetryEventCreator {
|
|
105
|
+
pub events: Vec<TelemetryEvent>,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
impl TelemetryEventCreator {
|
|
109
|
+
pub fn new() -> Self {
|
|
110
|
+
TelemetryEventCreator { events: Vec::new() }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pub fn create_event(&mut self, event: TelemetryEvent) {
|
|
114
|
+
self.events.push(event.clone());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub fn get_base_event(&self) -> TelemetryEvent {
|
|
118
|
+
let mut stats_enabled = false;
|
|
119
|
+
|
|
120
|
+
let user_config = get_user_config().unwrap_or_default();
|
|
121
|
+
|
|
122
|
+
if user_config.telemetry.stats == true {
|
|
123
|
+
stats_enabled = true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let mut event: TelemetryEvent = TelemetryEvent {
|
|
127
|
+
uuid: user_config.telemetry.uuid.clone(),
|
|
128
|
+
cli_version: env!("CARGO_PKG_VERSION").to_string(),
|
|
129
|
+
os: std::env::consts::OS.to_string(),
|
|
130
|
+
command: std::env::args().collect::<Vec<_>>(),
|
|
131
|
+
project_info: None,
|
|
132
|
+
error_level: TelemetryErrorLevel::None,
|
|
133
|
+
error_message: None,
|
|
134
|
+
exit_code: None,
|
|
135
|
+
timestamp: chrono::Utc::now().to_string(),
|
|
136
|
+
duration: 0,
|
|
137
|
+
success: true,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
let project_settings = ProjectConfig::get();
|
|
141
|
+
let project_stats = ProjectStats::get();
|
|
142
|
+
|
|
143
|
+
if project_settings.is_ok() && project_stats.is_ok() {
|
|
144
|
+
let project_settings = project_settings.unwrap();
|
|
145
|
+
let project_stats = project_stats.unwrap();
|
|
146
|
+
|
|
147
|
+
let mut stats = None;
|
|
148
|
+
|
|
149
|
+
if stats_enabled {
|
|
150
|
+
stats = Some(TelemetryProjectInfoStats {
|
|
151
|
+
counts: TelemetryProjectInfoStatsCounts {
|
|
152
|
+
nb_files: project_stats.counts.nb_files,
|
|
153
|
+
nb_modules: project_stats.counts.nb_modules,
|
|
154
|
+
nb_lines: project_stats.counts.nb_lines,
|
|
155
|
+
nb_banks: project_stats.counts.nb_banks,
|
|
156
|
+
nb_plugins: project_stats.counts.nb_plugins,
|
|
157
|
+
},
|
|
158
|
+
features: TelemetryProjectInfoStatsFeatures {
|
|
159
|
+
uses_imports: project_stats.features.uses_imports,
|
|
160
|
+
uses_functions: project_stats.features.uses_functions,
|
|
161
|
+
uses_groups: project_stats.features.uses_groups,
|
|
162
|
+
uses_automations: project_stats.features.uses_automations,
|
|
163
|
+
uses_loops: project_stats.features.uses_loops,
|
|
164
|
+
},
|
|
165
|
+
audio: TelemetryProjectInfoStatsAudio {
|
|
166
|
+
avg_bpm: project_stats.audio.avg_bpm,
|
|
167
|
+
has_synths: project_stats.audio.has_synths,
|
|
168
|
+
has_samples: project_stats.audio.has_samples,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
event.project_info = Some(TelemetryProjectInfo {
|
|
174
|
+
config: Some(TelemetryProjectInfoConfig {
|
|
175
|
+
entry_defined: project_settings.defaults.entry.is_some(),
|
|
176
|
+
output_defined: project_settings.defaults.output.is_some(),
|
|
177
|
+
watch_defined: project_settings.defaults.watch.is_some(),
|
|
178
|
+
repeat_defined: project_settings.defaults.repeat.is_some(),
|
|
179
|
+
debug_defined: project_settings.defaults.debug.is_some(),
|
|
180
|
+
compress_defined: project_settings.defaults.compress.is_some(),
|
|
181
|
+
}),
|
|
182
|
+
stats: stats,
|
|
183
|
+
});
|
|
184
|
+
} else {
|
|
185
|
+
event.project_info = None;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
event
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
pub fn refresh_event_project_info(event: &mut TelemetryEvent) {
|
|
193
|
+
let user_config = get_user_config().unwrap_or_default();
|
|
194
|
+
let stats_enabled = user_config.telemetry.stats;
|
|
195
|
+
|
|
196
|
+
let project_settings = ProjectConfig::get();
|
|
197
|
+
let project_stats = ProjectStats::get();
|
|
198
|
+
|
|
199
|
+
if project_settings.is_ok() && project_stats.is_ok() {
|
|
200
|
+
let project_settings = project_settings.unwrap();
|
|
201
|
+
let project_stats = project_stats.unwrap();
|
|
202
|
+
|
|
203
|
+
let mut stats = None;
|
|
204
|
+
if stats_enabled {
|
|
205
|
+
stats = Some(TelemetryProjectInfoStats {
|
|
206
|
+
counts: TelemetryProjectInfoStatsCounts {
|
|
207
|
+
nb_files: project_stats.counts.nb_files,
|
|
208
|
+
nb_modules: project_stats.counts.nb_modules,
|
|
209
|
+
nb_lines: project_stats.counts.nb_lines,
|
|
210
|
+
nb_banks: project_stats.counts.nb_banks,
|
|
211
|
+
nb_plugins: project_stats.counts.nb_plugins,
|
|
212
|
+
},
|
|
213
|
+
features: TelemetryProjectInfoStatsFeatures {
|
|
214
|
+
uses_imports: project_stats.features.uses_imports,
|
|
215
|
+
uses_functions: project_stats.features.uses_functions,
|
|
216
|
+
uses_groups: project_stats.features.uses_groups,
|
|
217
|
+
uses_automations: project_stats.features.uses_automations,
|
|
218
|
+
uses_loops: project_stats.features.uses_loops,
|
|
219
|
+
},
|
|
220
|
+
audio: TelemetryProjectInfoStatsAudio {
|
|
221
|
+
avg_bpm: project_stats.audio.avg_bpm,
|
|
222
|
+
has_synths: project_stats.audio.has_synths,
|
|
223
|
+
has_samples: project_stats.audio.has_samples,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
event.project_info = Some(TelemetryProjectInfo {
|
|
229
|
+
config: Some(TelemetryProjectInfoConfig {
|
|
230
|
+
entry_defined: project_settings.defaults.entry.is_some(),
|
|
231
|
+
output_defined: project_settings.defaults.output.is_some(),
|
|
232
|
+
watch_defined: project_settings.defaults.watch.is_some(),
|
|
233
|
+
repeat_defined: project_settings.defaults.repeat.is_some(),
|
|
234
|
+
debug_defined: project_settings.defaults.debug.is_some(),
|
|
235
|
+
compress_defined: project_settings.defaults.compress.is_some(),
|
|
236
|
+
}),
|
|
237
|
+
stats,
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
event.project_info = None;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#[derive(Debug)]
|
|
245
|
+
pub enum TelemetrySendError {
|
|
246
|
+
Http(String),
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
pub async fn send_telemetry_event(event: &TelemetryEvent) -> Result<(), TelemetrySendError> {
|
|
250
|
+
if let Some(cfg) = get_user_config() {
|
|
251
|
+
if cfg.telemetry.enabled == false {
|
|
252
|
+
return Ok(());
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let telemetry_url = format!("{}/v1/telemetry/send", get_api_url());
|
|
257
|
+
let client = reqwest::Client::builder()
|
|
258
|
+
.timeout(Duration::from_secs(5))
|
|
259
|
+
.build()
|
|
260
|
+
.map_err(|e| TelemetrySendError::Http(format!("client build error: {}", e)))?;
|
|
261
|
+
|
|
262
|
+
let mut last_err: Option<String> = None;
|
|
263
|
+
for (i, delay_ms) in [0u64, 250, 500, 1000].iter().enumerate() {
|
|
264
|
+
if *delay_ms > 0 {
|
|
265
|
+
tokio::time::sleep(Duration::from_millis(*delay_ms)).await;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let res = client
|
|
269
|
+
.post(telemetry_url.clone())
|
|
270
|
+
.json(event)
|
|
271
|
+
.send()
|
|
272
|
+
.await
|
|
273
|
+
.and_then(|r| r.error_for_status());
|
|
274
|
+
|
|
275
|
+
match res {
|
|
276
|
+
Ok(_) => {
|
|
277
|
+
return Ok(());
|
|
278
|
+
}
|
|
279
|
+
Err(err) => {
|
|
280
|
+
last_err = Some(err.to_string());
|
|
281
|
+
|
|
282
|
+
if i == 3 {
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
Err(TelemetrySendError::Http(
|
|
290
|
+
last_err.unwrap_or_else(|| "unknown error".to_string()),
|
|
291
|
+
))
|
|
292
|
+
}
|
package/rust/utils/watcher.rs
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
use notify::{
|
|
2
|
-
use std::sync::mpsc::channel;
|
|
3
|
-
|
|
4
|
-
use std::time::{
|
|
5
|
-
|
|
6
|
-
pub fn watch_directory<F>(entry: String, callback: F) -> notify::Result<()>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
watcher
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
|
|
2
|
+
use std::sync::mpsc::channel;
|
|
3
|
+
|
|
4
|
+
use std::time::{Duration, Instant};
|
|
5
|
+
|
|
6
|
+
pub fn watch_directory<F>(entry: String, callback: F) -> notify::Result<()>
|
|
7
|
+
where
|
|
8
|
+
F: Fn() + Send + 'static,
|
|
9
|
+
{
|
|
10
|
+
let (tx, rx) = channel();
|
|
11
|
+
|
|
12
|
+
let mut watcher: RecommendedWatcher = Watcher::new(tx, Config::default())?;
|
|
13
|
+
watcher.watch(&entry.as_ref(), RecursiveMode::Recursive)?;
|
|
14
|
+
|
|
15
|
+
let mut last_trigger = Instant::now();
|
|
16
|
+
|
|
17
|
+
loop {
|
|
18
|
+
match rx.recv() {
|
|
19
|
+
Ok(_) => {
|
|
20
|
+
let now = Instant::now();
|
|
21
|
+
if now.duration_since(last_trigger) > Duration::from_millis(200) {
|
|
22
|
+
callback();
|
|
23
|
+
last_trigger = now;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
Err(e) => {
|
|
27
|
+
eprintln!("Channel error: {:?}", e);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Ok(())
|
|
34
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="https://
|
|
2
|
+
<img src="https://devalang.com/images/devalang-logo-min.png" alt="Devalang Logo" width="100" />
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
5
|

|
|
@@ -7,184 +7,156 @@
|
|
|
7
7
|

|
|
8
8
|
|
|
9
9
|

|
|
10
|
-

|
|
11
11
|

|
|
12
12
|

|
|
13
13
|
|
|
14
14
|

|
|
15
15
|

|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
[](https://marketplace.visualstudio.com/items?itemName=devaloop.devalang-vscode)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
# 🦊 Devalang (CORE) — Compose music with code
|
|
20
20
|
|
|
21
21
|
Devalang is a tiny domain-specific language (DSL) for music makers, sound designers, and audio hackers.
|
|
22
22
|
Compose loops, control samples, render and play audio — all in clean, readable text.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Whether you're building a track, shaping textures, or performing live, Devalang helps you think in rhythms. It’s designed to be simple, expressive, and fast — because your ideas shouldn’t wait.
|
|
25
25
|
|
|
26
26
|
From studio sketches to live sets, Devalang gives you rhythmic control — with the elegance of code.
|
|
27
27
|
|
|
28
|
-
> 🚧
|
|
28
|
+
> 🚧 Alpha Notice 🚧
|
|
29
29
|
>
|
|
30
|
-
>
|
|
30
|
+
> Includes synthesis, playback, and rendering features, but is still in early development.
|
|
31
|
+
>
|
|
32
|
+
> Currently, Devalang CLI is only available for **Windows**.
|
|
31
33
|
> Linux and macOS binaries will be added in future releases via cross-platform builds.
|
|
32
34
|
|
|
33
|
-
---
|
|
34
|
-
|
|
35
35
|
## 📚 Quick Access
|
|
36
36
|
|
|
37
|
-
- [
|
|
37
|
+
- [▶️ Playground](https://playground.devalang.com)
|
|
38
|
+
- [📖 Documentation](https://docs.devalang.com)
|
|
39
|
+
- [🧩 VSCode Extension](https://marketplace.visualstudio.com/items?itemName=devaloop.devalang-vscode)
|
|
40
|
+
- [🎨 Prettier Plugin](https://www.npmjs.com/package/@devaloop/prettier-plugin-devalang)
|
|
41
|
+
- [📜 Changelog](./docs/CHANGELOG.md)
|
|
38
42
|
- [💡 Examples](./examples/)
|
|
39
43
|
- [🌐 Project Website](https://devalang.com)
|
|
44
|
+
- [📦 Devalang CLI on npm](https://www.npmjs.com/package/@devaloop/devalang)
|
|
40
45
|
|
|
41
|
-
##
|
|
46
|
+
## ⏱️ Try it now !
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
- 🧩 **Module system** for importing and exporting variables between files
|
|
45
|
-
- 📜 **Structured AST** generation for debugging and future compilation
|
|
46
|
-
- 🔢 **Basic data types**: strings, numbers, booleans, maps, arrays
|
|
47
|
-
- 👁️ **Watch mode** for `build`, `check` and `play` commands
|
|
48
|
-
- 📂 **Project templates** for quick setup
|
|
48
|
+
### Try Devalang in your browser
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
> Have a look at the [Playground](https://playground.devalang.com) to try Devalang directly in your browser
|
|
51
51
|
|
|
52
|
-
###
|
|
53
|
-
|
|
54
|
-
> - ⚠️ Requires [Node.js 18+](https://nodejs.org/en/download)
|
|
55
|
-
|
|
56
|
-
Install the package globally (NPM)
|
|
52
|
+
### Try Devalang CLI
|
|
57
53
|
|
|
58
54
|
```bash
|
|
55
|
+
# Install Devalang CLI globally
|
|
59
56
|
npm install -g @devaloop/devalang
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Usage without install (NPX)
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
npx @devaloop/devalang <command>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### For contributors
|
|
69
57
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
> git clone https://github.com/devaloop-labs/devalang.git
|
|
75
|
-
> cd devalang
|
|
76
|
-
> npm install
|
|
77
|
-
> cargo install --path .
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Development usage (you can customize arguments in package.json)
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
# For syntax checking test
|
|
84
|
-
npm run rust:dev:check
|
|
85
|
-
# For building test
|
|
86
|
-
npm run rust:dev:build
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## ❔ Usage
|
|
90
|
-
|
|
91
|
-
NOTE: Commands are available via `devalang` or `npx @devaloop/devalang`.
|
|
92
|
-
|
|
93
|
-
NOTE: Arguments can be passed to commands using `--<argument>` syntax. You can also use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
|
|
94
|
-
|
|
95
|
-
NOTE: Some commands require a mandatory `--entry` argument to specify the input folder, and a `--output` argument to specify the output folder. If not specified, they default to `./src` and `./output` respectively.
|
|
96
|
-
|
|
97
|
-
For more examples, see [docs/COMMANDS.md](./docs/COMMANDS.md)
|
|
98
|
-
|
|
99
|
-
### Initialize a new project
|
|
100
|
-
|
|
101
|
-
In the current directory
|
|
102
|
-
|
|
103
|
-
```bash
|
|
104
|
-
devalang init
|
|
58
|
+
# Create a new Devalang project
|
|
59
|
+
devalang init --name my-project --template minimal
|
|
60
|
+
cd my-project
|
|
105
61
|
```
|
|
106
62
|
|
|
107
|
-
|
|
63
|
+
Create a new Devalang file `src/index.deva` in the project directory:
|
|
108
64
|
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
65
|
+
```deva
|
|
66
|
+
# src/index.deva
|
|
67
|
+
|
|
68
|
+
group main:
|
|
69
|
+
let lead = synth sine {
|
|
70
|
+
attack: 0,
|
|
71
|
+
decay: 100,
|
|
72
|
+
sustain: 100,
|
|
73
|
+
release: 100
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Global automation for this synth (applies to subsequent notes)
|
|
77
|
+
automate lead:
|
|
78
|
+
param volume {
|
|
79
|
+
0% = 0.0
|
|
80
|
+
100% = 1.0
|
|
81
|
+
}
|
|
82
|
+
param pan {
|
|
83
|
+
0% = -1.0
|
|
84
|
+
100% = 1.0
|
|
85
|
+
}
|
|
86
|
+
param pitch {
|
|
87
|
+
0% = -12.0
|
|
88
|
+
100% = 12.0
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
lead -> note(C4, {
|
|
92
|
+
duration: 400,
|
|
93
|
+
velocity: 0.8,
|
|
94
|
+
automate: { pan: { 0%: -1.0, 100%: 0.0 } }
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
lead -> note(E4, { duration: 400 })
|
|
98
|
+
lead -> note(G4, { duration: 600, glide: true, target_freq: 659.25 })
|
|
99
|
+
lead -> note(B3, { duration: 400, slide: true, target_amp: 0.3 })
|
|
100
|
+
|
|
101
|
+
for i in [1, 2, 3]:
|
|
102
|
+
lead -> note(C5, { duration: 200 })
|
|
103
|
+
|
|
104
|
+
# Play the lead
|
|
105
|
+
|
|
106
|
+
call main
|
|
117
107
|
```
|
|
118
108
|
|
|
119
|
-
###
|
|
109
|
+
### And the best part ? You can play it directly from the command line:
|
|
120
110
|
|
|
121
111
|
```bash
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
### Playing audio files (once by file change)
|
|
112
|
+
# Play the Devalang file
|
|
113
|
+
devalang play
|
|
126
114
|
|
|
127
|
-
|
|
115
|
+
# Play the Devalang file with watch mode
|
|
128
116
|
devalang play --watch
|
|
129
|
-
```
|
|
130
117
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
```bash
|
|
118
|
+
# LIVE mode (repeat the playback + watch mode)
|
|
134
119
|
devalang play --repeat
|
|
135
120
|
```
|
|
136
121
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
You can use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
|
|
140
|
-
|
|
141
|
-
To do this, create a `.devalang` file in the root of your project directory.
|
|
142
|
-
|
|
143
|
-
See [docs/CONFIG.md](./docs/CONFIG.md) for more information.
|
|
144
|
-
|
|
145
|
-
## 📄 Syntax example
|
|
122
|
+
### 🎉 You can now hear your Devalang code in action
|
|
146
123
|
|
|
147
|
-
For more examples,
|
|
124
|
+
> For more examples, check out the [examples directory](./examples/)
|
|
148
125
|
|
|
149
|
-
|
|
150
|
-
# index.deva
|
|
151
|
-
|
|
152
|
-
@import { globalBpm, globalBank, kickDuration } from "global.deva"
|
|
153
|
-
|
|
154
|
-
@load "./examples/samples/kick-808.wav" as customKick
|
|
155
|
-
|
|
156
|
-
bpm globalBpm
|
|
157
|
-
# Will declare the tempo at the globalBpm variable beats per minute
|
|
126
|
+
## ❓ Why Devalang ?
|
|
158
127
|
|
|
159
|
-
|
|
160
|
-
|
|
128
|
+
- 🎹 Prototype audio ideas without opening a DAW, even VSCode
|
|
129
|
+
- 💻 Integrate sound into code-based workflows
|
|
130
|
+
- 🎛️ Control audio parameters through readable syntax
|
|
131
|
+
- 🧪 Build musical logic with variables and conditions
|
|
132
|
+
- 🔄 Create complex patterns with ease
|
|
161
133
|
|
|
162
|
-
|
|
163
|
-
.customKick kickDuration {reverb=50, drive=25}
|
|
164
|
-
# Will play 5 times a kick for the duration of the kickDuration variable with reverb and drive effects
|
|
165
|
-
```
|
|
134
|
+
## 🚀 Features
|
|
166
135
|
|
|
167
|
-
|
|
168
|
-
|
|
136
|
+
- 🎵 **Audio Engine**: Integrated audio playback and rendering
|
|
137
|
+
- 🧩 **Module system** for importing and exporting variables between files
|
|
138
|
+
- 📦 **Addon manager** for managing external banks, plugins and more
|
|
139
|
+
- 📜 **Structured AST** generation for debugging and future compilation
|
|
140
|
+
- 🔢 **Basic data types**: strings, numbers, booleans, maps, arrays
|
|
141
|
+
- 👁️ **Watch mode** for `build`, `check` and `play` commands
|
|
142
|
+
- 📂 **Project templates** for quick setup
|
|
143
|
+
- 🎛️ **Custom samples**: easily load and trigger your own audio files
|
|
144
|
+
- 🔄 **Looping and grouping**: create complex patterns with ease
|
|
169
145
|
|
|
170
|
-
|
|
171
|
-
let globalBank = 808
|
|
172
|
-
let kickDuration = 500
|
|
146
|
+
## 📄 Documentation
|
|
173
147
|
|
|
174
|
-
|
|
175
|
-
```
|
|
148
|
+
### Please refer to the [online documentation](https://docs.devalang.com) for detailed information on syntax, features, and usage examples
|
|
176
149
|
|
|
177
150
|
## 🧯 Known issues
|
|
178
151
|
|
|
179
|
-
- No
|
|
180
|
-
- No support yet for `@group`, `@pattern`, `@function` statements
|
|
152
|
+
- No smart modules yet, all groups, variables, and samples must be explicitly imported where used
|
|
181
153
|
- No support yet for cross-platform builds (Linux, macOS)
|
|
182
154
|
|
|
183
155
|
## 🧪 Roadmap Highlights
|
|
184
156
|
|
|
185
157
|
For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
|
|
186
158
|
|
|
187
|
-
- ⏳ Other statements (e.g `
|
|
159
|
+
- ⏳ Other statements (e.g `function`, `pattern`, ...)
|
|
188
160
|
- ⏳ Cross-platform support (Linux, macOS)
|
|
189
161
|
- ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
|
|
190
162
|
|
|
@@ -197,6 +169,10 @@ MIT — see [LICENSE](./LICENSE)
|
|
|
197
169
|
Contributions, bug reports and suggestions are welcome !
|
|
198
170
|
Feel free to open an issue or submit a pull request.
|
|
199
171
|
|
|
172
|
+
For more info, see [docs/CONTRIBUTING.md](./docs/CONTRIBUTING.md).
|
|
173
|
+
|
|
200
174
|
## 📢 Contact
|
|
201
175
|
|
|
176
|
+
Feel free to reach out for any inquiries or feedback.
|
|
177
|
+
|
|
202
178
|
📧 [contact@devaloop.com](mailto:contact@devaloop.com)
|