# Tunnels

A phase-modulation reese bass synthesizer plugin. JUCE 8, C++20. Builds as
**VST3**, **AU**, and **Standalone** on macOS, Linux, and Windows.

- Manufacturer: Beige Threat (`Lflu` / `Tnnl`)
- Bundle ID: `com.beigethreat.tunnels`
- JUCE: 8.0.12 (fetched via CMake `FetchContent`)

## Repository layout

| Path | Contents |
| --- | --- |
| `src/` | Plugin processor, presets, DSP, UI |
| `src/dsp/` | Synth engine: `PDVoice`, filters, drive, FX, LFO, sequencer |
| `src/ui/` | `Editor`, panels, composites, primitives, presenters, views |
| `src/auth/` | `LicenseManager` (offline license card verification) |
| `modules/thanet/` | Internal JUCE design system (`thanet::thanet`); see its own README |
| `presets/` | XML preset bank shipped with the plugin |
| `tests/` | CTest suite (DSP, UI, presets, license, render harness) |
| `tools/` | Preset renderer, snapshot tools, license-card signing, pluginval/auval scripts |
| `packaging/` | Platform installer recipes (`linux/`, `macos/`, `windows/`) |
| `cmake/` | `Dependencies.cmake` (JUCE fetch and friends) |
| `fonts/`, `licenses/`, `design/` | Binary assets and design references |

## Prerequisites

The repo ships a Nix flake and `devenv.nix` — entering the dev shell gives you
the exact CMake, Ninja, clang-tools, `just`, `ccache`, `lefthook`, and (on
Linux) `pluginval` and the X11/ALSA build inputs.

```sh
nix develop          # or: direnv allow
```

Without Nix you need: CMake ≥ 3.22, Ninja, a C++20 compiler (Clang/AppleClang
or GCC), `just`, `ccache`, and JUCE's platform deps (ALSA, JACK, GTK3,
freetype, fontconfig, X11 libs on Linux).

## Common tasks

All routine work goes through `just`. Run `just` for the full list.

```sh
just build              # Debug build (configures if needed)
just build-fast         # Release VST3 + Standalone, no LTO, unity build, ccache
just test               # Run the unit test binary directly
just ctest              # Full CTest suite with verbose failures
just verify             # build + ctest + pluginval (the local "ready to push" gate)
just ci-local           # Mirror the hosted PR gate before spending CI minutes
just asan               # ASan + UBSan in build-asan/
just pluginval          # Validate built formats at strictness 10
just auval              # Apple AU validator (macOS only)
just format             # lefthook-driven formatting (matches the pre-commit hook)
just render-refs        # Regenerate tests/refs/*.wav — commit intentionally
```

Build artefacts land under `build/Tunnels_artefacts/<Format>/`. On macOS the
standalone is `build/Tunnels_artefacts/Standalone/Tunnels.app`.

## Build flags

| Option | Default | Purpose |
| --- | --- | --- |
| `BUILD_TESTING` | `ON` | Build the CTest suite |
| `TUNNELS_SANITIZERS` | `OFF` | ASan + UBSan on Tunnels targets |
| `TUNNELS_STRICT_WARNINGS` | `ON` | `-Wall -Wextra -Wshadow -Wconversion …` on our sources only |
| `TUNNELS_WERROR` | `OFF` | Treat strict warnings as errors (CI: ON) |
| `TUNNELS_ENABLE_COMPONENT_GALLERY` | `ON` | Build `tunnels_ui_gallery_snapshot` |
| `TUNNELS_BUILD_TOOLS` | `ON` | Build `tunnels_preset_render` and friends |
| `TUNNELS_UNITY_BUILD` | `OFF` | Unity-build our `.cpp` files (JUCE TUs stay separate) |
| `TUNNELS_ENABLE_JUCE_LTO` | `ON` (Linux: `OFF`) | JUCE's recommended Release LTO |

Strict warnings are applied per-source so JUCE module TUs (pushed via
`INTERFACE_SOURCES`) compile cleanly.

## Testing

`tests/` contains GoogleTest-style unit tests for the DSP primitives
(filters, LFO, limiter, smoothing, voice, aliasing, waveforms), the matrix
and sequencer, presets, license verification, and UI primitives. Render
references live in `tests/refs/` — diff them with `just render`, regenerate
with `just render-refs`.

## Presets

Hand-authored XML presets live in `presets/`. The catalogue is validated by
`PresetCatalogueTest`. Generated/scripted presets go through
`tools/gen_presets.py`. **Trap to watch for:** any preset with osc `DCW`
depth = 0 collapses to a cosine regardless of the selected waveform — always
co-check `wave` and `DCW depth` when auditing.

## Installation (built locally)

After a successful build, the platform-specific installer scripts under
`tools/install-{linux,macos,windows}.sh|bat` copy the built bundles into the
standard plugin paths.

## Further reading

- `docs/ARCHITECTURE.md` — module map, key conventions, and where to make
  changes.
- `modules/thanet/README.md` and `modules/thanet/docs/` — the internal design
  system.
