@devaloop/devalang 0.0.1-beta.2 → 0.0.1-beta.3
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.toml +84 -81
- package/README.md +3 -2
- package/docs/CHANGELOG.md +41 -0
- package/docs/ROADMAP.md +3 -3
- package/examples/chain.deva +19 -0
- package/examples/plugin.deva +10 -10
- package/examples/routing.deva +23 -0
- package/out-tsc/bin/project-version.json +6 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +8 -8
- package/out-tsc/scripts/version/copy-to-binary.d.ts +1 -0
- package/out-tsc/scripts/version/copy-to-binary.js +79 -0
- package/package.json +23 -10
- package/project-version.json +3 -3
- package/rust/bindings/Cargo.toml +9 -0
- package/rust/bindings/src/lib.rs +86 -0
- package/rust/cli/addon/commands.rs +35 -0
- package/rust/cli/addon/download.rs +234 -0
- package/rust/cli/addon/install.rs +33 -0
- package/rust/cli/addon/list.rs +224 -0
- package/rust/cli/addon/metadata.rs +124 -0
- package/rust/cli/addon/mod.rs +8 -0
- package/rust/cli/addon/remove.rs +271 -0
- package/rust/cli/addon/update.rs +305 -0
- package/rust/cli/{install/addon.rs → addon/utils.rs} +109 -118
- package/rust/cli/build/commands.rs +153 -153
- package/rust/cli/build/process.rs +165 -165
- package/rust/cli/check/mod.rs +208 -208
- package/rust/cli/discover/commands.rs +275 -253
- package/rust/cli/discover/config.rs +109 -111
- package/rust/cli/discover/fs.rs +19 -19
- package/rust/cli/discover/install.rs +214 -103
- package/rust/cli/discover/metadata.rs +48 -48
- package/rust/cli/discover/mod.rs +5 -5
- package/rust/cli/me/commands.rs +52 -0
- package/rust/cli/me/mod.rs +1 -0
- package/rust/cli/mod.rs +12 -12
- package/rust/cli/parser.rs +30 -69
- package/rust/cli/play/commands.rs +375 -375
- package/rust/cli/play/process.rs +159 -159
- package/rust/core/audio/engine/driver.rs +19 -2
- package/rust/core/audio/engine/export.rs +169 -169
- package/rust/core/audio/engine/mod.rs +56 -56
- package/rust/core/audio/engine/notes/dsp.rs +88 -85
- package/rust/core/audio/engine/notes/mod.rs +53 -44
- package/rust/core/audio/engine/notes/params.rs +294 -294
- package/rust/core/audio/engine/sample/insert.rs +148 -47
- package/rust/core/audio/engine/sample/mod.rs +40 -40
- package/rust/core/audio/engine/sample/padding.rs +170 -170
- package/rust/core/audio/evaluator/condition.rs +61 -61
- package/rust/core/audio/evaluator/numeric.rs +152 -152
- package/rust/core/audio/evaluator/rhs.rs +16 -16
- package/rust/core/audio/evaluator/string_expr.rs +94 -94
- package/rust/core/audio/interpreter/driver.rs +574 -574
- package/rust/core/audio/interpreter/mod.rs +2 -2
- package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +9 -5
- package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +398 -384
- package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +323 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +1 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +66 -11
- package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -3
- package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -192
- package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -24
- package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -116
- package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -97
- package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -100
- package/rust/core/audio/interpreter/statements/automate.rs +16 -16
- package/rust/core/audio/interpreter/statements/call.rs +31 -1
- package/rust/core/audio/interpreter/statements/condition.rs +72 -72
- package/rust/core/audio/interpreter/statements/function.rs +24 -24
- package/rust/core/audio/interpreter/statements/let_.rs +36 -36
- package/rust/core/audio/interpreter/statements/load.rs +17 -17
- package/rust/core/audio/interpreter/statements/loop_.rs +115 -115
- package/rust/core/audio/interpreter/statements/spawn.rs +51 -2
- package/rust/core/audio/interpreter/statements/trigger.rs +242 -239
- package/rust/core/audio/loader/trigger.rs +98 -98
- package/rust/core/audio/player.rs +70 -70
- package/rust/core/audio/special/mod.rs +9 -9
- package/rust/core/builder/mod.rs +129 -129
- package/rust/core/debugger/lexer.rs +27 -27
- package/rust/core/debugger/logs.rs +52 -52
- package/rust/core/debugger/preprocessor.rs +27 -27
- package/rust/core/debugger/store.rs +38 -38
- package/rust/core/lexer/driver.rs +59 -59
- 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 -337
- package/rust/core/lexer/handler/identifier.rs +47 -47
- package/rust/core/lexer/handler/indent.rs +66 -66
- package/rust/core/lexer/handler/mod.rs +15 -15
- 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 +3 -3
- package/rust/core/mod.rs +9 -9
- package/rust/core/parser/driver/block.rs +111 -111
- package/rust/core/parser/driver/cursor.rs +82 -82
- package/rust/core/parser/driver/driver_impl.rs +21 -1
- package/rust/core/parser/driver/mod.rs +6 -6
- package/rust/core/parser/driver/parse_array.rs +120 -120
- package/rust/core/parser/driver/parse_map.rs +247 -223
- package/rust/core/parser/driver/parser.rs +160 -160
- package/rust/core/parser/handler/arrow_call.rs +65 -14
- package/rust/core/parser/handler/identifier/synth.rs +171 -135
- package/rust/core/parser/handler/mod.rs +9 -9
- package/rust/core/parser/handler/pattern.rs +24 -1
- package/rust/core/plugin/loader.rs +137 -137
- package/rust/core/plugin/mod.rs +2 -2
- package/rust/core/plugin/runner/non_wasm.rs +481 -297
- package/rust/core/plugin/runner/wasm32.rs +1 -0
- package/rust/core/preprocessor/loader/inject.rs +313 -278
- package/rust/core/preprocessor/loader/loader_helpers.rs +110 -110
- package/rust/core/preprocessor/loader/mod.rs +235 -235
- package/rust/core/preprocessor/module.rs +55 -55
- package/rust/core/preprocessor/processor/handlers.rs +107 -107
- package/rust/core/preprocessor/resolver/bank.rs +49 -49
- package/rust/core/preprocessor/resolver/call.rs +124 -124
- package/rust/core/preprocessor/resolver/condition.rs +95 -95
- package/rust/core/preprocessor/resolver/driver.rs +324 -324
- package/rust/core/preprocessor/resolver/function.rs +69 -69
- package/rust/core/preprocessor/resolver/group.rs +122 -122
- package/rust/core/preprocessor/resolver/let_.rs +32 -32
- package/rust/core/preprocessor/resolver/loop_.rs +318 -318
- package/rust/core/preprocessor/resolver/mod.rs +16 -16
- package/rust/core/preprocessor/resolver/pattern.rs +95 -83
- package/rust/core/preprocessor/resolver/spawn.rs +99 -99
- package/rust/core/preprocessor/resolver/synth.rs +54 -54
- package/rust/core/preprocessor/resolver/tempo.rs +48 -48
- package/rust/core/preprocessor/resolver/trigger.rs +116 -116
- package/rust/core/preprocessor/resolver/value.rs +176 -176
- package/rust/core/store/global.rs +57 -57
- package/rust/lib.rs +323 -323
- package/rust/macros/Cargo.toml +14 -0
- package/rust/macros/src/lib.rs +52 -0
- package/rust/main.rs +311 -142
- package/rust/types/Cargo.toml +1 -1
- package/rust/types/src/addons.rs +3 -1
- package/rust/types/src/config.rs +1 -3
- package/rust/utils/Cargo.toml +5 -2
- package/rust/utils/src/file.rs +397 -14
- package/rust/utils/src/path.rs +31 -2
- package/rust/utils/src/version.rs +38 -7
- package/rust/web/auth.rs +5 -0
- package/rust/web/forge.rs +5 -0
- package/rust/web/mod.rs +5 -3
- package/typescript/scripts/version/copy-to-binary.ts +82 -0
- package/rust/cli/bank/api.rs +0 -122
- package/rust/cli/bank/commands.rs +0 -306
- package/rust/cli/bank/mod.rs +0 -29
- package/rust/cli/install/bank.rs +0 -72
- package/rust/cli/install/commands.rs +0 -35
- package/rust/cli/install/mod.rs +0 -4
- package/rust/cli/install/plugin.rs +0 -80
package/Cargo.toml
CHANGED
|
@@ -1,81 +1,84 @@
|
|
|
1
|
-
[package]
|
|
2
|
-
name = "devalang"
|
|
3
|
-
version = "0.0.1-beta.
|
|
4
|
-
authors = ["Devaloop <contact@devaloop.com>"]
|
|
5
|
-
description = "Write music like code. Devalang is a domain-specific language (DSL) for sound designers and music hackers. Compose, automate, and control sound — in plain text."
|
|
6
|
-
license = "MIT"
|
|
7
|
-
repository = "https://github.com/devaloop-labs/devalang"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
#
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
wasmtime
|
|
1
|
+
[package]
|
|
2
|
+
name = "devalang"
|
|
3
|
+
version = "0.0.1-beta.3"
|
|
4
|
+
authors = ["Devaloop <contact@devaloop.com>"]
|
|
5
|
+
description = "Write music like code. Devalang is a domain-specific language (DSL) for sound designers and music hackers. Compose, automate, and control sound — in plain text."
|
|
6
|
+
license = "MIT"
|
|
7
|
+
repository = "https://github.com/devaloop-labs/devalang"
|
|
8
|
+
license-file = "LICENSE"
|
|
9
|
+
keywords = ["music", "dsl", "audio", "cli", "synthesis"]
|
|
10
|
+
categories = ["command-line-utilities", "development-tools", "parser-implementations"]
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
homepage = "https://devalang.com"
|
|
13
|
+
documentation = "https://docs.devalang.com/"
|
|
14
|
+
edition = "2024"
|
|
15
|
+
|
|
16
|
+
[[bin]]
|
|
17
|
+
name = "devalang"
|
|
18
|
+
path = "rust/main.rs"
|
|
19
|
+
|
|
20
|
+
[lib]
|
|
21
|
+
name = "devalang_core"
|
|
22
|
+
path = "rust/lib.rs"
|
|
23
|
+
crate-type = ["cdylib", "rlib"]
|
|
24
|
+
|
|
25
|
+
[profile.release]
|
|
26
|
+
opt-level = "s"
|
|
27
|
+
|
|
28
|
+
[features]
|
|
29
|
+
default = ["cli"]
|
|
30
|
+
cli = ["crossterm", "indicatif", "inquire", "zip", "reqwest", "flate2", "tokio"]
|
|
31
|
+
|
|
32
|
+
[dependencies]
|
|
33
|
+
devalang_types = { path = "rust/types", version = "0.0.4" }
|
|
34
|
+
devalang_bindings = { path = "rust/bindings", version = "0.0.1" }
|
|
35
|
+
devalang_macros = { path = "rust/macros", version = "0.0.1" }
|
|
36
|
+
clap = { version = "4.5", features = ["derive"] }
|
|
37
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
38
|
+
serde_json = "1.0"
|
|
39
|
+
rodio = "0.17"
|
|
40
|
+
hound = "3.4.0"
|
|
41
|
+
toml = "0.8"
|
|
42
|
+
notify = "6.1"
|
|
43
|
+
fs_extra = "1.3"
|
|
44
|
+
include_dir = "0.7"
|
|
45
|
+
wasm-bindgen = "0.2"
|
|
46
|
+
serde-wasm-bindgen = "0.4"
|
|
47
|
+
nom_locate = "4.0.0"
|
|
48
|
+
chrono = "0.4"
|
|
49
|
+
crossterm = { version = "0.27", optional = true }
|
|
50
|
+
indicatif = { version = "0.17", optional = true }
|
|
51
|
+
inquire = { version = "0.7.5", optional = true }
|
|
52
|
+
js-sys = "0.3"
|
|
53
|
+
getrandom = { version = "0.3", features = ["wasm_js"] }
|
|
54
|
+
reqwest = { version = "0.12.22", optional = true, features = ["json"] }
|
|
55
|
+
flate2 = { version = "1.0", optional = true }
|
|
56
|
+
tokio = { version = "1", features = ["full"], optional = true }
|
|
57
|
+
zip = { version = "4.3.0", optional = true }
|
|
58
|
+
rayon = "1.10.0"
|
|
59
|
+
webbrowser = "0.8"
|
|
60
|
+
tiny_http = "0.9.0"
|
|
61
|
+
dirs = "5"
|
|
62
|
+
urlencoding = "2.1"
|
|
63
|
+
uuid = { version = "1.18.0", features = ["v4"] }
|
|
64
|
+
console_error_panic_hook = "0.1.7"
|
|
65
|
+
midly = "0.5.3"
|
|
66
|
+
|
|
67
|
+
[dev-dependencies]
|
|
68
|
+
assert_cmd = "2"
|
|
69
|
+
predicates = "2"
|
|
70
|
+
tempfile = "3"
|
|
71
|
+
|
|
72
|
+
# For wasm32, enable wasm-friendly randomness backends and avoid
|
|
73
|
+
# pulling in native-only CLI dependencies.
|
|
74
|
+
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
|
75
|
+
getrandom = { version = "0.3", features = ["wasm_js"] }
|
|
76
|
+
uuid = { version = "1.18.0", features = ["v4", "js", "rng-getrandom"] }
|
|
77
|
+
# Keep a lightweight linkage to the utils crate for wasm builds without
|
|
78
|
+
# enabling native CLI features.
|
|
79
|
+
devalang_utils = { path = "rust/utils", default-features = false, version = "0.0.3" }
|
|
80
|
+
|
|
81
|
+
# devalang_utils with CLI and wasmtime are only needed for native targets.
|
|
82
|
+
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
|
83
|
+
devalang_utils = { path = "rust/utils", features = ["cli"], version = "0.0.3" }
|
|
84
|
+
wasmtime = "19"
|
package/README.md
CHANGED
|
@@ -32,9 +32,8 @@ From studio sketches to live sets, Devalang gives you rhythmic control — with
|
|
|
32
32
|
>
|
|
33
33
|
> Includes synthesis, playback, and rendering features, but is still in early development, and breaking changes may occur.
|
|
34
34
|
>
|
|
35
|
-
> **NEW**: [
|
|
35
|
+
> **NEW**: [Devalang WORKSHOP is now available](https://workshop.devalang.com).
|
|
36
36
|
>
|
|
37
|
-
> **NEW**: Now available for Windows, Linux, and macOS.
|
|
38
37
|
|
|
39
38
|
## 📚 Quick Access
|
|
40
39
|
|
|
@@ -192,6 +191,8 @@ devalang play --repeat
|
|
|
192
191
|
|
|
193
192
|
## 📰 What's new
|
|
194
193
|
|
|
194
|
+
- **Effects chaining**: Added support for chaining multiple effects on synths and samples.
|
|
195
|
+
- **New addons system**: Revamped the addons system for better management and integration.
|
|
195
196
|
- **MIDI export**: Added the ability to export MIDI files from Devalang scripts.
|
|
196
197
|
- **Synthesizer improvements**: Enhanced the built-in synthesizer with new types and modulation options.
|
|
197
198
|
- **Devaforge**: Introduced a new system for creating and managing addons, including a CLI for addon generation.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,47 @@
|
|
|
4
4
|
|
|
5
5
|
# Changelog
|
|
6
6
|
|
|
7
|
+
## Version 0.0.1-beta.3 (2025-09-20)
|
|
8
|
+
|
|
9
|
+
### ✨ Language Features
|
|
10
|
+
|
|
11
|
+
- Implemented `synth` effects chaining to apply effects to individual synth notes.
|
|
12
|
+
- Example: `mySynth -> note(C4) -> slide({ duration: 2000 }) -> reverb({ room_size: 0.8 })`
|
|
13
|
+
|
|
14
|
+
### 🛠️ CLI & Addons
|
|
15
|
+
|
|
16
|
+
- Introduced a unified addon manager and removed the legacy `install` / `bank` commands:
|
|
17
|
+
|
|
18
|
+
- Use `devalang addon install <publisher>.<name>` to install banks or plugins.
|
|
19
|
+
- Use `devalang addon remove <publisher>.<name>` to remove banks or plugins.
|
|
20
|
+
- Use `devalang addon list` to list installed addons.
|
|
21
|
+
|
|
22
|
+
- Improved the `discover` workflow:
|
|
23
|
+
|
|
24
|
+
- Recursively scans `.deva` for compiled archives (`.tar.gz` / `.tgz`) and proposes them for installation.
|
|
25
|
+
- Pre-classifies addon types by inspecting archive contents so installations can target the correct folder (bank/plugin/preset/template).
|
|
26
|
+
- Robust selection labels and mapping ensure the chosen addon is installed correctly.
|
|
27
|
+
|
|
28
|
+
- Installation and extraction improvements:
|
|
29
|
+
|
|
30
|
+
- Archives are extracted into the appropriate destination based on detected type.
|
|
31
|
+
- Temporary extraction folder is cleaned up only when empty after installation.
|
|
32
|
+
- Added `--no-clear-tmp` flag to `discover` and addon install flows to preserve the temporary folder when desired.
|
|
33
|
+
|
|
34
|
+
- Bugfixes: fixed selection-to-install mapping and improved success/error logging during install flows.
|
|
35
|
+
|
|
36
|
+
### 🧪 Telemetry & Versioning
|
|
37
|
+
|
|
38
|
+
- Telemetry now uses a runtime-first strategy to resolve the CLI version
|
|
39
|
+
|
|
40
|
+
### 📦 Packaging & Tools
|
|
41
|
+
|
|
42
|
+
- Added `typescript/scripts/version/copy-to-binary.ts` to copy `project-version.json` next to a packaged binary during release/packaging steps.
|
|
43
|
+
|
|
44
|
+
### ✅ Bugfixes & Misc
|
|
45
|
+
|
|
46
|
+
- Various fixes around temporary folder cleanup, archive detection, config updates and CLI ergonomics.
|
|
47
|
+
|
|
7
48
|
## Version 0.0.1-beta.2 (2025-09-07)
|
|
8
49
|
|
|
9
50
|
### 🛠️ MIDI & format
|
package/docs/ROADMAP.md
CHANGED
|
@@ -23,16 +23,16 @@ Devalang is a work in progress. Here’s what we’re planning next:
|
|
|
23
23
|
- ✅ **Sample loading**: Add `@load` assignment to load samples (.mp3, .wav) for use as values.
|
|
24
24
|
- ✅ **WASM support**: Compile Devalang to WebAssembly for use in web applications and other environments.
|
|
25
25
|
- ✅ **VSCode extension**: Create a VSCode extension for syntax highlighting and code completion.
|
|
26
|
+
- ✅ **Addon generator**: Implement addon generation for creating reusable plugins, banks and presets.
|
|
27
|
+
- ✅ **Effect chains**: Implement effect chains for applying multiple effects to a single note or group.
|
|
26
28
|
|
|
27
29
|
## In Progress
|
|
28
30
|
|
|
29
|
-
- ⏳ **Addon generator**: Implement addon generation for creating reusable plugins, banks and presets.
|
|
30
31
|
- ⏳ **Testing**: Expand test coverage for all features.
|
|
32
|
+
- ⏳ **Mixing & Routing**: Implement mixing and routing capabilities for advanced audio control.
|
|
31
33
|
|
|
32
34
|
## Planned
|
|
33
35
|
|
|
34
36
|
- ⏳ **MIDI mapping**: Implement MIDI mapping for external control.
|
|
35
37
|
- ⏳ **GUI**: Develop a graphical user interface for easier interaction.
|
|
36
|
-
- ⏳ **Mixing & Routing**: Implement mixing and routing capabilities for advanced audio control.
|
|
37
|
-
- ⏳ **Effect chains**: Implement effect chains for applying multiple effects to a single note or group.
|
|
38
38
|
- ⏳ **Smart modules**: Let Devalang detect and use groups, samples, and variables without needing to import them manually.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
let myChord = synth sine
|
|
2
|
+
|
|
3
|
+
myChord -> note(C4)
|
|
4
|
+
-> arp({ pattern: "up", rate: 1/8 })
|
|
5
|
+
-> slide({ duration: 2000 })
|
|
6
|
+
-> echo({ delay: 250, feedback: 0.5 })
|
|
7
|
+
-> reverb({ room_size: 0.8 })
|
|
8
|
+
|
|
9
|
+
myChord -> note(E4)
|
|
10
|
+
-> arp({ pattern: "up", rate: 1/8 })
|
|
11
|
+
-> slide({ duration: 2000 })
|
|
12
|
+
-> echo({ delay: 250, feedback: 0.5 })
|
|
13
|
+
-> reverb({ room_size: 0.8 })
|
|
14
|
+
|
|
15
|
+
myChord -> note(G4)
|
|
16
|
+
-> arp({ pattern: "up", rate: 1/8 })
|
|
17
|
+
-> slide({ duration: 2000 })
|
|
18
|
+
-> echo({ delay: 250, feedback: 0.5 })
|
|
19
|
+
-> reverb({ room_size: 0.8 })
|
package/examples/plugin.deva
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# This is an example of using a plugin in Devalang.
|
|
2
|
-
# Make sure you have the plugin installed in your Devaloop application. (devalang install
|
|
2
|
+
# Make sure you have the plugin installed in your Devaloop application. (devalang addon install <author>.<addon_name>)
|
|
3
3
|
|
|
4
4
|
@use devaloop.acid as acidPlugin
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
6
|
+
group acidSynthGroup:
|
|
7
|
+
let acidSynth = synth acidPlugin.synth {
|
|
8
|
+
waveform: "saw",
|
|
9
|
+
resonance: 1.0,
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
acidSynth -> note(
|
|
14
|
-
acidSynth -> note(
|
|
12
|
+
acidSynth -> note(C4, { duration: 1000 })
|
|
13
|
+
acidSynth -> note(E3, { duration: 1000 })
|
|
14
|
+
acidSynth -> note(B2, { duration: 1000 })
|
|
15
15
|
|
|
16
|
-
call
|
|
16
|
+
call acidSynthGroup
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# NOTE Future version of Deva may include built-in routing capabilities.
|
|
2
|
+
|
|
3
|
+
# @load "./samples/kick-808.wav" as kickCustom
|
|
4
|
+
|
|
5
|
+
# group myLead:
|
|
6
|
+
# let mySynth = synth sine
|
|
7
|
+
|
|
8
|
+
# mySynth -> note(C4, { duration: 400 })
|
|
9
|
+
|
|
10
|
+
# group myKick:
|
|
11
|
+
# .kickCustom 1/4
|
|
12
|
+
|
|
13
|
+
# routing:
|
|
14
|
+
# node $master
|
|
15
|
+
# node myLead
|
|
16
|
+
# node myKick
|
|
17
|
+
# node hallReverb = effect reverb { decay: 3.0, mix: 0.5 }
|
|
18
|
+
|
|
19
|
+
# connect myLead -> hallReverb -> $master
|
|
20
|
+
|
|
21
|
+
# connect myLead -> $master with { delay: { time: 300, feedback: 0.3 } }
|
|
22
|
+
|
|
23
|
+
# connect myKick -> myLead with { sidechain: 0.6 }
|
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
/* tslint:disable */
|
|
2
2
|
/* eslint-disable */
|
|
3
3
|
export const memory: WebAssembly.Memory;
|
|
4
|
-
export const
|
|
4
|
+
export const collect_playhead_events: () => [number, number, number];
|
|
5
5
|
export const debug_render: (a: number, b: number) => [number, number, number];
|
|
6
|
-
export const
|
|
6
|
+
export const parse: (a: number, b: number, c: number, d: number) => [number, number, number];
|
|
7
7
|
export const register_playhead_callback: (a: any) => void;
|
|
8
|
-
export const
|
|
8
|
+
export const render_audio: (a: number, b: number) => [number, number, number];
|
|
9
9
|
export const unregister_playhead_callback: () => void;
|
|
10
|
-
export const rust_lzma_wasm_shim_malloc: (a: number) => number;
|
|
11
10
|
export const rust_lzma_wasm_shim_calloc: (a: number, b: number) => number;
|
|
12
11
|
export const rust_lzma_wasm_shim_free: (a: number) => void;
|
|
12
|
+
export const rust_lzma_wasm_shim_malloc: (a: number) => number;
|
|
13
|
+
export const rust_lzma_wasm_shim_memchr: (a: number, b: number, c: number) => number;
|
|
13
14
|
export const rust_lzma_wasm_shim_memcmp: (a: number, b: number, c: number) => number;
|
|
14
15
|
export const rust_lzma_wasm_shim_memcpy: (a: number, b: number, c: number) => number;
|
|
15
16
|
export const rust_lzma_wasm_shim_memmove: (a: number, b: number, c: number) => number;
|
|
16
17
|
export const rust_lzma_wasm_shim_memset: (a: number, b: number, c: number) => number;
|
|
17
18
|
export const rust_lzma_wasm_shim_strlen: (a: number) => number;
|
|
18
|
-
export const rust_lzma_wasm_shim_memchr: (a: number, b: number, c: number) => number;
|
|
19
|
-
export const rust_zstd_wasm_shim_qsort: (a: number, b: number, c: number, d: number) => void;
|
|
20
|
-
export const rust_zstd_wasm_shim_malloc: (a: number) => number;
|
|
21
|
-
export const rust_zstd_wasm_shim_memcmp: (a: number, b: number, c: number) => number;
|
|
22
19
|
export const rust_zstd_wasm_shim_calloc: (a: number, b: number) => number;
|
|
23
20
|
export const rust_zstd_wasm_shim_free: (a: number) => void;
|
|
21
|
+
export const rust_zstd_wasm_shim_malloc: (a: number) => number;
|
|
22
|
+
export const rust_zstd_wasm_shim_memcmp: (a: number, b: number, c: number) => number;
|
|
24
23
|
export const rust_zstd_wasm_shim_memcpy: (a: number, b: number, c: number) => number;
|
|
25
24
|
export const rust_zstd_wasm_shim_memmove: (a: number, b: number, c: number) => number;
|
|
26
25
|
export const rust_zstd_wasm_shim_memset: (a: number, b: number, c: number) => number;
|
|
26
|
+
export const rust_zstd_wasm_shim_qsort: (a: number, b: number, c: number, d: number) => void;
|
|
27
27
|
export const __wbindgen_malloc: (a: number, b: number) => number;
|
|
28
28
|
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
|
29
29
|
export const __wbindgen_exn_store: (a: number) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const argv = process.argv.slice(2);
|
|
9
|
+
let sourceArg;
|
|
10
|
+
let binaryArg;
|
|
11
|
+
let outDirArg;
|
|
12
|
+
for (let i = 0; i < argv.length; i++) {
|
|
13
|
+
const a = argv[i];
|
|
14
|
+
if (a === "--source") {
|
|
15
|
+
sourceArg = argv[++i];
|
|
16
|
+
}
|
|
17
|
+
else if (a === "--binary") {
|
|
18
|
+
binaryArg = argv[++i];
|
|
19
|
+
}
|
|
20
|
+
else if (a === "--out-dir") {
|
|
21
|
+
outDirArg = argv[++i];
|
|
22
|
+
}
|
|
23
|
+
else if (a === "--help" || a === "-h") {
|
|
24
|
+
process.exit(0);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.error(`Unknown arg: ${a}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Default source: attempt to locate project-version.json at repo root
|
|
32
|
+
const defaultSource = path_1.default.resolve(__dirname, "..", "..", "..", "project-version.json");
|
|
33
|
+
const sourcePath = sourceArg ? path_1.default.resolve(sourceArg) : defaultSource;
|
|
34
|
+
if (!fs_1.default.existsSync(sourcePath)) {
|
|
35
|
+
console.error(`Source project-version.json not found at '${sourcePath}'. Please provide --source or ensure file exists.`);
|
|
36
|
+
process.exit(2);
|
|
37
|
+
}
|
|
38
|
+
let destDir = null;
|
|
39
|
+
if (binaryArg) {
|
|
40
|
+
const binPath = path_1.default.resolve(binaryArg);
|
|
41
|
+
// If it's an existing file, use its directory, otherwise assume user passed target path and use its parent
|
|
42
|
+
if (fs_1.default.existsSync(binPath) && fs_1.default.statSync(binPath).isFile()) {
|
|
43
|
+
destDir = path_1.default.dirname(binPath);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// If binPath looks like a file path (has extension) use parent, else treat as dir
|
|
47
|
+
const ext = path_1.default.extname(binPath);
|
|
48
|
+
if (ext) {
|
|
49
|
+
destDir = path_1.default.dirname(binPath);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
destDir = binPath;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (outDirArg) {
|
|
57
|
+
destDir = path_1.default.resolve(outDirArg);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Default: try to copy next to the running node current working dir (useful when packaging)
|
|
61
|
+
destDir = process.cwd();
|
|
62
|
+
}
|
|
63
|
+
if (!destDir) {
|
|
64
|
+
console.error("Could not resolve destination directory");
|
|
65
|
+
process.exit(3);
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
if (!fs_1.default.existsSync(destDir)) {
|
|
69
|
+
fs_1.default.mkdirSync(destDir, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
const destPath = path_1.default.join(destDir, "project-version.json");
|
|
72
|
+
fs_1.default.copyFileSync(sourcePath, destPath);
|
|
73
|
+
console.log(`project-version.json copied to '${destPath}'`);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error("Failed to copy project-version.json:", err);
|
|
78
|
+
process.exit(4);
|
|
79
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devaloop/devalang",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.3",
|
|
5
5
|
"description": "Write music like code. Devalang is a domain-specific language (DSL) for sound designers and music hackers. Compose, automate, and control sound — in plain text.",
|
|
6
|
+
"longDescription": "Devalang is a compact, performant DSL and toolchain for composing, automating and rendering sound. It provides a CLI, WASM bindings, a TypeScript API, and plugins for editors. Ideal for live-coding, sample-based production, algorithmic composition, and fast prototyping.",
|
|
6
7
|
"main": "out-tsc/index.js",
|
|
7
8
|
"bin": {
|
|
8
9
|
"devalang": "./out-tsc/bin/index.js"
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
"rust:prepack": "cargo build --release",
|
|
19
20
|
"scripts:postbuild": "tsc && node out-tsc/scripts/postbuild.js",
|
|
20
21
|
"scripts:version:bump": "tsc && node out-tsc/scripts/version/index.js",
|
|
22
|
+
"scripts:copy-version": "tsc && node out-tsc/scripts/version/copy-to-binary.js --out-dir ./out-tsc/bin",
|
|
21
23
|
"scripts:build": "tsc",
|
|
22
24
|
"types:build": "tsc --emitDeclarationOnly",
|
|
23
25
|
"types:wasm": "tsc && node out-tsc/scripts/copy-wasm-dts.js",
|
|
@@ -25,25 +27,36 @@
|
|
|
25
27
|
"test:rust": "cargo test",
|
|
26
28
|
"test:ts": "mocha -r ts-node/register tests/typescript/**/*.spec.ts --exit",
|
|
27
29
|
"test": "npm run test:ts",
|
|
28
|
-
"postinstall": "node out-tsc/scripts/postinstall.js"
|
|
30
|
+
"postinstall": "node out-tsc/scripts/postinstall.js",
|
|
31
|
+
"beforepublish": "npm run types:all && npm run scripts:copy-version"
|
|
29
32
|
},
|
|
30
33
|
"homepage": "https://devalang.com",
|
|
31
34
|
"keywords": [
|
|
32
35
|
"devalang",
|
|
33
36
|
"music",
|
|
34
37
|
"sound",
|
|
35
|
-
"domain-specific language",
|
|
36
38
|
"dsl",
|
|
37
|
-
"
|
|
38
|
-
"sound design",
|
|
39
|
-
"music hacking",
|
|
39
|
+
"domain-specific-language",
|
|
40
40
|
"audio",
|
|
41
|
+
"music-programming",
|
|
41
42
|
"synthesis",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"midi",
|
|
44
|
+
"wasm",
|
|
45
|
+
"vscode",
|
|
46
|
+
"live-coding",
|
|
47
|
+
"sound-design",
|
|
48
|
+
"samples",
|
|
49
|
+
"cli"
|
|
45
50
|
],
|
|
46
|
-
"author":
|
|
51
|
+
"author": {
|
|
52
|
+
"name": "Devaloop",
|
|
53
|
+
"email": "contact@devaloop.com",
|
|
54
|
+
"url": "https://devaloop.com"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/devaloop-labs/devalang/issues",
|
|
58
|
+
"email": "contact@devaloop.com"
|
|
59
|
+
},
|
|
47
60
|
"license": "MIT",
|
|
48
61
|
"repository": {
|
|
49
62
|
"type": "git",
|
package/project-version.json
CHANGED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//! Minimal, focused bindings helpers for writing custom render functions in
|
|
2
|
+
//! plugin crates.
|
|
3
|
+
//!
|
|
4
|
+
//! The core runtime already handles registration and FFI bridging. This crate
|
|
5
|
+
//! only exports the types and function-signature aliases that plugin authors
|
|
6
|
+
//! should implement in safe Rust. The host will convert raw buffers/pointers
|
|
7
|
+
//! into these safe types before calling the plugin function.
|
|
8
|
+
//!
|
|
9
|
+
//! Guiding principle: plugin authors write purely safe Rust functions with
|
|
10
|
+
//! clear parameters (slices and small structs). No registration helpers or
|
|
11
|
+
//! global registries are provided here.
|
|
12
|
+
|
|
13
|
+
/// Lightweight representation of a musical note.
|
|
14
|
+
#[derive(Debug, Clone, Copy)]
|
|
15
|
+
pub struct Note {
|
|
16
|
+
/// MIDI pitch 0..127
|
|
17
|
+
pub pitch: u8,
|
|
18
|
+
/// Velocity 0..127
|
|
19
|
+
pub velocity: u8,
|
|
20
|
+
/// Note duration in milliseconds (approximate)
|
|
21
|
+
pub duration_ms: u32,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
impl Default for Note {
|
|
25
|
+
fn default() -> Self {
|
|
26
|
+
Self { pitch: 60, velocity: 100, duration_ms: 500 }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Parameters describing the output buffer and audio context.
|
|
31
|
+
#[derive(Debug, Clone, Copy)]
|
|
32
|
+
pub struct BufferParams {
|
|
33
|
+
/// Sample rate in Hz
|
|
34
|
+
pub sample_rate: u32,
|
|
35
|
+
/// Number of channels (1 = mono, 2 = stereo, ...)
|
|
36
|
+
pub channels: u32,
|
|
37
|
+
/// Number of frames (samples per channel) available in the buffer
|
|
38
|
+
pub frames: u32,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Helper to compute expected buffer length (frames * channels).
|
|
42
|
+
impl BufferParams {
|
|
43
|
+
/// Returns the expected length of the interleaved buffer (frames * channels)
|
|
44
|
+
/// as a host-friendly `usize`. The host is responsible for converting
|
|
45
|
+
/// its platform-sized integers into these explicit-width fields.
|
|
46
|
+
pub fn buffer_len(&self) -> usize {
|
|
47
|
+
(self.frames as usize).saturating_mul(self.channels as usize)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Quick validation helper that plugins can call to ensure the provided
|
|
51
|
+
/// output slice matches the declared `params` length.
|
|
52
|
+
pub fn validate_buffer(out: &mut [f32], params: BufferParams) -> Result<(), &'static str> {
|
|
53
|
+
let expected = params.buffer_len();
|
|
54
|
+
if out.len() < expected { Err("output buffer too small") } else { Ok(()) }
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
impl Default for BufferParams {
|
|
59
|
+
fn default() -> Self {
|
|
60
|
+
Self { sample_rate: 44100, channels: 1, frames: 0 }
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Common render function signature plugin authors should implement.
|
|
65
|
+
///
|
|
66
|
+
/// - `out` is a mutable slice of f32 samples (interleaved if channels > 1).
|
|
67
|
+
/// - `params` provides sample rate / channels / frames info.
|
|
68
|
+
/// - `note` is the Note descriptor.
|
|
69
|
+
/// - `freq`/`amp` give additional voice parameters the host may pass.
|
|
70
|
+
pub type RenderFn = fn(out: &mut [f32], params: BufferParams, note: Note, freq: f32, amp: f32);
|
|
71
|
+
|
|
72
|
+
/// A more complete signature used by synth-style plugins that also need
|
|
73
|
+
/// access to extra controls (e.g. voice index or time offset).
|
|
74
|
+
pub type RenderFnExt = fn(
|
|
75
|
+
out: &mut [f32],
|
|
76
|
+
params: BufferParams,
|
|
77
|
+
note: Note,
|
|
78
|
+
freq: f32,
|
|
79
|
+
amp: f32,
|
|
80
|
+
voice_index: u32,
|
|
81
|
+
time_ms: u64,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
/// Optional signature for control parameter setters. The host can call these
|
|
85
|
+
/// safely by converting raw values into primitives.
|
|
86
|
+
pub type SetParamFn = fn(param_name: &str, value: f32);
|