# Tunnels

Tunnels is a JUCE 8 / C++20 phase-distortion bass instrument for Reese,
jungle, drum-and-bass, garage, IDM, and adjacent bass workflows.

The engine is deliberately focused: monophonic voice management, glide,
legato, two CZ-style phase-distortion oscillators, sine/PD sub oscillator,
stereo noise, drive, a selectable lowpass/filter slot, modulation matrix,
and a resizable single-canvas editor.

For deeper context:

- [DESIGN.md](DESIGN.md) covers the product and audio target.
- [PLAN.md](PLAN.md) is the engineering source of truth.
- [TOPOLOGY.md](TOPOLOGY.md) records DSP model choices.
- [DESIGN_LANGUAGE.md](DESIGN_LANGUAGE.md) is the UI grid, component grammar, and visual doctrine.
- [docs/PRESETS.md](docs/PRESETS.md) is the factory preset reference.
- [docs/SELF_HOSTED_RUNNERS.md](docs/SELF_HOSTED_RUNNERS.md) covers local release runners.

## Install

Grab the latest release from GitHub:
<https://github.com/beigethreat/tunnels/releases>

Public macOS release installers are signed and notarized, so normal first-run
installation should not require an operating-system bypass. Windows installers
are currently unsigned.

### macOS

Install `Tunnels-macos-<version>.pkg`.

The package installs:

- AU: `/Library/Audio/Plug-Ins/Components`
- VST3: `/Library/Audio/Plug-Ins/VST3`
- Standalone: `/Applications`

If macOS still reports that the package cannot be verified, download it again
from the official release page and make sure the filename matches the current
release.

### Windows

Install `Tunnels-windows-<version>.exe`.

The installer writes the VST3 to:

```text
C:\Program Files\Common Files\VST3
```

Windows may apply SmartScreen checks because the installer is currently
unsigned.

### Linux

Debian / Ubuntu:

```sh
sudo dpkg -i tunnels_<version>_amd64.deb
```

Other distributions:

```sh
tar -xf Tunnels-linux-<version>.tar.gz
./install.sh
```

Restart your DAW after installation so it rescans plug-in folders.

## Build

The pinned toolchain lives in the Nix dev shell. Work from inside it.

```sh
nix develop
just build
just test
```

Useful recipes:

| Recipe | Purpose |
|---|---|
| `just` | List available recipes. |
| `just build` | Configure and build the Debug plugin and tests. |
| `just test` | Run the unit test binary directly. |
| `just ctest` | Run the full CTest suite with verbose failures. |
| `just asan` | Build and test executable targets with ASan + UBSan. |
| `just pluginval` | Run pluginval at strictness 10. |
| `just auval` | Run Apple's AU validator on macOS. |
| `just render` | Diff reference renders against `tests/refs/`. |
| `just render-refs` | Regenerate reference WAVs intentionally. |
| `just verify` | Build, test, and run pluginval. |
| `just ci-local` | Mirror the core hosted CI checks before spending Actions minutes. |
| `just ci-format` | Mirror the hosted clang-format job on tracked source files. |
| `just ci-lint` | Mirror the hosted workflow/shell/CMake/Nix lint job on tracked files. |
| `just ci-build` | Mirror the hosted warning-as-error build and CTest in `/tmp/tunnels-ci`. |
| `just format` | Run the pre-commit formatting suite. |
| `just tidy` | Run clang-tidy across `src/` and `tests/`. |

The recipes wrap CMake, CTest, and scripts in `tools/`; raw invocations still
work when needed.

`just asan` focuses on test/tool executables, where sanitizer runtimes are
hosted reliably. Plugin formats are covered by the normal build and
`just pluginval`.

When GitHub Actions minutes are tight, run `just ci-local` before pushing.
Pull requests run format, lint, and the Ubuntu build/test gate; macOS,
clang-tidy, and sanitizer jobs run on `main` pushes or when the CI workflow is
started manually with `run_expensive` enabled.

## Layout

| Path | Purpose |
|---|---|
| `src/PluginProcessor.{h,cpp}` | APVTS layout, processor, held-note stack. |
| `src/ui/` | Custom single-canvas editor, widgets, tokens, browse and matrix views. |
| `src/dsp/CZWaveforms.h` | Eight CZ-style phase-distortion shapes. |
| `src/dsp/PDLine.h` | Single PD oscillator line with DCW envelope, PWM, and sync support. |
| `src/dsp/SubOscillator.h` | Sine/PD sub oscillator at -1 octave. |
| `src/dsp/NoiseSource.h` | Stereo white/pink/brown noise source. |
| `src/dsp/Drive.h` | Soft, diode, and fold drive models. |
| `src/dsp/FilterBank.h` | Runtime filter model selector. |
| `src/dsp/LadderFilter.h` | ZDF ladder lowpass model. |
| `src/dsp/PDVoice.{h,cpp}` | Monophonic voice, modulation, routing, oversampled section. |
| `presets/*.xml` | Factory preset XML plus `manifest.xml`. |
| `tests/` | JUCE unit tests and render harness. |
| `tests/reports/` | Measurement notes for DSP-sensitive changes. |
| `tools/` | Validation, installer, preset, preview, and render scripts. |

## Validation Bar

Before merging audio or processor changes, run:

```sh
nix develop
just ctest
just pluginval
```

When the change affects DSP output, also update or re-run the relevant
measurement report under `tests/reports/` and keep reference renders matching
unless the audio change is deliberate.
