>_ZPWR-FX
Modular patch effects — wire primitive DSP blocks (oscillators, filters, delays, reverbs, dynamics, modulation) into your own algorithm, Eventide-H3000 style, in a cyberpunk WebView UI. The reference below is generated from the live module registry the plugin runs, so it never drifts from the build.
zpwr-fx v0.1.23 · 3346 audio blocks (4218 total across the stack) · 42 factory presets · VST3 / AU / CLAP / Standalone · by MenkeTechnologies
Module Reference
Every patch block with its inputs and parameters, grouped by category. (HTML)
Reference (PDF)
The same reference, paginated for print — built from the same source.
Source
Build instructions, the patch model, and the DSP block implementations.
Overview
The plugin is a patch graph: a dynamic set of DSP blocks (add or delete any number — there is no fixed node count, the practical limit is CPU) wired together by selecting each input's source. The two stereo outputs (Out L/R) are summing buses — drag any number of cables into each and they mix, exactly like a block input. The whole graph runs once per sample frame (mono blocks; stereo only at the In/Out nodes), so feedback and cross-modulation behave like a hardware patch.
INPUTS BLOCKS (add/delete any N) OUTPUTS In L ─┐ ┌─[B1 Filter]─┐ Out L ◀─ B2 In R ├────►│ In/Mod │──►[B2 Delay]──► Out R ◀─ B3 Noise─┘ └─[B3 LFO]────┘ (feedback) SK1..N (soft keys, expandable, automatable, patchable as modulation)
The block palette is the shared audio module pack from zpwr-patch-core — 3346 audio blocks (4218 total across the audio/synth/MIDI stack, every name globally unique). Any block type can be dropped into any node. The full per-block catalog and counts live in zpwr-patch-core/BLOCKS.md, regenerated from the registration sites so they never drift.
Formats & Platforms
- VST3 — cross-platform.
- AU — macOS (Logic, GarageBand).
- CLAP — via clap-juce-extensions.
- Standalone — local dev/test app.
Platforms: macOS (ARM + Intel; the default build is a universal binary) and Linux (x86_64 / aarch64). Windows builds VST3 + CLAP (AU is macOS-only and is dropped automatically).
Patch Model
- Sources an input can read: silence, In L, In R, Noise, the Soft Keys,
MIDI/MPE (Mod Wheel, Aftertouch, Pitch Bend, Velocity, Expression, Breath, Sustain, Note,
and MPE Press/Slide/Bend), or any block's output (
src id = 100 + blockIndex). MPE is parsed viajuce::MPEInstrumentand aggregated to the most recent note. - Each block has three inputs (In 1, In 2, Mod), six params, and one output.
- The graph is topologically sorted each rebuild; cycles (feedback) resolve with a one-sample delay automatically — wire any output back to an earlier input to build feedback patches.
- Any source can fan out to unlimited destinations.
Patching the cables: drag an output jack to an input jack to wire it; drag an input away to disconnect; drop on a different output to rewire. Right-click a cable for its level (per-cable gain) and colour — the cable's brightness tracks its level.
Modules
The block palette is the shared audio module pack registered on the core by
zpc::registerAudioModules (re-exported as zfx::registerAudioModules in
src/dsp/AudioModules.h). It is 3346 audio blocks — including a large
circuit-modeled set (component-level analog emulations: zero-delay-feedback ladders/SVFs, Shockley-diode and
Ebers-Moll clippers, Koren triode/EL34 amp stages, Jiles-Atherton tape, Lambert-W wavefolder, four-diode ring
mod). The authoritative per-block reference — inputs and parameters, grouped by category — is the generated
Module Reference (and PDF).
Blocks are grouped into these categories (jump into the reference):
A few of the building blocks:
| Module | Params | Notes |
|---|---|---|
| Gain | Gain, Bias | |
| Mixer | In 1, In 2, Mod Amt, Offset | sums all three inputs + DC |
| Filter | Cutoff, Reso, Mode (LP/HP/BP), Mod (oct), Drive, Mix | Mod input sweeps cutoff |
| Delay | Time, Feedback, Mod, Damp, Mix | damped feedback, time-mod |
| LFO | Rate, Shape (sin/tri/saw/pulse), Depth, Phase, Bias, Width | control source |
| Drive | Drive, Output, Bias, Tone, Mix, Type (tanh/fold/clip) | |
| Expr | P0..P5 + code | user-written per-sample algorithm |
| Envelope | Attack, Release, Gain | follower → control |
| Ladder | Cutoff, Reso, Mod, Drive | Moog 4-pole resonant low-pass |
| Comb | Freq, Feedback, Damp, Mix | tuned resonator / karplus |
The Expr module: Expr blocks run a user-written per-sample expression compiled by
an in-house RT-safe VM (src/dsp/ScriptEngine.*). It can do things the fixed blocks can't, and it's
edited live in the block's detail panel.
- Vars:
in(In 1),t,sr,p0..p7(p0–p5 = knobs, p6 = In 2, p7 = Mod),s0..s3(persistent state),pi tau e. - Funcs:
sin cos tan tanh … floor frac wrap saw sqr tri min max pow fmod clamp lerp if step noise rand, andtap(d)— the block's own outputdsamples ago (fractional) for combs / karplus / feedback. - Safe by construction: no loops, allocation, or memory access in the hot path; output is sanitized (NaN/Inf → 0); over-limit programs fail to compile.
Example wavefolder: out = sin(in * (1 + p0 * 8) * pi)
Modulation
Mod matrix: every block param has a mod source + depth (detail panel →
MODULATION). Any source — LFO, Envelope, Soft Key, Noise, or another block — modulates the param by
source × depth (in param units). Mod sources are part of the dependency graph, so modulating
a param with a block's output is topologically ordered like any other connection.
Soft Keys & Automation
JUCE's parameter list must be static for host automation, so the host-automatable params are the Soft
Keys + Master In/Out/Bypass + a reserved pool of 96 Auto N params (right-click any block param to
bind it — the Kontakt/Reaktor model — so any module parameter becomes host-automatable / CC-mappable;
32 soft keys + 96 auto params = 128 CC-mappable slots, one per MIDI CC); the patch itself (block types, routing, block params) is plugin state the
UI edits and the plugin persists. The Soft Keys are an expandable pool — a fixed ceiling of 32
host params is created up front, and the +/− controls above the knob row set how
many are active (16 by default). The active count is saved with the plugin state. Soft keys are patchable as
modulation sources — exactly the H3000 model. Editing is lock-free: atomic param writes for live tweaks, an
atomic graph swap on structural edits.
User Interface
A JUCE 8 WebBrowserComponent rendering an embedded cyberpunk UI (cyan/magenta on near-black,
Orbitron + Share Tech Mono, grid + CRT scanlines), self-contained via juce_add_binary_data (no node
build, no external files). The UI is shared with zpwr-synth and zpwr-midi-fx; the tab set:
- Patch — drag an output jack onto an input jack to wire it; an ⚡ EZ WIRE button (auto-wires In L → your blocks → Out L/R), an INIT button (unplug every cable & mod, keep the blocks), 🗑 (blank the whole patch), the Stereo / 🔒 LOCK toggles, the soft-key strip, the sources / blocks / outputs grid with SVG cables, and a detail panel for the selected block. Cables glow with each source block's live signal level.
- Synth — a fixed-layout panel showing every module's knobs in a grid, no cables.
- Perform — macros + XY pads only, no patching.
- Clip — draw a MIDI pattern and play it (with key/scale, key-trigger).
- Mod Matrix — every modulation connection in one list.
- Mixer — per-layer channel strips (gain / pan / mute / solo) with sends to the aux FX buses, the aux returns, and the master strip, with peak + LUFS metering.
- Browse — search, save, tag and load patches; filter by bank, type, style, character.
- Settings — Master In/Out + Bypass, Auto Gain Stage + target, the brickwall limiter, MIDI Program Change / Bank Select toggles, scale-key/scale quantize, UI scale, interface toggles.
- About — version + engine info.
Auto gain staging: two Settings (both on by default) keep inter-block levels sane per block. Auto Gain Stage rides levels with a fast-attack / slow-release peak follower that pulls each block down toward the Auto-Gain Target ceiling. Soft Clip is the guarantee: an instant tanh bound at the same ceiling on every block output, catching transients the AGC's ~2 ms attack and downstream cable gains let slip. Both are per block; turn either off for raw gain. Distinct from the master Brickwall Limiter, a single hard ceiling on the final summed output.
Perform
Perform tab — a play-the-patch surface that drives only host-automatable params, so it works editor-closed and records as automation:
- Preset Morph — a 4-corner XY pad (A/B/C/D) that bilinearly interpolates between four
captured patches; X/Y are reserved host params (
morphX/morphY), and 🎲 assigns a random preset to all four corners. - Orb — a radial pad where the puck's angle selects a scene and distance sets its intensity; 🎲 rolls a new random scene set, ⏺ records the puck's motion, and ▶ loops the recorded motion back through the host-automatable params.
- XY macro pads — each with a per-pad HOLD / SPRING toggle.
- Macro knobs — the soft knobs surfaced as plain 0..1 APVTS params.
- Scenes — snapshot slots: click to recall, right-click to clear.
- Controls band — global dice/randomise, arp (mode / rate / latch), and scale + key quantize plus a Chord that stacks extra intervals on each key played.
Stereo mode + Stereo Lock: Stereo (off by default) mirrors the patch graph to the right channel, so blocks process L/R independently. 🔒 Lock keeps the mirrored (clone) blocks tracking the left channel — bidirectional and offset-preserving: dragging a left knob moves its clone, and dragging a clone moves the left, each by the same delta, so the L/R offset is preserved. Both states persist in plugin state.
MIDI Program Change / Bank Select (both default on): an incoming PC selects the matching
program (preset); CC0 (MSB) / CC32 (LSB) are captured and combined with the next PC
(bank × 128 + program) for banked preset addressing.
Output recorder: an in-plugin recorder (zpc::WavRecorder) captures the master
output to a 32-bit float WAV under ~/Music/zpwr/<product>_<timestamp>.wav.
It is RT-safe — recorder.pushBlock() runs at the end of processBlock, a no-op until
armed — and the editor drives it through the startRecord / stopRecord native functions.
startRecord returns the path it opened.
Master-insert plugin host: the plugin can host one external VST3 / AU plugin on
its master insert (zpc::PluginInsert + zpc::PluginHost;
JUCE_PLUGINHOST_VST3 / JUCE_PLUGINHOST_AU are enabled in CMake). The hosted plugin
processes in processBlock after the stereo widener, so it sits on the final master path. Editor
native functions drive it: pluginScan, pluginList, pluginLoad,
pluginClear, pluginCurrent, and pluginEditorOpen (a floating
zpc::PluginInsertWindow for the hosted editor). The hosted plugin's id and its own serialized state
save/restore with the host's get/setStateInformation.
Presets
- Factory (in code,
ZpwrFxProcessor::factoryNames()): 42 presets, exposed as host programs for MIDI Program Change — e.g. DL Stereo Slap, FL Filter Sweep, FL Comb Resonator, FL Auto Wah, FX Feedback Howl, DS Wavefolder, RV Iceverb Cathedral. - User patches save as JSON (
patch+ soft-key values) under<userAppData>/zpwr-fx/Presets/*.zfxpatch(e.g.~/Library/zpwr-fx/Presets). - The full plugin/host state (patch + all params) round-trips through JUCE's
get/setStateInformation.