// ZPWR-FX — DOCS

GitHub

>_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

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-core3346 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 via juce::MPEInstrument and 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:

ModuleParamsNotes
GainGain, Bias
MixerIn 1, In 2, Mod Amt, Offsetsums all three inputs + DC
FilterCutoff, Reso, Mode (LP/HP/BP), Mod (oct), Drive, MixMod input sweeps cutoff
DelayTime, Feedback, Mod, Damp, Mixdamped feedback, time-mod
LFORate, Shape (sin/tri/saw/pulse), Depth, Phase, Bias, Widthcontrol source
DriveDrive, Output, Bias, Tone, Mix, Type (tanh/fold/clip)
ExprP0..P5 + codeuser-written per-sample algorithm
EnvelopeAttack, Release, Gainfollower → control
LadderCutoff, Reso, Mod, DriveMoog 4-pole resonant low-pass
CombFreq, Feedback, Damp, Mixtuned 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, and tap(d) — the block's own output d samples 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.