Faust DSP sources, compiled WASM + JSON descriptors, AudioWorklet processors, and EOCModule subclasses for all three effects. - meml-4b4: 4-band parametric EQ (fi.low_shelf, fi.peak_eq × 2, fi.high_shelf) 10 params: freq/gain per band, Q for the two mid bell bands - meml-cpe: stereo feed-forward compressor (co.compressor_mono × 2) 7 params: threshold, ratio, attack, release, knee, makeup, mix (parallel) - meml-wwc: zita reverb (re.zita_rev1_stereo) with pre-delay and M/S width 8 active params + mod_rate placeholder (zita internal mod not yet exposed) All three DSPs compile cleanly under Faust 2.83.1. moduleFactory in eoc-chain-ui.js now returns real instances for eq/compressor/reverb. |
||
|---|---|---|
| .. | ||
| additive-processor.js | ||
| additive.dsp | ||
| additive.json | ||
| additive.wasm | ||
| build.sh | ||
| eoc-compressor-processor.js | ||
| eoc-compressor.dsp | ||
| eoc-compressor.json | ||
| eoc-compressor.wasm | ||
| eoc-eq-processor.js | ||
| eoc-eq.dsp | ||
| eoc-eq.json | ||
| eoc-eq.wasm | ||
| eoc-reverb-processor.js | ||
| eoc-reverb.dsp | ||
| eoc-reverb.json | ||
| eoc-reverb.wasm | ||
| faust-worklet-processor.js | ||
| fm-matrix-processor.js | ||
| fm-matrix.dsp | ||
| fm-matrix.json | ||
| fm-matrix.wasm | ||
| README.md | ||
playground/faust — Faust DSP Build Pipeline
This directory contains Faust DSP source files and the toolchain for compiling them to WebAssembly for use in the MEMLNaut playground.
Required Tools
| Tool | Version | Purpose |
|---|---|---|
faust |
>= 2.60 | Compiles .dsp → .wasm + .json |
emcc |
>= 3.1.x | Optional — needed only if linking extra C++ code |
emcc is already available at /usr/lib/emscripten/emcc on this system.
faust is not currently installed — use nix-shell -p faust for a one-off
build, or nix profile install nixpkgs#faust to install permanently.
How to Compile
cd playground/faust
./build.sh
This compiles every .dsp file in the directory, producing alongside it:
<name>.wasm— the compiled DSP binary (loaded as an AudioWorkletNode)<name>.json— the Faust UI descriptor (consumed byfaustJsonToParamMeta)<name>.js— JS glue / AudioWorklet wrapper generated by faust
DSP Files
| File | Status | Description |
|---|---|---|
additive.dsp |
Placeholder | 4-harmonic sine bank (2 params). Full engine: meml-pj4 |
fm-matrix.dsp |
Placeholder | 2-op FM synth (4 params). Full engine: meml-wgg |
Output Format — .json Descriptor
Faust's -json flag emits a UI descriptor tree. Example:
{
"name": "additive",
"version": "2.75.7",
"options": "-vec",
"size": "0",
"inputs": "0",
"outputs": "2",
"meta": [...],
"ui": [
{
"type": "vgroup",
"label": "additive",
"items": [
{
"type": "hslider",
"label": "freq",
"address": "/additive/freq",
"meta": [{"unit": "Hz"}],
"init": 220,
"min": 20,
"max": 4000,
"step": 0.1
},
{
"type": "hslider",
"label": "amp",
"address": "/additive/amp",
"init": 0.5,
"min": 0,
"max": 1,
"step": 0.001
}
]
}
]
}
How faustJsonToParamMeta Consumes the JSON
playground/js/synth/faust-param-meta.js exports:
import { faustJsonToParamMeta, loadFaustParamMeta } from './faust-param-meta.js';
// From a pre-parsed object:
const paramMeta = faustJsonToParamMeta(faustJson);
// Or fetch + parse in one step:
const paramMeta = await loadFaustParamMeta('faust/additive.json');
faustJsonToParamMeta recursively walks the ui tree, collects all
hslider / vslider / nentry items, and returns:
[
{ id: 'freq', name: 'freq', min: 20, max: 4000, init: 220, curve: 0.5, group: 'additive' },
{ id: 'amp', name: 'amp', min: 0, max: 1, init: 0.5, curve: 0.5, group: 'additive' },
]
This is the standard paramMeta format used throughout the playground
(SynthEngine.paramMeta, preset system, group drawer, etc.).
FaustEngineBase Loading Pattern
playground/js/synth/faust-engine-base.js provides a base class for any
engine compiled with this pipeline:
import { FaustEngineBase } from './js/synth/faust-engine-base.js';
class AdditiveEngine extends FaustEngineBase {
constructor() {
super({
id: 'additive',
displayName: 'Additive',
wasmUrl: 'faust/additive.wasm',
jsonUrl: 'faust/additive.json',
workletUrl: 'faust/additive-processor.js', // AudioWorklet file
processorName: 'additive-processor', // registerProcessor() name
});
}
}
const engine = new AdditiveEngine();
await engine.init(audioCtx); // fetches JSON + WASM, loads worklet
engine.noteOn(69, 0.8); // A4, velocity 0.8
engine.setParam(0, 0.6); // normalized [0,1] → maps to param range
engine.noteOff(69);
The init() call:
- Fetches
jsonUrl→ callsloadFaustParamMeta()→ populatesengine.paramMeta - Fetches
wasmUrl→ transfers bytes to AudioWorklet - Registers
workletUrlwithaudioCtx.audioWorklet.addModule() - Creates an
AudioWorkletNodeand connects it toaudioCtx.destination - Sends
{ type: 'init', wasmBytes, sampleRate }to the worklet - Waits for the worklet to reply
{ type: 'ready' }(10 s timeout)
AudioWorklet Processor Base
faust-worklet-processor.js (this directory) defines FaustWorkletProcessor,
a base class for concrete engine worklets. It handles:
{ type: 'init', wasmBytes, sampleRate }— calls_initWasm(){ type: 'setParam', index, value }— calls_onSetParam(){ type: 'noteOn', freq, vel }— calls_onNoteOn(){ type: 'noteOff', freq }— calls_onNoteOff()- Replies
{ type: 'ready' }or{ type: 'error', message }to main thread
Each concrete engine processor overrides _initWasm() and _renderBlock().