Docs / Nebula Sound System documentation / Features and current status

Features and current status

The consolidated inventory of what the app can do today, what is only partly there, and what is agreed but not built — every row naming the file that proves it.

Note. This page's header line records when the inventory was first written. The tables name the release each row shipped in, and several rows are newer than that header (0.3.0-alpha.275 … .278).

Written against 0.3.0-alpha.272 (2026-11-01). This page is the consolidated inventory: what the app can do today, what is only partly there, and what is agreed but not built. PROGRESS.md records what each release changed; this page answers "what is in it, right now".

How to read the state column

word meaning
shipped in the packaged build, covered by the test suites
partial it works, with a limit named in the row
planned agreed and written down, not built
not built deliberately dropped (with the reason recorded)
unverified written, but never run on the target (say so, never claim it works)

Evidence names the module, file or document that proves the claim — every row can be checked.


1. Platforms and packaging

Feature What it does State Evidence
Windows build MSVC, Qt 6.8, packaged app + setup.exe shipped tools/package.ps1, tools/installer.iss
Windows installer per-user install (no admin prompt), Start Menu entry, uninstaller; verified by silent install → run → uninstall shipped tools/make_installer.ps1, docs/implementation/building.md
Portable Windows zip dist/Nebula-<version>/ + .zip, latest version only shipped tools/package.ps1 (keep-1 prune)
Linux build GCC, Qt 6.8 (aqtinstall), tests + app shipped .gitea/workflows/ci.yml, references/wsl-linux-verification.md
Linux .deb installs to /opt/nebula, menu entry, nebula command, bundles its own Qt; verified by install → run → remove shipped tools/make_installer_linux.sh
Linux portable .tar.gz the same tree, unpack anywhere shipped same script
macOS .dmg macdeployqt bundle + disk image script unverified — no Mac in the toolchain, no CI job tools/make_installer_macos.sh (its own header says so)
macOS MIDI input — not built (Windows uses WinMM, Linux ALSA; no CoreMIDI) docs/plan/keyboard-shortcuts.md, HANDOFF
Headless project render render a saved .nebproj to WAV with no window shipped (example tool) examples/render_project_file.cpp

2. The app's surfaces

Feature What it does State Evidence
Timeline (arrangement) tracks, clips, drag/move, split, quantise, zoom, loop range, playhead shipped app/TimelineView.qml, PianoRoll.qml
Clip Launcher (Session) scene grid, clip triggers, launch quantise, per-clip loop shipped app/SessionView.qml
Mixer channel strips, faders, pan, meters, groups, returns, master shipped app/MixerView.qml
Node view build your own instrument by wiring modules (NOSI graph) shipped app/NodeView.qml, docs/plan/node-view-and-nosi.md
Browser panel instruments, effects, samples, content library, search shipped app/BrowserPanel.qml
Detail panel + cards per-track cards: Instrument, Devices/FX, Note Effects, Analyser, Mastering, Automation, Log shipped app/DetailPanel.qml + *Card.qml
Command palette Ctrl+K action list with shortcuts shipped app/CommandPalette.qml
Settings sheet 11 pages: appearance, audio, MIDI, instrument, local API, export, logging, project, bug report, keys & shortcuts, about shipped app/SettingsPanel.qml + sections
Themes built-in themes + user theme folder + import/export; contrast-checked shipped app/theme/*, tools/check_docs.py theme rules
Help strip hover help for every control ("point at anything") shipped app/Main.qml
Translations i18n skeleton + string externalisation partial (skeleton; strings extractable, no shipped translations yet) tools/translations.ps1
Accessibility accessible names/roles on controls, checked by a guard shipped check_qml_accessible guard
Crash report dialog in-app report to the project's endpoint, with a key shipped bug-report settings page, docs/plan/distribution-and-support.md

3. Instruments

Feature What it does State Evidence
Modular synth voices 93 lead/key patches (Modular Lead, Square Lead, Acid Saw, Tine E-Piano, …) shipped plugins/src/patch.cpp (voice_patch)
Bass patches 64 bass patches (Sub Bass, 808 Sub, Minimoog Bass, Motown Bass, Bass Guitar, …) shipped same (categorised_voice("bass", …))
Pad patches 61 pads (Warm Strings, Glass Pad, Aurora Pad, Choir Pad, …) shipped same (pad_patch)
FM instruments 45 FM patches (FM E-Piano, FM Bell, FM Bass, FM Brass, …) shipped same (fm)
263 factory patches total, four families — shipped factory_patches()
Sampler one sample per track, root note, tune, attack/release, loop, start/end shipped app/SamplerCard.qml, nebula.services.kSamplerInstrument
Drum Rack 16 pads, per-pad sample + gain/tune/release/start/end, choke groups, kit load/save (.nebkit), slice-a-sample to pads shipped app/DrumRackCard.qml, services/src/track_instrument.cpp
Instrument Rack layered instruments with per-layer gain, level control, add/remove/reorder layers shipped app/RackCard.qml
24 drum-machine kits 606, 707, 808, Acid, Breaks, Cinematic, Deep House, Drum and Bass, Electro, Funk, Garage, Hip-Hop, Jazz, Jungle, Kitchen Keys, Latin, Minimal, Orchestral, Percussion, Reggae, Rock, Techno, Trance, Trap shipped dist/…/patches/*Kit.nebpatch
292 patch files ship with the build factory patches + ready-made presets shipped dist/…/patches/
Per-instrument presets save/load a patch's knob settings (.nebpatch) shipped app/PatchFilesSection.qml
Rhytmix voice-to-MIDI (sing → notes), chord naming with plain-English explanation, next-chord suggestions, Play chords / inversions / voicings (block, strum, arpeggio, humanized), Scale lock, Hold, Strum shipped app/RhytmixCard.qml
Groover take the groove of one clip (Copy / Humanize / Shuffle / Auto / Templates) and write a new clip with that feel shipped app/GrooverCard.qml, app/src/groover_controller.cpp
Step sequencer + grids melodic step grid, drum grid, synth grid, piano roll shipped app/StepSequencer.qml, PianoRoll.qml

4. Effects

33 built-in effects (plugins/src/device_preset.cpp → track_effect_ids()), all with factory presets and per-effect preset save/load:

Group Effects
Time nebula.delay, nebula.pingpong, nebula.comb, nebula.stutter, nebula.haas
Space nebula.reverb, nebula.convolutionreverb
Tone nebula.eq, nebula.autofilter, nebula.tremolo, nebula.autopan, nebula.vibrato
Dynamics nebula.compressor, nebula.multibandcompressor, nebula.gate, nebula.expander, nebula.transientshaper, nebula.deesser, nebula.limiter, nebula.lookaheadlimiter, nebula.utility
Drive / colour nebula.distortion, nebula.saturator, nebula.wavefolder, nebula.bitcrusher
Modulation / pitch nebula.chorus, nebula.flanger, nebula.phaser, nebula.ringmod, nebula.octave, nebula.pitchshifter, nebula.vocoder, nebula.granular
Feature What it does State Evidence
Per-track effect chains add / remove / reorder / bypass, per-device preset shipped app/DevicesPanel.qml, devices.* API
Master chain the same chain on the master, with a mastering card and a Key row shipped app/MasteringCard.qml
Sidechain / key any keyable device can be keyed from another track (compressor ducking, gates); works offline and live, on tracks, buses and the master shipped (0.3.0-alpha.270–272) services/src/sidechain_plan.cpp, tests/services/test_sidechain*.cpp
Latency compensation devices that report latency (look-ahead limiter) are aligned; PDC across tracks shipped nebula.lookaheadlimiter (latency_samples()), engine PDC tests
Note effects per-track MIDI note-effect chains (arp/scale/etc.) with a picker and settings shipped app/NoteEffectsCard.qml
Analysers spectrum + loudness readings from the real render shipped app/AnalyserCard.qml

5. The audio engine

Feature What it does State Evidence
Audio backends WASAPI (Windows), ALSA (Linux), device pick, sample rate, buffer size, exclusive mode shipped docs/implementation/asio.md, settings audio.*
Audio input record and monitor an input, audio tracks and audio clips shipped addAudioClip, app/AudioSection.qml
Transport play/stop, metronome, loop range, position, tempo shipped TransportBar.qml, transport.* API
Tempo map tempo events, beat ↔ sample conversion shipped TempoMap, project_file tempo_events
Offline render render the project (whole or a range) to audio, run-to-run bit-identical shipped services/src/project_renderer.cpp, docs/adr/0022-project-to-audio-bridge.md
Live backing render the app renders what you hear in the background and swaps it in shipped app/src/render_worker.cpp
Live device state across rebuilds editing a knob no longer restarts a device: delay tails, envelope levels, oscillator phase and held notes survive a palette rebuild shipped on Windows (0.3.0-alpha.272); open Linux defect — see below engine/include/nebula/engine/node_cache.h, tests/engine/test_node_cache.cpp
Real-time safety no locks on the audio callback (audited, mutex by mutex), NEBULA_NONBLOCKING annotations, allocation-tripwire tests on Windows, RealtimeSanitizer + ThreadSanitizer jobs on Linux shipped docs/architecture/rt-lock-audit.md, tests/core/test_rt_safety.cpp
Multi-core render scheduler the offline renderer renders independent tracks at once, in waves that respect sidechain keys, and sums in one fixed order; the thread count cannot change the samples (measured 3.58x on four cores, 691 ms -> 193 ms) shipped (0.3.0-alpha.275) engine/include/nebula/engine/render_pool.h, services/src/project_renderer.cpp, ADR-0028
Export WAV (16/24/32-bit) and MP3 (LAME loaded at run time, never linked) shipped engine/src/audio_file.cpp, libmp3lame.dll in the package

6. The project model and files

Feature What it does State Evidence
Command bus + undo/redo every edit is a command, undoable, with history info shipped model/src/command_bus.cpp, history.* API
Project file .nebproj versioned JSON, unknown-field preservation, migrations shipped model/src/project_file.cpp
Autosave + crash recovery auto-saved copy restored after a kill, with a recovery dialog shipped projects/recovery.nebproj, app/Main.qml recover dialog
Atomic writes + rolling backups a kill during a save cannot corrupt the file; .bak1, .bak2, … shipped core::write_file_atomically, rotate_project_backups
Command-replay journal — not built (deliberately: atomic writes + recovery already meet the criterion) docs/plan/phases.md P3 note (AC-0281/AC-0283)
Kit file .nebkit save/load a Drum Rack's pads, relocatable shipped saveKitToFile / loadKitFromFile
Settings file only non-default values are stored; portable with --data-dir shipped core/src/settings.cpp
Sample import drag a WAV into the Sampler / a Drum Rack pad; slices shipped tracks.setSamplerSample, sliceToDrumRack

7. Automation and performance helpers

Feature What it does State Evidence
Automation curves draw a knob's curve on a lane, per track shipped app/AutomationLane.qml
Automation recording arm knobs, record a pass while the transport runs, written back into curves shipped app/AutomationPanel.qml, sampleArmedKnobs
Clip swing per-clip swing amount shipped clips.setSwing
Humanize / feel via Groover templates shipped groover_controller.cpp
Scale lock / chord modes keep notes in key, one key = a chord, inversions and voicings shipped RhytmixCard.qml

8. MIDI

Feature What it does State Evidence
MIDI input several keyboards at once, hot-plug, per-device enable shipped app/MidiSection.qml
Hardware mapping a unified CC map shared by all devices, learn-by-moving shipped settings midi.cc_map
Computer keyboard play notes from the typing keyboard (A–K, Z/X octave) shipped PianoKeys.qml, help strip
MIDI out the notes the song plays and the 24-ticks-a-beat clock go out of a chosen MIDI port, so external gear plays along and follows the transport; Start/Continue/Stop with the transport shipped (0.3.0-alpha.274) engine/include/nebula/engine/midi_out_queue.h, engine/src/midi_winmm.cpp / midi_alsa.cpp, app/src/midi_controller.cpp, ADR-0027
MIDI out — not built per-track routing to different ports, CC automation on the way out, clock input, timing finer than the 4 ms drain planned (Phase 11) ADR-0027

| MIDI clock input | Nebula follows external gear: pick an input as the clock source and the transport follows start/continue/stop, song position and the smoothed tempo; free-running when the clock stops | shipped (0.3.0-alpha.278) | ADR-0030 | | MTC | MIDI Timecode in and out, including exact 29.97 drop-frame, with a frame-rate setting | shipped (0.3.0-alpha.278) | ADR-0030 | | Program change + per-track MIDI channel | program change in selects a track's preset and out is emitted when it changes; each track has its own MIDI channel | shipped (0.3.0-alpha.278) | ADR-0030 | | MPE | per-note member channels: each note keeps its own bend/pressure/CC74 with its own voice, +/-48 semitones, in and out | shipped (0.3.0-alpha.278) | ADR-0031 | | Lua controller scripts | a sandboxed Lua 5.4.8 host that turns MIDI input into actions through MIDI learn's own path; scripts folder + enable switch + Reload | shipped (0.3.0-alpha.278) | ADR-0031 | | Multi-core LIVE mixer | playback renders independent tracks in parallel waves on a real-time-safe fork/join; the mix is bit-identical at any thread count (3.13x measured) | shipped (0.3.0-alpha.278) | ADR-0028 |

9. The Control API, OSC and the AI/MCP path

Feature What it does State Evidence
Local Control API JSON-RPC 2.0 over a localhost socket, token-guarded, 64 methods (app.ping, project.*, tracks.*, clips.*, devices.*, transport.*, history.*, instruments.*), events pushed to the client (nebula/render.finished, nebula/project.changed) shipped docs/adr/0024-control-api-v1.md, app/src/api_controller.cpp
Off by default the API is opt-in (settings → Local API), token generated per machine, localhost only shipped core/src/settings.cpp api.*
OSC door the same actions over UDP for hardware controllers shipped api_server/src/osc.cpp
Every API action is a command scripts get exactly the undoable edits the UI makes — an AI cannot do more than a script could shipped ADR-0023 rule 4
Headless render from a script project.renderToWav renders in the background and reports the written path shipped api_controller.cpp
AI assistant plugin (chat panel that drives the app: compose from a prompt, arrange, mix, export, build instruments) — planned, closed-source add-on — deliberately outside the open repo docs/plan/ai-plugin.md
MCP server an MCP server as a client of the same API door planned ADR-0024 ("the MCP server as a client of this same door")

Fixed in 0.3.0-alpha.273 (was a measured limitation on 2026-11-01): instruments.list and devices.catalogue never answered — their replies are bigger than the 8 KiB wire line and, unlike other oversized replies, the error came back with "id": null, so a client matching replies by id waited for an answer that had already arrived. Two changes: the server now carries the request's id on every reply (including "the reply is too long" and an internal error), and both methods answer a page — {"instruments": [...], "total": 291, "offset": 0} — so offset += items.size() walks the whole catalogue. Measured on the fixed build: a 156-entry page in 0.02 s, 291/291 instruments walked, 33 devices in two pages; instruments.list also takes limit and withPresets (46 entries per page with presets). (api_server/src/api_server.cpp, app/src/api_controller.cpp, tests/api_server/test_api_server.cpp, tests/app/test_api_controller.cpp.)

10. Content library

Feature What it does State Evidence
Content Library browser presets, kits, one-shots, loops, demo projects from a library folder with an index.json shipped services/src/content_catalog.cpp, app/BundleCard.qml
One-shot bundle the CC0 one-shot kit (33 sounds) generated into the data folder, exportable for publishing shipped --export-one-shots, examples/gen_one_shots.cpp
Kit loading load a library kit onto a Drum Rack (copies its samples into the project) shipped loadContentKit
Starter library 2 kits, 4 one-shots, 2 presets, 1 demo project shipped (sample library; the full library is a separate repo) Nebula-Sound-System-Content-Library/index.json

11. Quality gates, CI and release discipline

Feature What it does State Evidence
Test suites Windows 1225 cases, Linux 907 (six Qt-free suites + the app suite) shipped tests/, PROGRESS.md
Performance gates startup to first frame < 3000 ms, idle CPU < 1 %, RAM < 300 MB — measured every packaging run shipped tools/package.ps1 (measured 2174 ms / 0.55 % / 261 MB at alpha.272)
QML sweep 36 documented screens opened headlessly; any QML runtime error fails the package shipped tools/package.ps1 sweep list
Documentation guards 67 probes over the docs/layers/themes/shortcuts/API/… shipped tools/check_guards_selftest.py
Licence compliance REUSE lint over every file (539/539 at alpha.272) shipped reuse lint
Fault plants break a guard on purpose, prove the test catches it, restore practice recorded in PROGRESS.md per release
CI Gitea Actions (Windows + Linux), local runs when the runner is busy shipped .gitea/workflows/ci.yml
Release discipline one feature per release, an AC id per unit, CHANGELOG/PROGRESS/CHANGELOG-ARCH/HANDOFF updated, both remotes pushed with tag parity practice PROGRESS.md, docs/standards/versioning.md

12. Not built / known gaps (say these out loud)

Not a defect — an inconsistent incremental build (2026-11-02, explained the same day). One Linux build failed the two audible node-cache tail cases in tests/services/test_live_state.cpp (tail rms = 0 after a palette rebuild). A CLEAN build of the same sources passes (the whole services suite: 268 cases), as does a rebuild, and as does the code under ASan/UBSan at -O1 and -O3; Windows is green (1226/1226). The "adding a print fixes it" observation is explained: the print was in a HEADER (node.h), which forces every dependent translation unit to recompile and thereby repaired the inconsistent build. The mechanism: rsync -a preserves the Windows source mtimes, which can be OLDER than the WSL object files, so ninja silently skips rebuilding them and the mirror runs a binary that does not match its sources. Rule: rebuild cleanly before reporting a cross-platform failure; only a failure that survives a clean build is a code defect. The probe recipe stays in the repo skill (references/control-api-rig-and-capture.md) in case it ever returns.

Gap Note
macOS build script only; no Mac in the toolchain, no CI job, no CoreMIDI input, no signing/notarisation. Unverified, not claimed.
AI assistant plugin planned, closed source, outside the open repo (docs/plan/ai-plugin.md).
MCP server mcp/ — a stdio MCP server (Python, the official SDK) exposing 11 tools over the existing Control API; a render tool waits for nebula/render.finished and answers with the file. Verified against the running app (AC-0334) shipped (0.3.0-alpha.276) mcp/, ADR-0029
MIDI output — per-track ports, CC out, timing SHIPPED (0.3.0-alpha.278): per-track output ports, CC 7/CC 10 automation out, clock input (see the rows below), and a configurable drain with measured jitter shipped ADR-0027, ADR-0034
Command-replay journal deliberately not built (atomic writes + crash recovery cover the need).
Plug-in hosting CLAP hosting SHIPPED (0.3.0-alpha.278): discovery, a host node with knobs/PDC latency/state, SEH containment. VST3 is NOT supported and cannot be (GPLv3-or-proprietary SDK vs FSL); LV2/AU and a plug-in GUI are not built. Out-of-process hosting (32-bit / foreign licences) ships as the bridge. ADR-0032, ADR-0033
Translations skeleton only; no translated UI ships yet.

Updated 2026-11-03

An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.