From c398b86d2bd74158e21e74406a56056d0683560d Mon Sep 17 00:00:00 2001 From: Mikkeli Matlock Date: Sun, 14 Jun 2026 20:31:27 +0900 Subject: [PATCH] initial commit --- README.md | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..35ab414 --- /dev/null +++ b/README.md @@ -0,0 +1,202 @@ +# Codename 206 + +*Called 206 because the Peugeot 206 has a 'maxi' variant. Subdued lineage to the FL Studio plugin 'maximiser'* +Multiband Compressor / Limiter VST3 — Project Plan + +## Overview + +A VST3 multiband compressor/limiter with a custom gain curve display, inspired by FL Studio's Maximizer. +Built with **Rust** + **NIH-plug** (VST3 + CLAP output) + **egui** for the UI. + +**Goals:** +- 3-band (configurable crossover points) compressor/limiter +- Look-ahead brickwall output limiter with true-peak detection +- Real-time gain reduction metering per band +- Custom gain curve visualiser +- Fully resizable vector UI +--- + +## Tech Stack + +| Layer | Choice | +|---|---| +| Language | Rust (stable) | +| Plugin framework | [NIH-plug](https://github.com/robbert-vdh/nih-plug) | +| Plugin formats | VST3, CLAP | +| UI framework | egui (via `nih_plug_egui`) | +| Build tooling | `cargo xtask bundle` | + +--- + +## Signal Flow + +``` +Input + └─ Crossover filterbank (Linkwitz-Riley LR4 @ each crossover freq) + ├─ Band 1 (low) → look-ahead delay → compressor VCA → gain stage + ├─ Band 2 (mid) → look-ahead delay → compressor VCA → gain stage + └─ Band 3 (high) → look-ahead delay → compressor VCA → gain stage + └─ Sum → output brickwall limiter (true-peak, 4x oversampled) → output +``` + +The detector for each band reads `look_ahead_ms` ahead of the VCA, so gain reduction is already ramping when the transient arrives. + +--- + +## DSP Architecture + +### Crossover Filterbank +- Linkwitz-Riley 4th-order (LR4) filters at each crossover frequency +- LR4 = two cascaded biquads (Butterworth LP or HP) +- Bands sum phase-coherently back to flat +- Crossover frequencies are user-adjustable parameters +### Per-Band Compressor +- Level detection: switchable RMS / peak, with configurable window +- Gain computer: threshold, ratio, soft knee +- Attack / release envelopes (logarithmic ballistics) +- Makeup gain per band +- Look-ahead: circular delay buffer on the audio path; detector reads ahead +### Output Limiter +- True-peak brickwall (ceiling = 0 dBFS or user-defined) +- 4x oversampling for inter-sample peak detection +- Short attack (≤ 0.1 ms), auto-release +### Latency +- Look-ahead duration must be reported via `Plugin::latency()` for DAW compensation +- All bands use equal delay to preserve phase alignment +--- + +## Parameters + +### Global +- `input_gain` — pre-gain before filterbank (dB) +- `output_ceiling` — brickwall ceiling (dBFS, default 0.0) +- `look_ahead_ms` — look-ahead time (0–10 ms) +- `crossover_low_hz` — low/mid crossover frequency +- `crossover_high_hz` — mid/high crossover frequency +### Per Band (× 3, use a `#[nested]` params struct) +- `threshold_db` +- `ratio` — 1.0 (off) to ∞ (limiting) +- `attack_ms` +- `release_ms` +- `knee_db` — soft knee width +- `makeup_gain_db` +- `bypass` — per-band bypass +--- + +## Project Structure + +``` +src/ + lib.rs # Plugin entry point, implements Plugin trait + params.rs # Params struct with NIH-plug #[id] attributes + dsp/ + mod.rs + crossover.rs # LR4 filterbank (biquad chains) + compressor.rs # Per-band compressor + look-ahead + limiter.rs # Output true-peak brickwall limiter + biquad.rs # Generic biquad filter (Direct Form II transposed) + delay.rs # Circular buffer for look-ahead delay lines + oversampler.rs # 4x oversampler for true-peak detection + editor/ + mod.rs # egui editor setup via nih_plug_egui + widgets/ + gain_curve.rs # Custom egui Widget: gain curve display + band_meter.rs # Per-band gain reduction meter + level_meter.rs# Input/output level meter +``` + +--- + +## Build Steps + +```bash +# Install Rust (if not already) +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + +# Clone NIH-plug cookiecutter or start fresh +cargo new --lib my_maximizer +cd my_maximizer + +# Add dependencies to Cargo.toml: +# nih-plug = { git = "https://github.com/robbert-vdh/nih-plug", features = ["assert_process_allocs"] } +# nih-plug-egui = { git = "https://github.com/robbert-vdh/nih-plug" } + +# Build and bundle +cargo xtask bundle my_maximizer --release +# Output: target/bundled/my_maximizer.vst3 +``` + +--- + +## Implementation Order + +Work through these stages in order — each stage produces a loadable, audible plugin. + +### Stage 1 — Skeleton plugin +- [ ] NIH-plug "passthrough" compiling and loading in DAW +- [ ] `Params` struct with all parameters declared (no DSP yet) +- [ ] `process()` passes audio through untouched +- [ ] Verify plugin loads and parameters appear in DAW +### Stage 2 — Single-band compressor (no look-ahead, no UI) +- [ ] Implement `biquad.rs` — generic biquad, Direct Form II transposed +- [ ] Implement basic RMS level detector +- [ ] Implement gain computer (threshold, ratio, knee) +- [ ] Implement attack/release envelope on gain reduction +- [ ] Wire into `process()`, test with a sine sweep +### Stage 3 — Crossover filterbank +- [ ] Implement LR4 LP and HP biquad chains in `crossover.rs` +- [ ] Verify bands sum flat (null test: sum vs dry should be silence) +- [ ] Apply per-band compressor to each band +- [ ] Sum bands back to output +### Stage 4 — Look-ahead + brickwall limiter +- [ ] Implement `delay.rs` circular buffer +- [ ] Wire look-ahead: detector reads N samples ahead of VCA +- [ ] Report latency via `Plugin::latency()` +- [ ] Implement `oversampler.rs` (4x, use a polyphase FIR or windowed sinc) +- [ ] Implement brickwall output limiter with true-peak detection +### Stage 5 — Basic egui UI +- [ ] Add `nih_plug_egui` editor +- [ ] Knobs / sliders for all parameters +- [ ] Per-band bypass toggles +- [ ] Confirm UI controls update DSP in real time +### Stage 6 — Custom visualisations +- [ ] `level_meter.rs` — input/output RMS + peak meters +- [ ] `band_meter.rs` — per-band gain reduction meters (vertical bars) +- [ ] `gain_curve.rs` — static gain curve display per band (threshold/ratio/knee) +- [ ] Draggable crossover handles on a frequency display +--- + +## Key Implementation Notes + +### No allocations in `process()` +Rust's borrow checker will help, but be explicit. All buffers (delay lines, filter states) +must be pre-allocated in `initialize()`. Use `assert_process_allocs` feature flag during +development to catch violations. + +### Denormal flushing +Add `#[cfg(target_arch = "x86_64")] std::arch::x86_64::_MM_SET_FLUSH_ZERO_MODE(...)` in +`initialize()`, or add a small DC offset (1e-25) to filter inputs. + +### Parameter smoothing +NIH-plug provides `Smoother` — use it for all gain/threshold params to avoid zipper noise. + +### Thread safety +Params are atomics. The editor and audio thread communicate only through params and +`Arc>` meter data. Never pass DSP state to the UI directly. + +### VST3 licensing +You must accept Steinberg's VST3 SDK licence before distributing VST3 binaries. +NIH-plug's VST3 bindings are GPLv3; if you distribute, the plugin must also be GPLv3 +(or you need a commercial Steinberg licence). CLAP has no such restriction. + +--- + +## Reference Material + +- [NIH-plug repo](https://github.com/robbert-vdh/nih-plug) — read the `plugins/` examples first +- [NIH-plug docs](https://nih-plug.robbertvanderhelm.nl/) +- [Cookiecutter template](https://github.com/robbert-vdh/nih-plug-template) +- [egui docs](https://docs.rs/egui) +- Zölzer, *DAFX: Digital Audio Effects* — biquad filter cookbook +- Giannoulis et al., "Digital Dynamic Range Compressor Design" (JAES 2012) — compressor ballistics reference +- AES paper on true-peak limiting / inter-sample peaks (ITU-R BS.1770) \ No newline at end of file