memlnaut-nisps/playground/faust/modular-fm.json

1 line
258 KiB
JSON
Raw Normal View History

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
{"name": "modular-fm","filename": "modular-fm.dsp","version": "2.79.3","compile_options": "-lang wasm -ct 1 -cn modular_fm -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","/home/w1n5t0n/src/MEMLNaut-NISPS/playground/faust/mod-pool.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/oscillators.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/envelopes.lib","/nix/store/yjqpc2a6b2m08zwwrgsdlqsi40m5wnpp-faust-2.79.3/share/faust/signals.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","/home/w1n5t0n/src/MEMLNaut-NISPS/playground/faust"],"size": 265316,"code": "Ly8gbW9kdWxhci1mbS5kc3Ag4oCUIDQtb3BlcmF0b3IgRk0gdm9pY2UgZm9yIHRoZSAiTW9kdWxhciIgbW9kZS4KLy8KLy8gQVVUTy1HRU5FUkFURUQgYnkgZ2VuLW1vZHVsYXItZHNwLnB5LiBETyBOT1QgRURJVCBCWSBIQU5ELgovLyBSZWdlbmVyYXRlIHdpdGg6Ci8vICAgICBjZCBwbGF5Z3JvdW5kL2ZhdXN0ICYmIHB5dGhvbjMgZ2VuLW1vZHVsYXItZHNwLnB5Ci8vCi8vIEF1ZGlvIHBhdGg6IDQgb3BzIHdpdGggMTItY2VsbCBjcm9zcy1tb2QgbWF0cml4IGFuZCBwZXItb3AgZmVlZGJhY2suCi8vIEFsbCBlbnZlbG9wZXMgYW5kIExGT3MgY29tZSBmcm9tIG1vZC1wb29sLmxpYiB2aWEgYSA0OC1zb3VyY2Ugw5cgMTAtZGVzdAovLyBtb2R1bGF0aW9uIG1hdHJpeC4gTm8gaW50ZXJuYWwgZW52cy9MRk9zLgovLwovLyBNb2R1bGF0aW9uIGRlc3RpbmF0aW9ucyAoMTApOgovLyAgICAgMCBwaXRjaCAgICAgICAgICAgICBzZW1pdG9uZXMgYWRkZWQgdG8gdGhlIGJhc2UgZnJlcXVlbmN5Ci8vICAgICAxIG9wMV9sZXZlbCAgICAgICAgIGFkZGVkIHRvIG9wMSBsZXZlbCBrbm9iCi8vICAgICAyIG9wMl9sZXZlbCAgICAgICAgIGFkZGVkIHRvIG9wMiBsZXZlbCBrbm9iCi8vICAgICAzIG9wM19sZXZlbCAgICAgICAgIGFkZGVkIHRvIG9wMyBsZXZlbCBrbm9iCi8vICAgICA0IG9wNF9sZXZlbCAgICAgICAgIGFkZGVkIHRvIG9wNCBsZXZlbCBrbm9iCi8vICAgICA1IGNyb3NzX21vZF9nbG9iYWwgIGdsb2JhbCBGTSBkZXB0aCBtdWx0aXBsaWVyIG9uIGFsbCAxMiBjcm9zcy1tb2QgY2VsbHMKLy8gICAgIDYgZmVlZGJhY2tfZ2xvYmFsICAgZ2xvYmFsIGZlZWRiYWNrIG11bHRpcGxpZXIgb24gYWxsIDQgc2VsZi1mZWVkYmFjayBjZWxscwovLyAgICAgNyBnbG9iYWxfcmF0aW8gICAgICBhZGRpdGl2ZSBzY2FsZSBmYWN0b3Igb24gYWxsIDQgb3BlcmF0b3IgcmF0aW9zCi8vICAgICA4IGFtcCAgICAgICAgICAgICAgIG1hc3RlciBhbXBsaXR1ZGUgZGVzdCAocm91dGUgYW4gQURTUiBoZXJlIGZvciBhIFZDQSBlbnYpCi8vICAgICA5IHBhbiAgICAgICAgICAgICAgIHN0ZXJlbyBiYWxhbmNlCi8vCi8vIEhpZGRlbiBjb250cm9scyAoZHJpdmVuIGJ5IG5vdGVPbi9ub3RlT2ZmLCBub3QgYnkgdGhlIE1MIGVuZ2luZSk6Ci8vICAgICBmcmVxLCBnYXRlLCBfdmVsCi8vCi8vIEJ1aWxkOgovLyAgICAgY2QgcGxheWdyb3VuZC9mYXVzdCAmJiAuL2J1aWxkLnNoCi8vCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKaW1wb3J0KCJzdGRmYXVzdC5saWIiKTsKbXAgPSBsaWJyYXJ5KCJtb2QtcG9vbC5saWIiKTsKCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBIaWRkZW4gY29udHJvbHMKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmZyZXEgPSBoc2xpZGVyKCIwX0hpZGRlbi9mcmVxW2hpZGRlbjoxXVt1bml0Okh6XSIsIDIyMCwgMjAsIDQwMDAsIDAuMDEpOwpnYXRlID0gYnV0dG9uKCIwX0hpZGRlbi9nYXRlW2hpZGRlbjoxXSIpOwp2ZWwgID0gaHNsaWRlcigiMF9IaWRkZW4vX3ZlbFtoaWRkZW46MV0iLCAwLjcsIDAuMCwgMS4wLCAwLjAwMSkgOiBzaS5zbW9vOwoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vIEdyb3VwIDEg4oCUIE9wZXJhdG9ycyAocmF0aW8gJiBsZXZlbCBwZXIgb3ApCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpvcDFfcmF0aW8gPSBoc2xpZGVyKCIxX09wZXJhdG9ycy8wMF9vcDFfcmF0aW8iLCAxLjAsIDAuMTI1LCAxNi4wLCAwLjAwMSk7Cm9wMV9sZXZlbCA9IGhzbGlkZXIoIjFfT3BlcmF0b3JzLzAxX29wMV9sZXZlbCIsIDAuOCwgMC4wLCAgIDEuMCwgIDAuMDAxKTsKb3AyX3JhdGlvID0gaHNsaWRlcigiMV9PcGVyYXRvcnMvMDJfb3AyX3JhdGlvIiwgMi4wLCAwLjEyNSwgMTYuMCwgMC4wMDEpOwpvcDJfbGV2ZWwgPSBoc2xpZGVyKC