SUBCHange
A modular synthesizer you build yourself. Every module is a little machine with knobs, input jacks and output jacks; drag a cable from an output to an input and the signal flows. Oscillators make waves, filters shape them, envelopes and LFOs move the knobs for you, the sequencer plays the notes. Pick a starting patch, press Power, then start pulling cables. The + tile in the rack adds modules; the × on a module removes it; tap a jack to unplug its cable.
Rack pick a patch, power up, patch
- Engine
- –
- CPU
- –
- Rate
- –
- Patch
- –
- Resets
- –
About a module
Click a module's name to read what it does. Tap a wired jack to unplug its cable; drag a cable away from an input to move it. The + tile in the rack (or the button above) adds a module; the × in a module's corner removes it.
Signals
Audio swings between -1 and 1. Pitch is in octaves from middle C (1 V/oct, so a sequencer note and a VCO agree). Gates are 0 or 1. CV from an LFO is -1..1, from an envelope 0..1. Any output can go to any input; two cables into one jack add up.
Modules the whole shelf - click one to add it to the rack
Patch (JSON) — edit anything, paste a patch
Modules are { id, type, params }; cables are { from: [module, output], to: [module, input] }. Types: vco lfo noise svf ladder vca adsr mix delay reverb seq keys sh shaper cv out. The patch autosaves in this browser.
How it works the same stack as Pedal Lab
A graph, run 48,000 times a second
The page keeps the patch as plain data: a list of modules with their knob values and a list of cables. When you change it, the patch is compiled into one block of numbers and handed to the engine, which is written in Rust and compiled to WebAssembly. On the audio thread, for every sample, the engine walks the modules in order: it adds up the cables arriving at each input, runs that module's maths, and stores its outputs for the next module to read.
Feedback is allowed
Modules are sorted so a cable normally carries this sample's value. A cable that points backwards (a filter modulating the oscillator that feeds it) reads the previous sample instead: a one-sample delay, which is exactly what a real patch cable does at the speed of light divided by a lot of capacitance.
What is inside the modules
The oscillator's saw and square are polyBLEP band-limited so they don't alias. The Filter is Zavalishin's topology-preserving state-variable filter; the Ladder is four tanh-saturated one-pole stages with the feedback that makes it sing. The envelope is exponential like a capacitor charging. The delay soft-clips its loop; the reverb is Schroeder's four combs and two all-passes, as in Freeverb. Knobs are smoothed over four milliseconds so they never zipper.
Nothing leaves your browser
Patches live in this browser's storage and in the share links you make. The engine is 18 KB of WebAssembly; there is no server side to any of it.
Source: the Rust crate music/hub/wasm-synth and the page under music/hub/public/subchange, with the module catalogue in modules.js as the contract between them. Tests run the same engine in Node against things you can work out by hand: the VCO's pitch, the filters' slopes, the sequencer's timing.