<div align="center">
A TWIN POLIVOKS-STYLE STEREO FILTER — TWO CHANNELS, ONE SOUL, AND THE DRIFT BETWEEN THEM
◈ DROP 004 · BUILD V003 ◈
ZRGRT
*Independent instrument — a digital implementation of a classic Soviet-chip
stereo filter; unaffiliated with any hardware manufacturer. All audio
synthesized in code, all artwork original.*
</div>
◆ FIELD NOTE — This is a field manual, not a contract. Read *Before You
Begin* to start playing; the rest of the panel explains itself in one
screen under H. Every range named here is the panel's own printed
range, and where the digital twin deliberately departs from the hardware
rule that inspired it, the departure is named.
This manual documents CATCH-22 DROP 004 · build V003, an independent
software instrument for LÖVE 11.5. CATCH-22 is not affiliated with,
endorsed by, or a reproduction of any hardware manufacturer; it is an
original work — a digital implementation of a classic Soviet-chip stereo
filter. No hardware firmware or manual text is reproduced. All audio is
synthesized in code; all artwork and diagrams are original.
The instrument is released under the **MIT License, © 2026 ZRGRT**.
This manual is part of that release.
| you have | do this |
|---|---|
catch-22-x86_64.AppImage | chmod +x it, then run it. One file, nothing to install. |
catch-22-linux.zip | unzip, then ./catch-22-linux/run-linux.sh |
catch-22-windows.zip | unzip, then run-windows.bat (or catch-22.exe) |
catch-22.love | install LÖVE 11.5 from love2d.org, then drag the file onto it |
Platforms. Linux and Windows are supported (the fused builds carry the real-time audio bridge, the filter kernels and the NYDUS daemon). On macOS the audio bridge is not built — the panel runs in the honest NO AUDIO state.
If the window opens and no sound comes. Run from a terminal once and read
the [audio] line: RT active backend=… means the bridge is live;
NO AUDIO - see log names the cause — usually the bridge library missing
next to the game file (use the fused builds).
The unit boots already filtering. The built-in APP drone feeds both
channels, LINK FREQ is on, and a slow LFO breathes FILTER 1's cutoff. Wait
nothing — play something:
1. Drag the big red CUTOFF knobs and listen to the twin filters open.
2. Push RESONANCE past 0.8 and find the self-oscillation point — it
will not be identical on both channels. That difference is the sound.
3. Flip WIRING to SE — the patch cord draws itself and the two
12 dB stages stack into a 24 dB chain.
4. The noise bay: PINK at full LEVEL through a bandpass is a
landscape; sweep it.
One 1600×1034 surface, two bands:
BAND A — the filter band (top, 72%): the hardware arrangement.
| Section | Controls | |||
| IN / SOURCE | SOURCE select (DRONE / NOISE / EXT — APP sources), IN 1, IN 2 | |||
| NOISE | WHITE \ | PINK switch, LEVEL, BALANCE (center-compensated pan into F1/F2) | ||
| FILTER 1 | CUTOFF, RESONANCE, LEVEL, MODE (LP \ | BP \ | HP \ | N), CV IN jack + AMOUNT + LED mirror |
| LINK | FREQ and CV slide switches, WIRING (DU / SE / PA) | |||
| FILTER 2 | mirror of FILTER 1 | |||
| OUT | DRY/WET 1, DRY/WET 2 (per-channel blends), VU L/R, OUT 1, OUT 2 |
BAND B — the app bay (bottom, 28%, marked APP): SCOPE L/R, SPECTRUM,
MISMATCH (seed readouts, deviations, warm-up gauge, NEW TWIN, WARM on/off),
PRESETS (click to load, F2 saves the current state as a user preset).
Two 12 dB multimode state-variable filters in the TPT/ZDF topology, mode
taps LP / BP / HP / NOTCH derived from the same state pair. Key behaviours:
fc = 20 Hz · 2^(10·cv) — 20 Hz to 20.48 kHz.Amplitude is caught by an op-amp-rail state clipper, so the limit cycle
stays level-consistent at every cutoff. Below the knee the filter is
lossless.
~0.5 dB while resonance rises (measured, docs/audits/character.md).
cutoff-dependent crossover bias (0.15 → 0.375 over ~6 octaves below
1.28 kHz) — the low-cutoff "angry" crossover distortion of the original
output stage. Odd-order grit grows with res.
applied mismatch range settles from ±1.2% to the full ±3% over 90 s.
The WARM:ON/OFF button in the MISMATCH bay bypasses the settle for A/B
work.
Real hardware units differ from each other; the two channels of one unit
differ too. CATCH-22 models the channel mismatch as a permanent feature:
±0.02, self-osc threshold ±0.02**.
twins breathe apart over minutes. Maximum observed drift over a 10-minute
run: 0.4% (docs/audits/character.md).
every preset, so a saved patch is reproducible.
difference you hear is the model, not noise (tests/dsptest.lua).
| Position | Wiring |
| DU | dual mono — IN1→F1→OUT1, IN2→F2→OUT2 (two independent paths) |
| SE | series — IN1→F1→OUT1→(cord)→IN2→F2→OUT2; the cord is drawn, and the two stages stack into a 24 dB chain (measured ~21 dB/oct in-region, docs/audits/routing.md) |
| PA | stereo parallel — the default stereo wiring (L→F1, R→F2) |
LINK FREQ: the FILTER 1 CUTOFF knob (and its CV) drives both channels —
a gold cord draws between the cutoffs. LINK CV: channel 1's CV input
drives both channels' cutoffs. With both LINKs off the channels are fully
independent.
0..+10 V ≙ +7 octaves up from 20 Hz (in 0..+10 mode the knob is
parked — the CV owns fc).
post-attenuator value with a peak-hold (0.5 s recovery, ±0.5% at 60 FPS).
(sine / triangle / saw, 0.03–30 Hz, bipolar), envelope follower on the
ext input.
White shaped to unit variance; pink (−3.00 dB/oct measured 40 Hz–10 kHz)
at matched RMS. Noise injects pre-filter at each channel's input
summing node — it filters with everything else — and BALANCE pans the
stream between F1 and F2 (center-compensated).
The SOURCE select chooses the base input: the DRONE (two 3-saw + sub
voices, voice 1 leaning left, voice 2 leaning right), the NOISE
generator itself, or the EXT input (microphone / line via the OS
recording device; gain + soft pad). Sources are app-original so the unit
makes its signature sound before anything is patched in.
Eight factory patches ship in the PRESETS bay: Init Twin (the boot state),
Acid Pluck, Stereo Breathe, 24 dB Bass Chain, Noise Landscape, Notch Radar,
Drone Polish, Drum Bus. Click to load; F2 saves the current panel as a
user preset. The schema is versioned and forward-only; mismatch seeds are
part of the state, so presets are reproducible bit-for-bit.
The MISMATCH bay's CHARACTER row exposes the twin cell's temperament
(the modelled behaviours of the programmable-op-amp filter family).
STARVE is intrinsic: at RES above 0.9 the ring chokes — strangled,
yet it still rings; the amber dot lights while the corner is active, and
the button A/Bs the layer against the clean cell. DRIP sets the
depth of the amplitude-conditional slow instability — push RES high, find
the input level, and the filter "bubbles" like dripping water. Both
layers travel inside presets.
Four responses, one knob per filter. Original diagrams, drawn for this manual.


MONO SINGLE FILTER MODE. Connect a mono signal to IN 1 and take OUT 1 — one 12 dB voice. The second filter works independently on IN 2 / OUT 2.

MONO DUAL FILTER MODE (SERIES, 24 dB). Connect a mono signal to IN 1, patch a cable from OUT 1 to IN 2, take OUT 2. With LINK FREQ on, one cutoff knob and one CV drive both stages — the 24 dB chain. The panel draws the cord for you.

STEREO MODE. Left into IN 1, right into IN 2, out from OUT 1 and OUT 2. Set different modes per channel and enjoy the disagreement.

Clock-less — no transport. Right-click any knob → move a controller to
bind it (toast confirms). ESC ESC (double-tap) is the panic: it clears
the whole map. The map persists across restarts.
The unit participates in the ZRGRT instrument mesh with zero configuration: on boot it announces itself and peers connect automatically. Nothing waits for a click.
A sibling (or an agent peer) may steer the filters over the family bus — the wire parameter
surface: every value is validated and clamped before it touches the engine, unknown ids are
ignored. Ids: fx/wet, fx/level,
fx/cutoff/fx/cutoff1/fx/cutoff2,
fx/res/fx/res1/fx/res2,
fx/mode1|fx/mode2 (0 LP / 1 BP / 2 HP / 3 NOTCH),
fx/topology (0 mono / 1 series / 2 stereo),
fx/dw/fx/dw1/fx/dw2, fx/starve,
fx/drip, fx/source, fx/noise,
fx/linkfreq, fx/linkcv. This is how a LUNAR-24 score breathes
the twin filters in the family sessions — no UI on this side.
Room overlay (P, drop 004): the family link gets a face — sibling cards
with protocol-§8 peer dots (green local / blue LAN / hollow absent), the three family links
(LUNAR bus → twin filter IN, filtered return OUT, PULPO clock IN) as lit nodes with live
activity, the trio badge and an honest state footer. Presentation only: the links
self-assemble on presence.
Family capture (drop 004): CATCH22_REC=1 records the post-return master
to the save dir; CATCH22_WINDOW=WxH sizes the boot window for multi-instrument
session hosts.
LAN (drop 003): machines on the same network find each other over a multicast beacon
(1 Hz) and link over TCP — no configuration, same as local. No multicast on the network (some
VPNs, containers)? Point units at each other once: NYDUS_LAN_DIAL=ip:port seeds a
static peer and re-dials until it is up. NYDUS_TIER2=0 keeps the unit local-only;
NYDUS_LOCKDOWN=1 is the venue switch (no new connections at all). If the daemon
ever dies, the unit respawns and re-links it within seconds — the room heals itself.
Status LED (app bay header): amber pulsing = searching; green solid = a same-machine peer is
patched; blue solid = a LAN peer; red solid = lockdown; red fast blink = nydus fault (dev
chrome — without nydus the unit filters exactly as before). Same-machine peers are tagged
LOCAL; LAN peers show measured milliseconds. FX destination mode: a peer streams
its bus into the unit's pre-filter summing node; the filtered return streams back at
48 kHz / 16-bit in 128-frame chunks (measured round trip 2.67 ms p50 local).
The trio toast: when LUNAR-24, PULPO-23 and CATCH-22 are all present on one machine, the
set announces itself once. The conformance suite (scripts/nydus-tests.sh) travels
with the protocol — every ZRGRT instrument's CI proves the same wire.
| NYDUS=0 | disable nydus entirely for this run |
| NYDUS_TIER2=0 | local-only (no LAN beacon, no LAN dial) |
| NYDUS_LOCKDOWN=1 | venue switch: no new connections at all |
| NYDUS_LAN_DIAL=ip:port,… | static LAN seeds; re-dialed until up (networks without multicast) |
| NYDUS_LAN_PORT=n | pin the LAN TCP port (default: ephemeral) |
| NYDUS_BEACON_PORT/GROUP=n | isolate the mesh (concurrent venues/suites) |
| NYDUS_NS=/path | alternate local namespace (testing) |
| Key | Action |
| F5 | focus walk (a11y): steps through every control |
| arrows | adjust the focused control (shift = fine) |
| tab | switch skin: catch (steel) / twin (cream) |
| H | help overlay |
| F3 | transport telemetry (backend / queue / underrun counters) |
| F2 | save user preset |
| ESC ESC | MIDI panic |
Measured claims live in docs/audits/:
routing.md — topology × mode transfer table, series slope.character.md — bass retention (0.51 dB at res 0.9), pink slope(−3.00 dB/oct), white RMS (0.00 dB), warm-up curve, drift bound,
twin pairs.
tests/dsptest.lua — C/Lua and AVX2/scalar ULP-0 parity, stabilityburn (64 self-osc configs × 60 s, zero failures), mode nulls.
| symptom | look here |
|---|---|
| NO AUDIO state | the fused builds carry the bridge; for the bare .love, lib/miniaudio/rtbridge.so must sit beside it. The log line names the cause. |
| No preset names | user presets live in the save directory data/presets/; factory names come from inside the build. If the list is empty the build is incomplete — re-download. |
| MIDI knob does not follow | right-click the knob (red ring), then move the controller within 5 seconds. A bind toasts; ESC ESC clears everything. |
| Underruns on a weak machine | the transport watchdog resyncs the pump automatically; if audio stops entirely the app continues in the NO AUDIO state rather than freezing. |
| Peer LED stays amber | no peers present — the correct honest state. Check NYDUS=0 is not set and the other instrument is running. |
| engine | 48 kHz stereo, 512-frame blocks, C kernels (PGO) with bit-exact Lua twin, AVX2 dispatch |
| cost | ~38 µs per 512-frame block (budget 60) on the reference machine |
| latency | local FX round trip 2.67 ms p50; live ext input adds the OS buffer once |
| stability | 64-config self-osc burn × 60 s zero failures; 8 h release soak (engine + FX stream) |
| mismatch | per-channel seeds: g ±3%, k ±4%, bias ±0.02, res threshold ±0.02, OU drift ±0.4% (tau 30–120 s) |
| format | standalone app; .love ~250 KB bare / fused installers with native libs |
| license | MIT © 2026 the ZRGRT — source included |
CATCH-22 is an original work of the ZRGRT. Its filter lineage: the mid-1980s Soviet Formanta Polivoks designed by Vladimir Kuzmin, whose programmable-op-amp filter cell is public engineering folklore and the inspiration here — an independent digital implementation, not a product of, endorsed by, or affiliated with ELTA Music or any hardware manufacturer.
The temperament research (starve / drip) was validated against primary sources, among them Mark Barton's breadboard notes published by Cherry Audio and the DIY synth community's technical archives. Thanks to that community — the build lore, bench measurements and schematics culture that keep these machines playable.
Everything in BAND B, the SOURCE bay, the LFOs, the follower, presets and
MIDI learn are app-original supersets — the hardware had none of them, and
they are marked APP on the panel. The parity contract is the hardware
control inventory; the supersets never host a hardware function.