A circuit-derived model of a 1176-style FET limiting amplifier, in Rust. VST3, CLAP, and a standalone harness.
The dynamics are not produced by an envelope follower and a gain computer. They come out of solving a closed feedback loop once per internal sample: a JFET shunt attenuator, an amplifier, a resistively switched detector network, a rectifier and a two-capacitor timing network. Gain reduction and distortion fall out of the same device equations at the same operating point, so they cannot be tuned apart — which is the whole point of building it this way.
There is no threshold parameter, no ratio constant, no knee control and no makeup gain anywhere in the core, because the hardware has none of those things. The compression curve is whatever the loop settles to.
The unit can also run a distilled neural model instead of the circuit. Same faceplate, same controls; the ENGINE chip in the header switches between them, and a right-click on it loads the next installed model.
Models are .fbmx files — a small container holding weights, the control
surface they were trained with, and where the training data came from. They
live in
~/Documents/Futureboard Studio/Utilities/Neural Models/
(FBMX_MODEL_DIR overrides it.) To see what the plugin can see:
cargo run -p fa76-neural --bin fa76-models -- --probeThe models are distilled from this circuit model, so they inherit its
approximations plus whatever the fit missed. They are a research engine, not a
replacement, and the differences are measured rather than guessed: as of the
current models the release runs roughly twice as fast as the circuit's and the
second harmonic about 10 dB high. crates/fa76-neural-lab in the parent
workspace prints the full comparison.
Three limits are structural rather than incidental:
- Mono. The models were trained on one channel, so stereo runs two independent copies. There is no detector linking in neural mode whatever the Stereo switch says.
- Rev D only. The conditioning is Input, Attack, Release, Ratio. The revision switch does nothing to a neural model; the model carries the revision it was trained on.
- OUTPUT is still real DSP. The output attenuator sits after the sidechain tap and cannot change gain reduction, so it was held fixed during training and is applied as a plain gain around the model.
The gain-reduction meter in neural mode is an estimate — the runtime does not execute the model's auxiliary gain head, so the engine infers it from the input/output envelopes against a small-signal gain it measures at load.
The engine adds no latency (the model is causal and has no oversampling), so switching engines changes the plugin's reported latency; hosts are told.
Building without any of this:
cargo bundle --no-default-features # circuit only, no fbmx-runtime dependency# VST3 + CLAP into target/bundled/
cargo bundle
# the standalone harness: drop an audio file in and drive it
cargo playground
# offline DSP measurement (writes target/dsp-analysis/*.csv)
cargo lab linear
cargo lab allThose are aliases in .cargo/config.toml. Spelled out:
cargo xtask bundle fa76-plugin --release
cargo run --release -p fa76-playground
cargo run --release -p fa76-dsp-lab -- linear
cargo xtask bundle fa76will not work.fa76is the DSP core: an rlib with nocdylib, so there is nothing to bundle. The plugin package isfa76-plugin. Usecargo bundleand the question does not arise.
Install by copying target/bundled/FA76.vst3 to your VST3 folder
(C:\Program Files\Common Files\VST3\, ~/.vst3, or
~/Library/Audio/Plug-Ins/VST3) and rescanning.
Requires a recent stable Rust (built against 1.97). The plugin pulls nih-plug from git, pinned by revision.
| crate | what it is | dependencies |
|---|---|---|
fa76 |
the DSP core | none |
fa76-ui |
the faceplate: geometry, widgets, presets, fonts | fa76, egui |
fa76-playground |
standalone: file loading, transport, waveform | fa76-ui, eframe, cpal, symphonia |
fa76-plugin |
VST3/CLAP wiring | fa76-ui, nih_plug, nih_plug_egui |
fa76-dsp-lab |
offline measurement and calibration | fa76 |
xtask |
the bundler | nih_plug_xtask |
The core has zero dependencies and is tested on its own. The editor is
written once against bare egui and shared verbatim between the standalone and
the plugin, which talk to it through an EditorHost trait — the standalone
backs it with atomics, the plugin with nih-plug parameters and automation
gestures.
in ─► input transformer ─► INPUT attenuator
│
▼
FET shunt cell ◄──────────────────────────┐
│ │
▼ │
preamp ──┬──► ratio network ──► sidechain amp
│ │ │ │
│ │ full-wave rectifier │
│ │ │ │
│ │ attack/release network │
│ │ │ │
│ └─────────┴──► control voltage ─┘
▼
OUTPUT attenuator ─► output amplifier ─► output transformer ─► out
The detector is fed from the preamp output — signal that has already been through the gain-reduction cell — so the unit is a feedback compressor. That one wiring decision is why the knee is soft without a knee parameter existing, and why the OUTPUT control cannot change the amount of gain reduction.
The ratio buttons are not numbers. Each closes contacts that add resistors to a detector summing node; the node is solved as a one-node nodal problem, and the ratio, the threshold and the sidechain bandwidth all fall out of it. All Buttons is simply all four decks closed at once — nothing in the code branches on it — and the network lands on an operating point no single button can reach.
Slopes over the 1–15 dB gain-reduction window, and the level at which each deck first produces 1 dB of gain reduction:
| mode | threshold | slope | max GR |
|---|---|---|---|
| 4:1 | −10.36 dB | 4.01:1 | 17.4 dB |
| 8:1 | −12.71 dB | 8.41:1 | 21.9 dB |
| 12:1 | −15.59 dB | 12.16:1 | 25.0 dB |
| 20:1 | −18.64 dB | 19.58:1 | 28.7 dB |
| All Buttons | −17.71 dB | 17.29:1 | 27.4 dB |
Linear baseline, Rev D at 48 kHz / 2×, relative to 1 kHz:
20 Hz -0.163 dB 5 kHz -0.000 dB
50 Hz -0.029 dB 10 kHz -0.001 dB
100 Hz -0.007 dB 15 kHz -0.004 dB
1 kHz 0.000 dB 20 kHz -0.025 dB
Distortion at matched drive rises from 0.09 % at 10 kHz to 1.10 % at 50 Hz, with the third harmonic climbing 35 dB — that is the control voltage moving inside the cycle, not a bass-dependent effect anyone wrote.
cargo test --release -p fa76 # DSP core: 100 tests
cargo test --release --workspace # everything
cargo clippy --workspace --all-targetsThe suite covers static transfer curves, per-ratio thresholds, attack/release measurement, THD versus gain reduction, all-buttons comparison, sample-rate and oversampling regression, linear-response acceptance bounds, and robustness (NaN, DC, full-scale, rapid automation, block-size invariance).
Stage-by-stage isolation of the linear path is a development build:
cargo run --release -p fa76-dsp-lab --features diagnostics -- stagesIt compiles to nothing without the feature and is never exposed as a user control.
docs/dsp/1176-circuit-model.md |
the model, its assumptions, and the measurements behind them |
docs/dsp/fa76-linear-calibration.md |
how the linear transfer function was diagnosed and corrected |
docs/plugin.md |
VST3/CLAP build, parameters, latency |
docs/playground.md |
the standalone harness and the panel |
Each labels its claims: circuit-derived, fitted, approximated, or empirical.
No hardware was measured while building this. The targets are published specifications and the widely reported behaviour of the design; component values are fitted to hit those, and the documentation says which are which. No claim of equivalence to any particular unit is made or implied.
Known limitations, in full in the docs:
- THD is roughly flat against gain reduction at a fixed ratio. That is a real consequence of the topology, not an oversight, but it is less dramatic than the hardware's reputation and needs measurements to apportion.
- The linear response is flatter than a real unit; the pole positions come from plausible component values rather than a measured sweep.
- Transformer hysteresis is a rate-independent play operator: the loop width is right, the loop shape is not.
- Rev A and Rev F are structural stubs — the FET and output stage differ correctly, but their detector networks have not been re-fitted, so their ratio markings will not measure right. Rev E is currently identical to Rev D.
- The plugin has not been validated in a host. It builds and bundles; it has not
been through
pluginvalor a DAW.
MIT. See LICENSE.
The panel artwork, the knob image and the bundled Mona Sans font in
ui/assets/ are covered by their own licences, not by the MIT licence above.