memlnaut-nisps/playground/faust/eoc-delay.json
monkey-w1n5t0n afff406d92 feat(playground): add Modular audio mode with shared mod pool
New "Modular" engine in a-immersive with three hot-swappable Faust
sub-engines (subtractive/additive/fm) sharing a common modulation pool:
16 ADSR slots + 32 LFO slots (single-knob sine->tri->square->saw
wavemorph) routed through a 48-source x 10-destination matrix per
engine. Per-connection scalar amounts in [-1, 1], summed at each
destination. Default MLP output count is 512 (32 mod-source params +
480 matrix cells); model reinits on sub-engine swap, count change, or
engine-param exposure toggle.

Faust layer:
- mod-pool.lib: shared ADSR/LFO/source-bus library
- gen-modular-dsp.py: byte-reproducible generator (source of truth)
- modular-subtractive: faithful Minimoog (3 osc, ladder filter, no envs)
- modular-additive: 64-partial, spectral shape + formants, no envs/LFOs
- modular-fm: 4-op matrix + self-feedback, no envs
- All three share d08=amp, d09=pan conventions
- MODULAR_DESTINATIONS.md: authoritative destination table

JS layer:
- ModularEngine: self-contained SynthEngine with getState/setState,
  setSubEngine, setModSourceCount, setExposeEngineParam
- modular-ui: drawer with sub-engine toggle, ADSR/LFO count steppers,
  per-slot enable switches, matrix grid editor (tap-cycle, long-press
  precise, right-click menu, negative amounts), preset overlay
- modular-presets: 6 named presets (Slow pad, Plucky bass, Crystal,
  DX bell, Morphing drone + default)
- a-app.js: Modular mode registered, paramMeta:change -> resizeMLP,
  modular DSP state persisted under modularDspState, window.__nisps
  debug hooks for programmatic control

Tests: tests/e2e/modular-mode.spec.js (11 Playwright tests, all passing
including DSP state survives reload, sub-engine swap keeps paramCount,
preset apply verification).

Also fixes a pre-existing build.sh bug where the -e flag caused faust
to overwrite .wasm outputs with expanded DSP source text, leaving
additive/fm-matrix/eoc-* committed as invalid WebAssembly. Rebuilt all
affected engines with the corrected script. Added an early-message
buffer to faust-worklet-processor.js so setParam calls arriving before
wasm instantiation are queued rather than dropped (needed when the user
configures modular state before clicking Start Audio).
2026-04-11 07:34:41 +02:00

1 line
No EOL
8.7 KiB
JSON

{"name": "eoc-delay","filename": "eoc-delay.dsp","version": "2.79.3","compile_options": "-lang wasm -ct 1 -cn eoc_delay -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0","library_list": ["/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/stdfaust.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/maths.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/platform.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/basics.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/delays.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/filters.lib"],"include_pathnames": ["/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust","/usr/local/share/faust","/usr/share/faust",".","/home/w1n5t0n/src/MEMLNaut-NISPS/playground/faust"],"size": 1048656,"code": "Ly8gZW9jLWRlbGF5LmRzcCDigJQgU3RlcmVvIGRlbGF5IGVmZmVjdCBmb3IgdGhlIEVPQyByYWNrLgovLwovLyBQYXJhbWV0ZXJzICg3KToKLy8gICB0aW1lICAgICAgWzI1MG1zLCAxLTIwMDBtc10gICBkZWxheSB0aW1lIChtcykgd2hlbiBzeW5jPTAKLy8gICBmZWVkYmFjayAgWzAuMywgIDAtMC45NV0gICAgICBmZWVkYmFjayBhbW91bnQKLy8gICBscF9jdXRvZmYgWzgwMDAsIDUwMC0yMDAwMF0gICBMUCBmaWx0ZXIgY3V0b2ZmIG9uIGZlZWRiYWNrIHBhdGggKEh6KQovLyAgIHBpbmdfcG9uZyBbMC4wLCAgMC0xXSAgICAgICAgIDA9bm9ybWFsIHN0ZXJlbywgMT1mdWxsIHBpbmctcG9uZyBMPC0+UgovLyAgIHNwcmVhZCAgICBbMC41LCAgMC0xXSAgICAgICAgIHN0ZXJlbyB3aWR0aCBvZiBkZWxheSB0YWlscwovLyAgIHN5bmMgICAgICBbMF0gICAgICAgICAgICAgICAgIG5lbnRyeTogMD1mcmVlLCAxPWhhbGYsIDI9cXVhcnRlciwgMz1laWdodGggKDEyMGJwbSkKLy8gICBtaXggICAgICAgWzAuMywgIDAtMV0gICAgICAgICBkcnkvd2V0IG1peAoKaW1wb3J0KCJzdGRmYXVzdC5saWIiKTsKCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBVSQovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCnRpbWUgICAgICA9IGhzbGlkZXIoInRpbWVbdW5pdDptc10iLCAgICAgIDI1MCwgMSwgICAyMDAwLCAgMC4xKTsKZmVlZGJhY2sgID0gaHNsaWRlcigiZmVlZGJhY2siLCAgICAgICAgICAgMC4zLCAwLCAgIDAuOTUsICAwLjAwMSk7CmxwX2N1dG9mZiA9IGhzbGlkZXIoImxwX2N1dG9mZlt1bml0Okh6XSIsIDgwMDAsIDUwMCwgMjAwMDAsIDEpOwpwaW5nX3BvbmcgPSBoc2xpZGVyKCJwaW5nX3BvbmciLCAgICAgICAgICAwLjAsIDAsICAgMSwgICAgIDAuMDAxKTsKc3ByZWFkICAgID0gaHNsaWRlcigic3ByZWFkIiwgICAgICAgICAgICAgMC41LCAwLCAgIDEsICAgICAwLjAwMSk7CnN5bmMgICAgICA9IG5lbnRyeSgic3luYyIsICAgICAgICAgICAgICAgIDAsICAgMCwgICAzLCAgICAgMSk7Cm1peCAgICAgICA9IGhzbGlkZXIoIm1peCIsICAgICAgICAgICAgICAgIDAuMywgMCwgICAxLCAgICAgMC4wMDEpOwoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vIERlcml2ZWQgZGVsYXkgdGltZTogZnJlZSBvciB0ZW1wby1zeW5jZWQgYXQgMTIwYnBtCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYnBtID0gMTIwLjA7CmJlYXRfbXMgPSA2MDAwMC4wIC8gYnBtOwoKc3luY190aW1lX21zID0KICAgIGJhLmlmKHN5bmMgPCAwLjUsIHRpbWUsCiAgICBiYS5pZihzeW5jIDwgMS41LCBiZWF0X21zICogMi4wLAogICAgYmEuaWYoc3luYyA8IDIuNSwgYmVhdF9tcywKICAgICAgICAgICAgICAgICAgICAgIGJlYXRfbXMgKiAwLjUpKSk7CgovLyBGaXhlZCBtYXggZGVsYXk6IDk2MDAwIHNhbXBsZXMgKDFzIGF0IDk2a0h6LCBjb3ZlcnMgYWxsIHRlbXBvcyBmb3IgZWlnaHRoIG5vdGVzIGF0IDMwYnBtKykKbWF4X2RlbGF5X3NhbXAgPSA5NjAwMDsKCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBTdGVyZW8gcGluZy1wb25nIGRlbGF5LgovLyBVc2VzIGYgfiAoXywgXykgcGF0dGVybiBmb3Igc3RlcmVvIGZlZWRiYWNrIGxvb3AuCi8vIGRlLmRlbGF5IHVzZWQgZm9yIHZhcmlhYmxlIGRlbGF5IChubyBMUCBvbiBmZWVkYmFjayBwYXRoIGluc2lkZSB0aGUgbG9vcCDigJQKLy8gTFAgaXMgYXBwbGllZCB0byB0aGUgd2hvbGUgd2V0IHNpZ25hbCBmb3IgZWZmaWNpZW5jeSkuCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKZFNhbXAgPSBpbnQoc3luY190aW1lX21zICogZmxvYXQobWEuU1IpIC8gMTAwMC4wKTsKCmRlbGF5Q29yZShpbkwsIGluUiwgZmJMLCBmYlIpID0gd2V0TCwgd2V0Ugp3aXRoIHsKICAgIHBwICA9IHBpbmdfcG9uZzsKICAgIGZiICA9IGZlZWRiYWNrOwogICAgbWl4TCA9IGluTCArIChmYkwgKiAoMS4wIC0gcHApICsgZmJSICogcHApICogZmI7CiAgICBtaXhSID0gaW5SICsgKGZiUiAqICgxLjAgLSBwcCkgKyBmYkwgKiBwcCkgKiBmYjsKICAgIHdldEwgPSBkZS5kZWxheShtYXhfZGVsYXlfc2FtcCwgZFNhbXAsIG1peEwpOwogICAgd2V0UiA9IGRlLmRlbGF5KG1heF9kZWxheV9zYW1wLCBkU2FtcCwgbWl4Uik7Cn07CgpzdGVyZW9EZWxheSA9IChfLCBfKSA6IGRlbGF5Q29yZSB+IChfLCBfKTsKCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBQb3N0LWRlbGF5IExQIGZpbHRlciAodG9uZSBzaGFwaW5nIG9uIHRoZSBmZWVkYmFjayB0YWlsKQovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmRlbGF5TFAoeCkgPSBmaS5sb3dwYXNzKDEsIGxwX2N1dG9mZiwgeCk7CgovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gTWlkLXNpZGUgc3RlcmVvIHNwcmVhZAovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCm1zU3ByZWFkKGluTCwgaW5SKSA9IG91dEwsIG91dFIKd2l0aCB7CiAgICB3ICAgID0gc3ByZWFkOwogICAgbWlkICA9IChpbkwgKyBpblIpICogMC41OwogICAgc2lkZSA9IChpbkwgLSBpblIpICogMC41OwogICAgb3V0TCA9IG1pZCArIHNpZGUgKiB3ICogMi4wOwogICAgb3V0UiA9IG1pZCAtIHNpZGUgKiB3ICogMi4wOwp9OwoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vIE1haW4gcHJvY2VzczogZHJ5L3dldCBtaXgKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgovLyBEZWxheSArIExQICsgc3ByZWFkIG9uIHR3byBzaWduYWxzCmRlbGF5QW5kUHJvY2VzcyhpbkwsIGluUikgPSB3aWRlTCwgd2lkZVIKd2l0aCB7CiAgICB3ZXRMMCA9IHN0ZXJlb0RlbGF5KGluTCwgaW5SKSA6IF8sITsKICAgIHdldFIwID0gc3RlcmVvRGVsYXkoaW5MLCBpblIpIDogISxfOwogICAgd2V0TDEgPSBkZWxheUxQKHdldEwwKTsKICAgIHdldFIxID0gZGVsYXlMUCh3ZXRSMCk7CiAgICB3aWRlTCA9IG1zU3ByZWFkKHdldEwxLCB3ZXRSMSkgOiBfLCE7CiAgICB3aWRlUiA9IG1zU3ByZWFkKHdldEwxLCB3ZXRSMSkgOiAhLF87Cn07Cgpwcm9jZXNzKGluTCwgaW5SKSA9IG91dEwsIG91dFIKd2l0aCB7CiAgICB3aWRlTCA9IGRlbGF5QW5kUHJvY2VzcyhpbkwsIGluUikgOiBfLCE7CiAgICB3aWRlUiA9IGRlbGF5QW5kUHJvY2VzcyhpbkwsIGluUikgOiAhLF87CiAgICBvdXRMID0gaW5MICogKDEuMCAtIG1peCkgKyB3aWRlTCAqIG1peDsKICAgIG91dFIgPSBpblIgKiAoMS4wIC0gbWl4KSArIHdpZGVSICogbWl4Owp9Owo=","inputs": 2,"outputs": 2,"meta": [ { "basics.lib/name": "Faust Basic Element Library" },{ "basics.lib/version": "1.21.0" },{ "compile_options": "-lang wasm -ct 1 -cn eoc_delay -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0" },{ "delays.lib/name": "Faust Delay Library" },{ "delays.lib/version": "1.1.0" },{ "filename": "eoc-delay.dsp" },{ "filters.lib/lowpass0_highpass1": "MIT-style STK-4.3 license" },{ "filters.lib/lowpass0_highpass1:author": "Julius O. Smith III" },{ "filters.lib/lowpass:author": "Julius O. Smith III" },{ "filters.lib/lowpass:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },{ "filters.lib/lowpass:license": "MIT-style STK-4.3 license" },{ "filters.lib/name": "Faust Filters Library" },{ "filters.lib/tf1:author": "Julius O. Smith III" },{ "filters.lib/tf1:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },{ "filters.lib/tf1:license": "MIT-style STK-4.3 license" },{ "filters.lib/tf1s:author": "Julius O. Smith III" },{ "filters.lib/tf1s:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },{ "filters.lib/tf1s:license": "MIT-style STK-4.3 license" },{ "filters.lib/version": "1.7.1" },{ "maths.lib/author": "GRAME" },{ "maths.lib/copyright": "GRAME" },{ "maths.lib/license": "LGPL with exception" },{ "maths.lib/name": "Faust Math Library" },{ "maths.lib/version": "2.8.1" },{ "name": "eoc-delay" },{ "platform.lib/name": "Generic Platform Library" },{ "platform.lib/version": "1.3.0" }],"ui": [ {"type": "vgroup","label": "eoc-delay","items": [ {"type": "hslider","label": "feedback","varname": "fHslider1","shortname": "feedback","address": "/eoc-delay/feedback","index": 4,"init": 0.3,"min": 0,"max": 0.95,"step": 0.001},{"type": "hslider","label": "lp_cutoff","varname": "fHslider3","shortname": "lp_cutoff","address": "/eoc-delay/lp_cutoff","index": 1048624,"meta": [{ "unit": "Hz" }],"init": 8000,"min": 500,"max": 20000,"step": 1},{"type": "hslider","label": "mix","varname": "fHslider5","shortname": "mix","address": "/eoc-delay/mix","index": 1048652,"init": 0.3,"min": 0,"max": 1,"step": 0.001},{"type": "hslider","label": "ping_pong","varname": "fHslider0","shortname": "ping_pong","address": "/eoc-delay/ping_pong","index": 0,"init": 0,"min": 0,"max": 1,"step": 0.001},{"type": "hslider","label": "spread","varname": "fHslider4","shortname": "spread","address": "/eoc-delay/spread","index": 1048648,"init": 0.5,"min": 0,"max": 1,"step": 0.001},{"type": "nentry","label": "sync","varname": "fEntry0","shortname": "sync","address": "/eoc-delay/sync","index": 524300,"init": 0,"min": 0,"max": 3,"step": 1},{"type": "hslider","label": "time","varname": "fHslider2","shortname": "time","address": "/eoc-delay/time","index": 524304,"meta": [{ "unit": "ms" }],"init": 250,"min": 1,"max": 2000,"step": 0.1}]}]}