Docs / Nebula Sound System documentation / Architecture and decisions
Architecture and decisions
Why Nebula is built this way, and the decisions it will not reverse — including why VST3 cannot be supported and CLAP was chosen instead.
Nebula's big choices are written down as numbered decision records: the situation, the options
considered, the decision and its consequences. This page is that list, in the same order as the
repository's docs/adr/ folder.
Two of them are the ones users ask about most, because they explain what the app will never do:
- VST3 is not supported, and cannot be. The VST3 SDK is dual-licensed GPLv3-or-Steinberg-proprietary, and a GPL dependency cannot go into a binary shipped under the Functional Source License (FSL-1.1-ALv2). The dependency ledger once carried a row claiming the VST3 SDK is MIT; that row was wrong and has been corrected. Nothing in the repository links or ships the VST3 SDK.
- CLAP was chosen instead, because it is licence-clean: MIT headers, a C ABI with no runtime to link, documented search paths and an open validator. A hosted plug-in's parameters become ordinary knobs, its reported latency feeds delay compensation, and its state is saved in the project — but its own editor window is never shown.
A hosted plug-in is subject to the same real-time rule as everything in the engine: the audio thread may not allocate, lock, block, log or do I/O. That is why the out-of-process bridge (ADR-0033) hands block N over and plays block N-1's answer instead of waiting.
The decision records
An ADR records why something was decided: the situation, the options considered, the decision, and the consequences. New significant decisions get a new numbered file here; the architectural changelog (CHANGELOG-ARCH) links each change to its ADR.
| # | Title | Status |
|---|---|---|
| 0001 | Technology stack (with Qt-version and owner-decision amendments) | Accepted |
| 0002 | Project licence, MIT SDK split, dependency policy and list | Accepted |
| 0003 | Threading model and real-time rules | Accepted (graph swap details in Phase 2) |
| 0004 | Command system and undo/redo | Accepted, implemented (Phase 3, slice 1) |
| 0005 | File formats (preset, patch, project v1 implemented; bundle/journal later) | Accepted for preset/patch/project; Proposed for the rest |
| 0006 | Plugin sandbox protocol | Planned (Phase 2 spike / 7) |
| 0007 | Device and parameter model (C ABI proposed) | Accepted in-process; C ABI Proposed |
| 0008 | UI architecture (Qt Quick, themes, help strip) | Accepted |
| 0009 | 32-bit bridge design | Dropped from critical path (owner decision) |
| 0010 | Graph Builder runtime and plugin export | Planned (Phase 12) |
| 0011 | Audio backends and ASIO | Accepted |
| 0012 | VST2 stance | Decided: no VST2 (see owner decisions) |
| 0013 | Tempo sync (Ableton Link) | Decided: not implemented (owner decision) |
| 0014 | Video codecs and FFmpeg build | Planned (Phase 14) |
| 0015 | ML models and licences | Planned (Phase 13) |
| 0016 | Warp modes and time-stretch | Planned (Phase 5) |
| 0017 | Audio graph, render plan and offline-first engine | Accepted (slices 1-4 implemented) |
| 0018 | Modular synthesis, numbered input slots and patches | Accepted |
| 0020 | Actions, shortcuts and keymaps (ActionRegistry, contexts, keymap.json, .nebconfig) |
Accepted, implemented (Phase 3) |
| 0019 | Nebula devices as standalone plug-ins (CLAP/VST3/LV2 export, licence of the plug-in line) | Planned (post-1.0; foundations kept in mind from now on) |
| 0021 | Musical time and TempoMap (ticks, piecewise tempo/time-signature, bar/beat/tick) |
Accepted, implemented |
| 0022 | The project-to-audio bridge (services, ProjectRenderer, VoiceAllocator) |
Accepted, implemented |
| 0023 | The five-rule architecture charter (thread separation, lock-free comms, instrument API, Closed Core/Open API, domain folders) + the migration plan | Accepted — docs/architecture/README.md is the source of truth |
| 0024 | The Control API v1: local TCP JSON-RPC server, token auth, first method set (api_server/ + app/src/api_controller.*) |
Accepted, implemented |
| 0025 | FAUST as a build-time-only code generator for instruments (plan P5) | Accepted |
| 0026 | Structural headroom: equal-energy polyphony (√voices), a keyboard velocity curve, and a shared transparent-by-default master limiter | Accepted, implemented |
| 0027 | MIDI output: the song's notes and clock go out of a port | Accepted |
| 0028 | A multi-core render scheduler: render independent tracks at once, sum in one fixed order | Accepted |
| 0029 | An MCP server, as a client of the Control API | Accepted |
| 0030 | Clock receive, MIDI Timecode and program change (following external gear; the per-track MIDI channel) | Accepted |
| 0031 | Lua controller scripts (a vendored, sandboxed Lua host) and MPE (per-note expression, in and out) | Accepted |
| 0032 | Hosting CLAP plug-ins (and why not VST3) | Accepted, implemented (engine/plugins side; see its "Not built" list) |
| 0033 | The out-of-process plugin bridge (hosting a plugin in a process of its own; 32-bit or foreign-licence plugins) | Accepted, implemented (protocol, host, bridge process, stub plugin; a 32-bit bridge is not built here) |
| 0034 | Per-track MIDI output ports, control-change (CC 7 / CC 10) automation out, and a configurable MIDI-out drain interval | Accepted, implemented |
Settings design is documented in architecture/settings.md.
Updated 2026-11-03