@devaloop/devalang 0.0.1-beta.3 → 0.1.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.
Files changed (345) hide show
  1. package/README.md +182 -152
  2. package/out-tsc/api.d.ts +180 -0
  3. package/out-tsc/api.d.ts.map +1 -0
  4. package/out-tsc/api.js +286 -0
  5. package/out-tsc/api.js.map +1 -0
  6. package/out-tsc/bin/index.d.ts +12 -0
  7. package/out-tsc/bin/index.d.ts.map +1 -0
  8. package/out-tsc/bin/index.js +20 -54
  9. package/out-tsc/bin/index.js.map +1 -0
  10. package/out-tsc/examples/basic-usage.d.ts +8 -0
  11. package/out-tsc/examples/basic-usage.d.ts.map +1 -0
  12. package/out-tsc/examples/basic-usage.js +113 -0
  13. package/out-tsc/examples/basic-usage.js.map +1 -0
  14. package/out-tsc/index.d.ts +19 -5
  15. package/out-tsc/index.d.ts.map +1 -0
  16. package/out-tsc/index.js +24 -6
  17. package/out-tsc/index.js.map +1 -0
  18. package/out-tsc/scripts/copy-wasm-dts.d.ts +7 -0
  19. package/out-tsc/scripts/copy-wasm-dts.d.ts.map +1 -0
  20. package/out-tsc/scripts/copy-wasm-dts.js +36 -32
  21. package/out-tsc/scripts/copy-wasm-dts.js.map +1 -0
  22. package/out-tsc/scripts/postinstall.d.ts +1 -0
  23. package/out-tsc/scripts/postinstall.d.ts.map +1 -0
  24. package/out-tsc/scripts/postinstall.js +4 -1
  25. package/out-tsc/scripts/postinstall.js.map +1 -0
  26. package/out-tsc/scripts/version/bump.d.ts +5 -1
  27. package/out-tsc/scripts/version/bump.d.ts.map +1 -0
  28. package/out-tsc/scripts/version/bump.js +114 -44
  29. package/out-tsc/scripts/version/bump.js.map +1 -0
  30. package/out-tsc/scripts/version/fetch.d.ts +12 -1
  31. package/out-tsc/scripts/version/fetch.d.ts.map +1 -0
  32. package/out-tsc/scripts/version/fetch.js +68 -24
  33. package/out-tsc/scripts/version/fetch.js.map +1 -0
  34. package/out-tsc/scripts/version/index.d.ts +6 -0
  35. package/out-tsc/scripts/version/index.d.ts.map +1 -0
  36. package/out-tsc/scripts/version/index.js +44 -22
  37. package/out-tsc/scripts/version/index.js.map +1 -0
  38. package/out-tsc/scripts/version/sync.d.ts +5 -1
  39. package/out-tsc/scripts/version/sync.d.ts.map +1 -0
  40. package/out-tsc/scripts/version/sync.js +78 -29
  41. package/out-tsc/scripts/version/sync.js.map +1 -0
  42. package/out-tsc/types.d.ts +68 -0
  43. package/out-tsc/types.d.ts.map +1 -0
  44. package/out-tsc/{core/types/value.js → types.js} +4 -0
  45. package/out-tsc/types.js.map +1 -0
  46. package/out-tsc/wasm.d.ts +8 -0
  47. package/out-tsc/wasm.d.ts.map +1 -0
  48. package/out-tsc/{core/index.js → wasm.js} +9 -6
  49. package/out-tsc/wasm.js.map +1 -0
  50. package/package.json +42 -42
  51. package/.cargo/config.toml +0 -2
  52. package/.devalang +0 -9
  53. package/.github/workflows/ci.yml +0 -103
  54. package/Cargo.toml +0 -84
  55. package/docs/CHANGELOG.md +0 -622
  56. package/docs/CONTRIBUTING.md +0 -101
  57. package/docs/ROADMAP.md +0 -38
  58. package/docs/TODO.md +0 -71
  59. package/examples/automation.deva +0 -42
  60. package/examples/bank.deva +0 -7
  61. package/examples/bus.deva +0 -10
  62. package/examples/chain.deva +0 -19
  63. package/examples/condition.deva +0 -20
  64. package/examples/duration.deva +0 -9
  65. package/examples/effect.deva +0 -2
  66. package/examples/events.deva +0 -12
  67. package/examples/filter.deva +0 -11
  68. package/examples/function.deva +0 -15
  69. package/examples/group.deva +0 -12
  70. package/examples/index.deva +0 -63
  71. package/examples/lfo.deva +0 -9
  72. package/examples/loop.deva +0 -10
  73. package/examples/pattern.deva +0 -8
  74. package/examples/plugin.deva +0 -16
  75. package/examples/routing.deva +0 -23
  76. package/examples/samples/hat-808.wav +0 -0
  77. package/examples/samples/kick-808.wav +0 -0
  78. package/examples/synth.deva +0 -24
  79. package/examples/synth_types.deva +0 -17
  80. package/examples/variables.deva +0 -9
  81. package/out-tsc/bin/project-version.json +0 -6
  82. package/out-tsc/core/functions/index.d.ts +0 -42
  83. package/out-tsc/core/functions/index.js +0 -87
  84. package/out-tsc/core/index.d.ts +0 -6
  85. package/out-tsc/core/types/index.d.ts +0 -4
  86. package/out-tsc/core/types/index.js +0 -20
  87. package/out-tsc/core/types/plugin.d.ts +0 -18
  88. package/out-tsc/core/types/plugin.js +0 -2
  89. package/out-tsc/core/types/result.d.ts +0 -27
  90. package/out-tsc/core/types/result.js +0 -2
  91. package/out-tsc/core/types/statement.d.ts +0 -106
  92. package/out-tsc/core/types/statement.js +0 -2
  93. package/out-tsc/core/types/value.d.ts +0 -43
  94. package/out-tsc/pkg/devalang_core.d.ts +0 -15
  95. package/out-tsc/pkg/devalang_core.js +0 -65
  96. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +0 -34
  97. package/out-tsc/scripts/version/copy-to-binary.d.ts +0 -1
  98. package/out-tsc/scripts/version/copy-to-binary.js +0 -79
  99. package/project-version.json +0 -6
  100. package/rust/bindings/Cargo.toml +0 -9
  101. package/rust/bindings/src/lib.rs +0 -86
  102. package/rust/cli/addon/commands.rs +0 -35
  103. package/rust/cli/addon/download.rs +0 -234
  104. package/rust/cli/addon/install.rs +0 -33
  105. package/rust/cli/addon/list.rs +0 -224
  106. package/rust/cli/addon/metadata.rs +0 -124
  107. package/rust/cli/addon/mod.rs +0 -8
  108. package/rust/cli/addon/remove.rs +0 -271
  109. package/rust/cli/addon/update.rs +0 -305
  110. package/rust/cli/addon/utils.rs +0 -109
  111. package/rust/cli/build/commands.rs +0 -153
  112. package/rust/cli/build/mod.rs +0 -2
  113. package/rust/cli/build/process.rs +0 -165
  114. package/rust/cli/check/mod.rs +0 -208
  115. package/rust/cli/discover/commands.rs +0 -275
  116. package/rust/cli/discover/config.rs +0 -109
  117. package/rust/cli/discover/fs.rs +0 -19
  118. package/rust/cli/discover/install.rs +0 -214
  119. package/rust/cli/discover/metadata.rs +0 -48
  120. package/rust/cli/discover/mod.rs +0 -5
  121. package/rust/cli/init/commands.rs +0 -88
  122. package/rust/cli/init/mod.rs +0 -1
  123. package/rust/cli/login/commands.rs +0 -124
  124. package/rust/cli/login/mod.rs +0 -1
  125. package/rust/cli/me/commands.rs +0 -52
  126. package/rust/cli/me/mod.rs +0 -1
  127. package/rust/cli/mod.rs +0 -12
  128. package/rust/cli/parser.rs +0 -320
  129. package/rust/cli/play/commands.rs +0 -375
  130. package/rust/cli/play/io.rs +0 -17
  131. package/rust/cli/play/mod.rs +0 -5
  132. package/rust/cli/play/process.rs +0 -159
  133. package/rust/cli/play/realtime.rs +0 -91
  134. package/rust/cli/play/utils.rs +0 -23
  135. package/rust/cli/telemetry/commands.rs +0 -22
  136. package/rust/cli/telemetry/event_creator.rs +0 -80
  137. package/rust/cli/telemetry/mod.rs +0 -3
  138. package/rust/cli/telemetry/send.rs +0 -51
  139. package/rust/cli/template/commands.rs +0 -69
  140. package/rust/cli/template/mod.rs +0 -1
  141. package/rust/cli/update/commands.rs +0 -6
  142. package/rust/cli/update/mod.rs +0 -1
  143. package/rust/config/driver.rs +0 -112
  144. package/rust/config/mod.rs +0 -3
  145. package/rust/config/ops.rs +0 -26
  146. package/rust/config/settings.rs +0 -101
  147. package/rust/core/audio/engine/driver.rs +0 -237
  148. package/rust/core/audio/engine/export.rs +0 -169
  149. package/rust/core/audio/engine/helpers.rs +0 -178
  150. package/rust/core/audio/engine/mod.rs +0 -56
  151. package/rust/core/audio/engine/notes/dsp.rs +0 -88
  152. package/rust/core/audio/engine/notes/mod.rs +0 -53
  153. package/rust/core/audio/engine/notes/params.rs +0 -294
  154. package/rust/core/audio/engine/sample/insert.rs +0 -300
  155. package/rust/core/audio/engine/sample/mod.rs +0 -40
  156. package/rust/core/audio/engine/sample/padding.rs +0 -170
  157. package/rust/core/audio/evaluator/condition.rs +0 -61
  158. package/rust/core/audio/evaluator/mod.rs +0 -9
  159. package/rust/core/audio/evaluator/numeric.rs +0 -152
  160. package/rust/core/audio/evaluator/rhs.rs +0 -16
  161. package/rust/core/audio/evaluator/string_expr.rs +0 -94
  162. package/rust/core/audio/interpreter/driver.rs +0 -574
  163. package/rust/core/audio/interpreter/mod.rs +0 -2
  164. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +0 -179
  165. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +0 -398
  166. package/rust/core/audio/interpreter/statements/arrow_call/methods/effects.rs +0 -323
  167. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +0 -3
  168. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +0 -371
  169. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +0 -3
  170. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +0 -192
  171. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +0 -24
  172. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +0 -116
  173. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +0 -97
  174. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +0 -100
  175. package/rust/core/audio/interpreter/statements/automate.rs +0 -16
  176. package/rust/core/audio/interpreter/statements/call.rs +0 -325
  177. package/rust/core/audio/interpreter/statements/condition.rs +0 -72
  178. package/rust/core/audio/interpreter/statements/function.rs +0 -24
  179. package/rust/core/audio/interpreter/statements/let_.rs +0 -36
  180. package/rust/core/audio/interpreter/statements/load.rs +0 -17
  181. package/rust/core/audio/interpreter/statements/loop_.rs +0 -115
  182. package/rust/core/audio/interpreter/statements/mod.rs +0 -12
  183. package/rust/core/audio/interpreter/statements/sleep.rs +0 -28
  184. package/rust/core/audio/interpreter/statements/spawn.rs +0 -302
  185. package/rust/core/audio/interpreter/statements/tempo.rs +0 -40
  186. package/rust/core/audio/interpreter/statements/trigger.rs +0 -242
  187. package/rust/core/audio/loader/mod.rs +0 -1
  188. package/rust/core/audio/loader/trigger.rs +0 -98
  189. package/rust/core/audio/mod.rs +0 -6
  190. package/rust/core/audio/player.rs +0 -70
  191. package/rust/core/audio/special/easing.rs +0 -189
  192. package/rust/core/audio/special/env.rs +0 -45
  193. package/rust/core/audio/special/math.rs +0 -134
  194. package/rust/core/audio/special/mod.rs +0 -9
  195. package/rust/core/audio/special/modulator.rs +0 -143
  196. package/rust/core/builder/mod.rs +0 -129
  197. package/rust/core/debugger/lexer.rs +0 -27
  198. package/rust/core/debugger/logs.rs +0 -52
  199. package/rust/core/debugger/mod.rs +0 -30
  200. package/rust/core/debugger/preprocessor.rs +0 -27
  201. package/rust/core/debugger/store.rs +0 -38
  202. package/rust/core/error/mod.rs +0 -269
  203. package/rust/core/lexer/driver.rs +0 -59
  204. package/rust/core/lexer/handler/arrow.rs +0 -82
  205. package/rust/core/lexer/handler/at.rs +0 -21
  206. package/rust/core/lexer/handler/brace.rs +0 -41
  207. package/rust/core/lexer/handler/colon.rs +0 -21
  208. package/rust/core/lexer/handler/comment.rs +0 -30
  209. package/rust/core/lexer/handler/dot.rs +0 -21
  210. package/rust/core/lexer/handler/driver.rs +0 -337
  211. package/rust/core/lexer/handler/identifier.rs +0 -47
  212. package/rust/core/lexer/handler/indent.rs +0 -66
  213. package/rust/core/lexer/handler/mod.rs +0 -15
  214. package/rust/core/lexer/handler/newline.rs +0 -23
  215. package/rust/core/lexer/handler/number.rs +0 -31
  216. package/rust/core/lexer/handler/operator.rs +0 -46
  217. package/rust/core/lexer/handler/parenthesis.rs +0 -41
  218. package/rust/core/lexer/handler/slash.rs +0 -21
  219. package/rust/core/lexer/handler/string.rs +0 -63
  220. package/rust/core/lexer/mod.rs +0 -3
  221. package/rust/core/lexer/token.rs +0 -91
  222. package/rust/core/mod.rs +0 -9
  223. package/rust/core/parser/driver/block.rs +0 -111
  224. package/rust/core/parser/driver/cursor.rs +0 -82
  225. package/rust/core/parser/driver/driver_impl.rs +0 -159
  226. package/rust/core/parser/driver/mod.rs +0 -6
  227. package/rust/core/parser/driver/parse_array.rs +0 -120
  228. package/rust/core/parser/driver/parse_map.rs +0 -247
  229. package/rust/core/parser/driver/parser.rs +0 -160
  230. package/rust/core/parser/handler/arrow_call.rs +0 -328
  231. package/rust/core/parser/handler/at.rs +0 -279
  232. package/rust/core/parser/handler/bank.rs +0 -104
  233. package/rust/core/parser/handler/condition.rs +0 -83
  234. package/rust/core/parser/handler/dot.rs +0 -148
  235. package/rust/core/parser/handler/identifier/automate.rs +0 -254
  236. package/rust/core/parser/handler/identifier/call.rs +0 -91
  237. package/rust/core/parser/handler/identifier/emit.rs +0 -70
  238. package/rust/core/parser/handler/identifier/function.rs +0 -113
  239. package/rust/core/parser/handler/identifier/group.rs +0 -89
  240. package/rust/core/parser/handler/identifier/let_.rs +0 -173
  241. package/rust/core/parser/handler/identifier/mod.rs +0 -55
  242. package/rust/core/parser/handler/identifier/on.rs +0 -107
  243. package/rust/core/parser/handler/identifier/print.rs +0 -49
  244. package/rust/core/parser/handler/identifier/sleep.rs +0 -96
  245. package/rust/core/parser/handler/identifier/spawn.rs +0 -91
  246. package/rust/core/parser/handler/identifier/synth.rs +0 -171
  247. package/rust/core/parser/handler/loop_.rs +0 -194
  248. package/rust/core/parser/handler/mod.rs +0 -9
  249. package/rust/core/parser/handler/pattern.rs +0 -97
  250. package/rust/core/parser/handler/tempo.rs +0 -105
  251. package/rust/core/parser/mod.rs +0 -3
  252. package/rust/core/parser/statement.rs +0 -10
  253. package/rust/core/plugin/loader.rs +0 -137
  254. package/rust/core/plugin/mod.rs +0 -2
  255. package/rust/core/plugin/runner/mod.rs +0 -11
  256. package/rust/core/plugin/runner/non_wasm.rs +0 -481
  257. package/rust/core/plugin/runner/wasm32.rs +0 -44
  258. package/rust/core/preprocessor/loader/inject.rs +0 -313
  259. package/rust/core/preprocessor/loader/loader_helpers.rs +0 -110
  260. package/rust/core/preprocessor/loader/mod.rs +0 -235
  261. package/rust/core/preprocessor/mod.rs +0 -4
  262. package/rust/core/preprocessor/module.rs +0 -55
  263. package/rust/core/preprocessor/processor/handlers.rs +0 -107
  264. package/rust/core/preprocessor/processor/mod.rs +0 -1
  265. package/rust/core/preprocessor/resolver/bank.rs +0 -49
  266. package/rust/core/preprocessor/resolver/call.rs +0 -124
  267. package/rust/core/preprocessor/resolver/condition.rs +0 -95
  268. package/rust/core/preprocessor/resolver/driver.rs +0 -324
  269. package/rust/core/preprocessor/resolver/function.rs +0 -69
  270. package/rust/core/preprocessor/resolver/group.rs +0 -122
  271. package/rust/core/preprocessor/resolver/let_.rs +0 -32
  272. package/rust/core/preprocessor/resolver/loop_.rs +0 -318
  273. package/rust/core/preprocessor/resolver/mod.rs +0 -16
  274. package/rust/core/preprocessor/resolver/pattern.rs +0 -95
  275. package/rust/core/preprocessor/resolver/spawn.rs +0 -99
  276. package/rust/core/preprocessor/resolver/synth.rs +0 -54
  277. package/rust/core/preprocessor/resolver/tempo.rs +0 -48
  278. package/rust/core/preprocessor/resolver/trigger.rs +0 -116
  279. package/rust/core/preprocessor/resolver/value.rs +0 -176
  280. package/rust/core/store/global.rs +0 -57
  281. package/rust/core/store/mod.rs +0 -1
  282. package/rust/lib.rs +0 -323
  283. package/rust/macros/Cargo.toml +0 -14
  284. package/rust/macros/src/lib.rs +0 -52
  285. package/rust/main.rs +0 -557
  286. package/rust/types/Cargo.toml +0 -11
  287. package/rust/types/src/addons.rs +0 -57
  288. package/rust/types/src/ast.rs +0 -202
  289. package/rust/types/src/config.rs +0 -82
  290. package/rust/types/src/lib.rs +0 -15
  291. package/rust/types/src/plugin.rs +0 -20
  292. package/rust/types/src/store.rs +0 -139
  293. package/rust/types/src/telemetry.rs +0 -85
  294. package/rust/utils/Cargo.toml +0 -29
  295. package/rust/utils/src/error.rs +0 -186
  296. package/rust/utils/src/file.rs +0 -477
  297. package/rust/utils/src/first_usage.rs +0 -97
  298. package/rust/utils/src/lib.rs +0 -9
  299. package/rust/utils/src/logger.rs +0 -200
  300. package/rust/utils/src/path.rs +0 -158
  301. package/rust/utils/src/signature.rs +0 -41
  302. package/rust/utils/src/spinner.rs +0 -20
  303. package/rust/utils/src/version.rs +0 -58
  304. package/rust/utils/src/watcher.rs +0 -46
  305. package/rust/web/api.rs +0 -5
  306. package/rust/web/auth.rs +0 -5
  307. package/rust/web/cdn.rs +0 -34
  308. package/rust/web/forge.rs +0 -5
  309. package/rust/web/mod.rs +0 -5
  310. package/rust/web/sso.rs +0 -5
  311. package/templates/minimal/.devalang +0 -5
  312. package/templates/minimal/README.md +0 -218
  313. package/templates/minimal/src/index.deva +0 -2
  314. package/templates/welcome/.devalang +0 -5
  315. package/templates/welcome/README.md +0 -218
  316. package/templates/welcome/samples/kick-808.wav +0 -0
  317. package/templates/welcome/src/index.deva +0 -61
  318. package/templates/welcome/src/variables.deva +0 -3
  319. package/tests/integration.rs +0 -21
  320. package/tests/rust/cli_check_build.rs +0 -21
  321. package/tests/rust/cli_help.rs +0 -12
  322. package/tests/rust/cli_template_list.rs +0 -10
  323. package/tests/rust/cli_version.rs +0 -11
  324. package/tests/typescript/index.spec.ts +0 -136
  325. package/tests/typescript/playhead.spec.ts +0 -36
  326. package/tests/typescript/render_e2e.spec.ts +0 -77
  327. package/tsconfig.json +0 -115
  328. package/typescript/bin/index.ts +0 -28
  329. package/typescript/core/functions/index.ts +0 -94
  330. package/typescript/core/index.ts +0 -6
  331. package/typescript/core/types/index.ts +0 -4
  332. package/typescript/core/types/plugin.ts +0 -19
  333. package/typescript/core/types/result.ts +0 -29
  334. package/typescript/core/types/statement.ts +0 -47
  335. package/typescript/core/types/value.ts +0 -29
  336. package/typescript/index.ts +0 -8
  337. package/typescript/pkg/devalang_core.d.ts +0 -4
  338. package/typescript/pkg/devalang_core.ts +0 -65
  339. package/typescript/scripts/copy-wasm-dts.ts +0 -41
  340. package/typescript/scripts/postinstall.ts +0 -85
  341. package/typescript/scripts/version/bump.ts +0 -44
  342. package/typescript/scripts/version/copy-to-binary.ts +0 -82
  343. package/typescript/scripts/version/fetch.ts +0 -18
  344. package/typescript/scripts/version/index.ts +0 -25
  345. package/typescript/scripts/version/sync.ts +0 -24
@@ -1,323 +0,0 @@
1
- use crate::core::audio::engine::AudioEngine;
2
- use devalang_types::Value;
3
- use devalang_utils::logger::{LogLevel, Logger};
4
- use std::collections::HashMap;
5
-
6
- fn parse_value_to_f32(v: &Value) -> Option<f32> {
7
- match v {
8
- Value::Number(n) => Some(*n as f32),
9
- Value::String(s) => s.parse::<f32>().ok(),
10
- Value::Identifier(s) => s.parse::<f32>().ok(),
11
- Value::Boolean(b) => Some(if *b { 1.0 } else { 0.0 }),
12
- _ => None,
13
- }
14
- }
15
-
16
- // Simple nearest-neighbour resampler that produces an output with the same frame count
17
- // while applying a time-scaling factor per frame. channels = interleaved channel count.
18
- fn resample_segment_nearest(
19
- src: &[i16],
20
- channels: usize,
21
- start_rate: f32,
22
- end_rate: f32,
23
- ) -> Vec<i16> {
24
- if src.is_empty() || channels == 0 {
25
- return Vec::new();
26
- }
27
-
28
- let frames = src.len() / channels;
29
- if frames == 0 {
30
- return Vec::new();
31
- }
32
-
33
- // Copy source into frames x channels matrix access via frame*channels + ch
34
- let mut out = vec![0i16; frames * channels];
35
-
36
- for f in 0..frames {
37
- let t = if frames > 1 {
38
- f as f32 / (frames - 1) as f32
39
- } else {
40
- 0.0
41
- };
42
- let rate = start_rate + t * (end_rate - start_rate);
43
- let inv_rate = if rate == 0.0 { 1.0 } else { 1.0 / rate };
44
-
45
- // determine source frame position (nearest)
46
- let src_frame_pos = (f as f32 * inv_rate).clamp(0.0, (frames - 1) as f32);
47
- let src_idx = src_frame_pos.round() as usize;
48
-
49
- for ch in 0..channels {
50
- let s_idx = src_idx.saturating_mul(channels).saturating_add(ch);
51
- let o_idx = f.saturating_mul(channels).saturating_add(ch);
52
- let sample = if s_idx < src.len() { src[s_idx] } else { 0 };
53
- out[o_idx] = sample;
54
- }
55
- }
56
-
57
- out
58
- }
59
-
60
- // Basic effect application for chainable effects. This is intentionally minimal:
61
- // - Accepts a target synth name and args parsed from the arrow call.
62
- // - Applies effects by mutating the AudioEngine or scheduling transforms.
63
- // Current effects implemented: echo, reverb, slide (as parameter modifiers).
64
-
65
- pub fn apply_effect_chain(
66
- method: &str,
67
- args: &Vec<Value>,
68
- target: &str,
69
- audio_engine: &mut AudioEngine,
70
- variable_table: &devalang_types::VariableTable,
71
- ) {
72
- match method {
73
- "echo" => apply_echo(args, target, audio_engine, variable_table),
74
- "reverb" => apply_reverb(args, target, audio_engine, variable_table),
75
- "slide" => apply_slide(args, target, audio_engine, variable_table),
76
- "arp" => apply_arp_effect(args, target, audio_engine, variable_table),
77
- _ => {
78
- let logger = Logger::new();
79
- logger.log_message(
80
- LogLevel::Error,
81
- &format!("Unknown chainable effect '{}' on '{}'.", method, target),
82
- );
83
- }
84
- }
85
- }
86
-
87
- fn parse_map_arg(args: &Vec<Value>) -> Option<HashMap<String, Value>> {
88
- // Typical usage: method({ key: value }) -> args[0] is a Map
89
- if let Some(Value::Map(m)) = args.first() {
90
- return Some(m.clone());
91
- }
92
- None
93
- }
94
-
95
- fn apply_echo(
96
- args: &Vec<Value>,
97
- _target: &str,
98
- engine: &mut AudioEngine,
99
- _variable_table: &devalang_types::VariableTable,
100
- ) {
101
- let map = parse_map_arg(args);
102
- let mut delay_ms = 250.0_f32;
103
- let mut feedback = 0.5_f32;
104
-
105
- if let Some(m) = map {
106
- if let Some(Value::Number(n)) = m.get("delay") {
107
- delay_ms = *n as f32;
108
- }
109
- if let Some(Value::Number(n)) = m.get("feedback") {
110
- feedback = *n as f32;
111
- }
112
- }
113
-
114
- // Very small and cheap echo: we will add a delayed, attenuated copy of the buffer
115
- let sample_rate = engine.sample_rate as f32;
116
- let channels = engine.channels as usize;
117
- let delay_samples = ((delay_ms / 1000.0) * sample_rate) as usize * channels;
118
-
119
- if delay_samples == 0 || engine.buffer.is_empty() {
120
- return;
121
- }
122
-
123
- // Mix a single echo pass
124
- let mut out = engine.buffer.clone();
125
- for i in delay_samples..engine.buffer.len() {
126
- let src = engine.buffer[i - delay_samples] as f32;
127
- let added = (src * feedback)
128
- .round()
129
- .clamp(i16::MIN as f32, i16::MAX as f32) as i16;
130
- out[i] = out[i].saturating_add(added);
131
- }
132
-
133
- engine.buffer = out;
134
- }
135
-
136
- fn apply_reverb(
137
- args: &Vec<Value>,
138
- _target: &str,
139
- engine: &mut AudioEngine,
140
- _variable_table: &devalang_types::VariableTable,
141
- ) {
142
- let map = parse_map_arg(args);
143
- let mut room_size = 0.5_f32;
144
- if let Some(m) = map {
145
- if let Some(Value::Number(n)) = m.get("room_size") {
146
- room_size = *n as f32;
147
- }
148
- }
149
-
150
- // Cheap reverb: multiple short comb filters (very approximate)
151
- if engine.buffer.is_empty() {
152
- return;
153
- }
154
-
155
- let sample_rate = engine.sample_rate as f32;
156
- let channels = engine.channels as usize;
157
- let reverb_delay_samples = ((0.03 * room_size) * sample_rate) as usize * channels;
158
- if reverb_delay_samples == 0 {
159
- return;
160
- }
161
-
162
- let mut out = engine.buffer.clone();
163
- for i in reverb_delay_samples..engine.buffer.len() {
164
- let src = engine.buffer[i - reverb_delay_samples] as f32;
165
- let added = (src * room_size * 0.5)
166
- .round()
167
- .clamp(i16::MIN as f32, i16::MAX as f32) as i16;
168
- out[i] = out[i].saturating_add(added);
169
- }
170
-
171
- engine.buffer = out;
172
- }
173
-
174
- fn apply_slide(
175
- args: &Vec<Value>,
176
- _target: &str,
177
- _engine: &mut AudioEngine,
178
- _variable_table: &devalang_types::VariableTable,
179
- ) {
180
- // Slide: apply a linear pitch glide across the most recently recorded note ranges
181
- let map = parse_map_arg(args);
182
- let mut from_semitones = 0.0_f32;
183
- let mut to_semitones = 0.0_f32;
184
-
185
- if let Some(m) = map {
186
- if let Some(v) = m.get("from") {
187
- if let Some(f) = parse_value_to_f32(v) {
188
- from_semitones = f;
189
- }
190
- }
191
- if let Some(v) = m.get("to") {
192
- if let Some(t) = parse_value_to_f32(v) {
193
- to_semitones = t;
194
- }
195
- }
196
- }
197
-
198
- // Compute rate multipliers from semitone offsets
199
- let start_rate = 2f32.powf(from_semitones / 12.0);
200
- let end_rate = 2f32.powf(to_semitones / 12.0);
201
-
202
- let channels = _engine.channels as usize;
203
- if channels == 0 {
204
- return;
205
- }
206
-
207
- // For each recorded last note range for the target, apply a per-frame resample glide
208
- if let Some(ranges) = _engine.last_notes.get(_target) {
209
- for (start_sample, total_samples) in ranges.iter() {
210
- if *total_samples == 0 {
211
- continue;
212
- }
213
- // clamp range
214
- let end = (*start_sample)
215
- .saturating_add(*total_samples)
216
- .min(_engine.buffer.len());
217
- if *start_sample >= end {
218
- continue;
219
- }
220
-
221
- // work on a copy of the segment
222
- let seg = _engine.buffer[*start_sample..end].to_vec();
223
- let processed = resample_segment_nearest(&seg, channels, start_rate, end_rate);
224
-
225
- // Mix processed back into buffer (replace to preserve duration)
226
- for i in 0..processed.len().min(seg.len()) {
227
- _engine.buffer[*start_sample + i] = processed[i];
228
- }
229
- }
230
- } else {
231
- let logger = Logger::new();
232
- logger.log_message(
233
- LogLevel::Warning,
234
- "Slide requested but no recent notes found for target",
235
- );
236
- }
237
- }
238
-
239
- fn apply_arp_effect(
240
- args: &Vec<Value>,
241
- _target: &str,
242
- _engine: &mut AudioEngine,
243
- _variable_table: &devalang_types::VariableTable,
244
- ) {
245
- // Arp effect: split the last note into N slices and re-pitch each slice across a spread
246
- let map = parse_map_arg(args);
247
- let mut steps: usize = 4;
248
- let mut spread_semitones: f32 = 0.0;
249
-
250
- if let Some(m) = map {
251
- if let Some(v) = m.get("steps") {
252
- if let Some(s) = parse_value_to_f32(v) {
253
- steps = (s as usize).max(1);
254
- }
255
- }
256
- if let Some(v) = m.get("spread") {
257
- if let Some(s) = parse_value_to_f32(v) {
258
- spread_semitones = s;
259
- }
260
- }
261
- }
262
-
263
- let channels = _engine.channels as usize;
264
- if channels == 0 {
265
- return;
266
- }
267
-
268
- if let Some(ranges) = _engine.last_notes.get(_target) {
269
- for (start_sample, total_samples) in ranges.iter() {
270
- if *total_samples == 0 {
271
- continue;
272
- }
273
- let end_sample = (*start_sample)
274
- .saturating_add(*total_samples)
275
- .min(_engine.buffer.len());
276
- if *start_sample >= end_sample {
277
- continue;
278
- }
279
-
280
- let seg = _engine.buffer[*start_sample..end_sample].to_vec();
281
- let frames = seg.len() / channels;
282
- if frames == 0 {
283
- continue;
284
- }
285
-
286
- // For each step, compute semitone and pitch multiplier and place slice at computed offset
287
- for step in 0..steps {
288
- let t = if steps > 1 {
289
- step as f32 / (steps - 1) as f32
290
- } else {
291
- 0.0
292
- };
293
- let semis = t * spread_semitones;
294
- let rate = 2f32.powf(semis / 12.0);
295
-
296
- // Resample the entire segment to the same duration using nearest approach with rate
297
- let processed = resample_segment_nearest(&seg, channels, rate, rate);
298
-
299
- // place the processed slice starting at fractional positions across original segment
300
- let offset_frames =
301
- ((t * frames as f32).round() as usize).min(frames.saturating_sub(1));
302
- let offset_samples = offset_frames.saturating_mul(channels);
303
-
304
- // mix into engine buffer
305
- for i in 0..processed.len() {
306
- let dst_idx = *start_sample + offset_samples + i;
307
- if dst_idx >= _engine.buffer.len() {
308
- break;
309
- }
310
- // simple additive mix and clamp
311
- let sum = (_engine.buffer[dst_idx] as i32) + (processed[i] as i32);
312
- _engine.buffer[dst_idx] = sum.clamp(i16::MIN as i32, i16::MAX as i32) as i16;
313
- }
314
- }
315
- }
316
- } else {
317
- let logger = Logger::new();
318
- logger.log_message(
319
- LogLevel::Warning,
320
- "Arp effect requested but no recent notes found for target",
321
- );
322
- }
323
- }
@@ -1,3 +0,0 @@
1
- pub mod chord;
2
- pub mod effects;
3
- pub mod note;
@@ -1,371 +0,0 @@
1
- use crate::core::{audio::engine::AudioEngine, plugin::runner::WasmPluginRunner};
2
- use devalang_types::Value;
3
- use devalang_utils::logger::{LogLevel, Logger};
4
- use std::collections::HashMap;
5
-
6
- pub fn interprete_note_method(
7
- args: &Vec<devalang_types::Value>,
8
- target: &str,
9
- audio_engine: &mut AudioEngine,
10
- variable_table: &devalang_types::VariableTable,
11
- global_store: &crate::core::store::global::GlobalStore,
12
- waveform_str: &str,
13
- synth_params: &HashMap<String, devalang_types::Value>,
14
- amp: f32,
15
- base_bpm: f32,
16
- base_duration: f32,
17
- max_end_time: &mut f32,
18
- mut cursor_time: Option<&mut f32>,
19
- cursor_copy: f32,
20
- update_cursor: bool,
21
- ) -> (f32, f32) {
22
- let filtered_args: Vec<_> = args
23
- .iter()
24
- .filter(|arg| !matches!(arg, Value::Unknown))
25
- .collect();
26
-
27
- let Some(Value::Identifier(note_name)) = filtered_args.first().map(|v| (*v).clone()) else {
28
- println!(
29
- "❌ Invalid or missing argument for 'note' method on '{}'.",
30
- target
31
- );
32
- return (*max_end_time, cursor_copy);
33
- };
34
-
35
- let mut note_params = HashMap::new();
36
- if let Some(arg1) = filtered_args.get(1) {
37
- if let Value::Map(map) = (*arg1).clone() {
38
- for (key, value) in map {
39
- note_params.insert(key, value);
40
- }
41
- }
42
- }
43
-
44
- // Note parameters and calculations
45
- let amp_note = extract_f32(&note_params, "amp", base_bpm).unwrap_or(amp);
46
- let duration_ms =
47
- extract_f32(&note_params, "duration", base_bpm).unwrap_or(base_duration * 1000.0);
48
-
49
- let duration_secs = duration_ms / 1000.0;
50
- let final_freq = note_to_freq(&note_name);
51
- let start_time = cursor_copy;
52
- let end_time = start_time + duration_secs;
53
-
54
- // Fetch automation map if present:
55
- // - Global (per-synth): key "<target>__automation" => map with key "params"
56
- // - Per-note: note parameter "automate" => map
57
- let auto_key = format!("{}__automation", target);
58
- let synth_automation = match variable_table.get(&auto_key) {
59
- Some(Value::Map(map)) => match map.get("params") {
60
- Some(Value::Map(p)) => Some(p.clone()),
61
- _ => None,
62
- },
63
- _ => None,
64
- };
65
-
66
- let note_automation = match note_params.get("automate") {
67
- Some(Value::Map(m)) => Some(m.clone()),
68
- _ => None,
69
- };
70
-
71
- // Merge: per-note overrides synth automation per key (volume/pan/pitch)
72
- let automation = match (synth_automation, note_automation) {
73
- (Some(mut a), Some(n)) => {
74
- for (k, v) in n {
75
- a.insert(k, v);
76
- }
77
- Some(a)
78
- }
79
- (None, Some(n)) => Some(n),
80
- (Some(a), None) => Some(a),
81
- _ => None,
82
- };
83
-
84
- // If waveform references a plugin alias (e.g., alias.synth), use the WASM plugin runner
85
- if waveform_str.contains('.') && waveform_str.ends_with(".synth") {
86
- let alias = waveform_str.split('.').next().unwrap_or("");
87
- if let Some(Value::String(uri)) = variable_table.get(alias) {
88
- if let Some(id) = uri.strip_prefix("devalang://plugin/") {
89
- let mut parts = id.split('/');
90
- let author = parts.next().unwrap_or("");
91
- let name = parts.next().unwrap_or("");
92
- let key = format!("{}:{}", author, name);
93
- if let Some((info, wasm_bytes)) = global_store.plugins.get(&key) {
94
- // Prepare buffer (stereo f32)
95
- let sample_rate = 44100.0_f32;
96
- let total_samples = ((duration_ms / 1000.0) * sample_rate) as usize;
97
- let channels = 2usize;
98
- let start_index = ((start_time * sample_rate) as usize) * channels;
99
- let required_len = start_index + total_samples * channels;
100
- if audio_engine.buffer.len() < required_len {
101
- audio_engine.buffer.resize(required_len, 0);
102
- }
103
- let mut fbuf = vec![0.0f32; total_samples * channels];
104
- let runner = WasmPluginRunner::new();
105
- let mut params_num: std::collections::HashMap<String, f32> =
106
- std::collections::HashMap::new();
107
- let mut params_str: std::collections::HashMap<String, String> =
108
- std::collections::HashMap::new();
109
- for (k, v) in synth_params.iter() {
110
- match v {
111
- Value::Number(n) => {
112
- params_num.insert(k.clone(), *n);
113
- }
114
- Value::String(s) => {
115
- params_str.insert(k.clone(), s.clone());
116
- }
117
- Value::Identifier(s) => {
118
- params_str.insert(k.clone(), s.clone());
119
- }
120
- _ => {}
121
- }
122
- }
123
-
124
- // collect exported names to pass to the runner (preference list)
125
- let exported_names_vec: Vec<String> =
126
- info.exports.iter().map(|e| e.name.clone()).collect();
127
-
128
- // Debug log: exported names and synth param keys
129
- {
130
- let logger = devalang_utils::logger::Logger::new();
131
- logger.log_message(
132
- devalang_utils::logger::LogLevel::Debug,
133
- &format!(
134
- "Calling plugin runner for '{}' with {} exported names and {} synth params",
135
- key,
136
- exported_names_vec.len(),
137
- synth_params.len()
138
- )
139
- );
140
- }
141
-
142
- let _ = runner.render_note_with_params_in_place(
143
- wasm_bytes,
144
- &mut fbuf,
145
- None,
146
- final_freq,
147
- amp_note,
148
- duration_ms as i32,
149
- 44100,
150
- 2,
151
- &params_num,
152
- Some(&params_str),
153
- Some(&exported_names_vec),
154
- );
155
-
156
- for (i, sample) in fbuf.iter().enumerate().take(total_samples * channels) {
157
- let s = (sample.clamp(-1.0, 1.0) * (i16::MAX as f32)) as i16;
158
- let idx = start_index + i;
159
- audio_engine.buffer[idx] = audio_engine.buffer[idx].saturating_add(s);
160
- }
161
- } else {
162
- let logger = Logger::new();
163
- logger.log_message(
164
- LogLevel::Warning,
165
- &format!(
166
- "Plugin bytes not found for key '{}' (alias '{}').",
167
- key, alias
168
- ),
169
- );
170
- }
171
- } else {
172
- let logger = Logger::new();
173
- logger.log_message(
174
- LogLevel::Warning,
175
- &format!("Invalid plugin URI in alias '{}': {}", alias, uri),
176
- );
177
- }
178
- } else {
179
- let logger = Logger::new();
180
- logger.log_message(
181
- LogLevel::Warning,
182
- &format!("Plugin alias '{}' not found in variable table.", alias),
183
- );
184
- }
185
- } else {
186
- // Allow types to adjust per-note scheduling/params
187
- let start_ms = start_time * 1000.0;
188
- let mut final_amp = amp_note;
189
- let mut final_note_params = note_params.clone();
190
-
191
- let mut handled = false;
192
- if let Some(tval) = synth_params.get("type") {
193
- let tname = match tval {
194
- Value::String(s) => s.as_str(),
195
- Value::Identifier(s) => s.as_str(),
196
- _ => "",
197
- };
198
- match tname {
199
- "arp" => {
200
- // compute a step (ms) from synth params (rate/step). compute_arp_step
201
- // will interpret `rate` as number of notes across the provided duration
202
- let step_ms =
203
- crate::core::audio::interpreter::statements::arrow_call::types::arp::compute_arp_step(
204
- duration_ms,
205
- 1,
206
- &synth_params
207
- );
208
- let steps = if step_ms > 0.0 {
209
- ((duration_ms / step_ms).ceil() as usize).max(1)
210
- } else {
211
- 1usize
212
- };
213
-
214
- // For each arp step, call prepare_note to get per-step params and schedule it
215
- for idx in 0..steps {
216
- let (start_abs_ms, freq_step, amp_out, params_out) =
217
- crate::core::audio::interpreter::statements::arrow_call::types::arp::prepare_note(
218
- &note_name,
219
- idx,
220
- steps,
221
- start_ms,
222
- duration_ms,
223
- amp_note,
224
- &synth_params,
225
- &final_note_params,
226
- &automation
227
- );
228
-
229
- // sub-note duration: default to step_ms so arp steps are audible and sequenced
230
- let sub_duration_ms = if step_ms > 0.0 { step_ms } else { duration_ms };
231
-
232
- let _ranges = audio_engine.insert_note(
233
- Some(target.to_string()),
234
- waveform_str.to_string(),
235
- freq_step,
236
- amp_out,
237
- start_abs_ms,
238
- sub_duration_ms,
239
- synth_params.clone(),
240
- params_out.clone(),
241
- automation.clone(),
242
- );
243
- // Apply per-note effects if present in synth_params or note params
244
- if let Some(ev) = params_out.get("effects") {
245
- // for now expect effects as array of maps or identifiers
246
- match ev {
247
- Value::Array(arr) => {
248
- for eff in arr.iter() {
249
- if let Value::Map(_m) = eff {
250
- // each map may have single key -> value
251
- }
252
- }
253
- }
254
- _ => {}
255
- }
256
- }
257
- }
258
-
259
- // mark handled to avoid the unconditional insert below
260
- handled = true;
261
- }
262
- "pluck" => {
263
- let (_s, _f, amp_out, params_out) =
264
- crate::core::audio::interpreter::statements::arrow_call::types::pluck::prepare_note(
265
- &note_name,
266
- 0,
267
- 1,
268
- start_ms,
269
- duration_ms,
270
- amp_note,
271
- &synth_params,
272
- &final_note_params,
273
- &automation
274
- );
275
- final_amp = amp_out;
276
- final_note_params = params_out;
277
- }
278
- "pad" => {
279
- let (_s, _f, amp_out, params_out) =
280
- crate::core::audio::interpreter::statements::arrow_call::types::pad::prepare_note(
281
- &note_name,
282
- 0,
283
- 1,
284
- start_ms,
285
- duration_ms,
286
- amp_note,
287
- &synth_params,
288
- &final_note_params,
289
- &automation
290
- );
291
- final_amp = amp_out;
292
- final_note_params = params_out;
293
- }
294
- _ => {}
295
- }
296
- }
297
-
298
- if !handled {
299
- let ranges = audio_engine.insert_note(
300
- Some(target.to_string()),
301
- waveform_str.to_string(),
302
- final_freq,
303
- final_amp,
304
- start_ms,
305
- duration_ms,
306
- synth_params.clone(),
307
- final_note_params.clone(),
308
- automation.clone(),
309
- );
310
- // apply per-note effects specified in final_note_params
311
- if let Some(Value::Map(eff_map)) = final_note_params.get("effects") {
312
- // delegate to effects module per range
313
- for (_start, _len) in ranges.iter() {
314
- // for simplicity apply using engine buffer ranges via effects module
315
- crate::core::audio::interpreter::statements::arrow_call::methods::effects::apply_effect_chain(
316
- "echo",
317
- &vec![Value::Map(eff_map.clone())],
318
- target,
319
- audio_engine,
320
- variable_table
321
- );
322
- }
323
- }
324
- }
325
- }
326
-
327
- *max_end_time = (*max_end_time).max(end_time);
328
-
329
- if update_cursor {
330
- if let Some(c) = cursor_time.as_mut() {
331
- **c = end_time;
332
- }
333
- }
334
-
335
- return (*max_end_time, end_time);
336
- }
337
-
338
- fn extract_f32(map: &HashMap<String, Value>, key: &str, base_bpm: f32) -> Option<f32> {
339
- map.get(key).and_then(|v| match v {
340
- Value::Number(n) => Some(*n),
341
- Value::Beat(beat_str) => {
342
- let parts: Vec<&str> = beat_str.split('/').collect();
343
- if parts.len() == 2 {
344
- let numerator = parts[0].parse::<f32>().ok()?;
345
- let denominator = parts[1].parse::<f32>().ok()?;
346
-
347
- Some((numerator / denominator) * ((60.0 / base_bpm) * 1000.0))
348
- } else {
349
- None
350
- }
351
- }
352
- _ => None,
353
- })
354
- }
355
-
356
- fn note_to_freq(note: &str) -> f32 {
357
- let notes = [
358
- "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
359
- ];
360
-
361
- if note.len() < 2 || note.len() > 3 {
362
- return 440.0;
363
- }
364
-
365
- let (name, octave_str) = note.split_at(note.len() - 1);
366
- let semitone = notes.iter().position(|&n| n == name).unwrap_or(9) as i32;
367
- let octave = octave_str.parse::<i32>().unwrap_or(4);
368
- let midi_note = (octave + 1) * 12 + semitone;
369
-
370
- 440.0 * (2.0_f32).powf(((midi_note as f32) - 69.0) / 12.0)
371
- }
@@ -1,3 +0,0 @@
1
- pub mod interprete;
2
- pub mod methods;
3
- pub mod types;