Phase 31: add CLAP, VST2 and VST3 mono effect hosting

This commit is contained in:
Johannes Findeisen 2026-10-27 17:34:46 +01:00
commit 9e0e4562d7
114 changed files with 10369 additions and 75 deletions

View file

@ -272,3 +272,10 @@ removal. Override `PREFIX`, `exec_prefix`, `bindir`, `libdir`, `includedir`,
`datarootdir`, `datadir`, `docdir`, `pkgconfigdir`, `licensedir`, `examplesdir` or
`desktopdir` as needed. `DESTDIR` adds staging separately; pass the same layout
to uninstall. See RELEASING.md for commands and RELEASE_NOTES.md for upgrades.
Phase 31 modern plugin adapters build in C99 using the pinned header-only CLAP
and VST3 C APIs under third_party; there is no network build or SDK runtime.
VST2 compatibility uses original ABI declarations. `make test-modern-plugins`
runs original shared-library fixtures without a server; `make test-gui-modern-plugins`
adds GUI/browser/undo/reopen tests under Xvfb. The fixtures also run in `make test`
and therefore in sanitizer/release builds. Notices are installed with LICENSE.

View file

@ -22,7 +22,7 @@
plus baseline and at most one reserved metadata snapshot; GUI edits reserve
history before mutation/publication. Media is
never removed by undo/delete. Broad screen-reader/accessibility testing is pending.
- Format v10 reads v1–v9 and uses relative local media references. External absolute
- Format v11 reads v1–v10 and uses relative local media references. External absolute
media/module paths need manual repair after relocation. Saving does not bundle
media; missing media stays referenced, missing plugins reject GUI installation.
Unknown data is rejected rather than stripped. Post-rename directory-sync errors
@ -73,3 +73,11 @@ The project format is Linux/POSIX oriented; absolute plugin paths, architecture,
ABI and JACK/device configuration must be supplied on another system. Unknown
fields are rejected, not preserved. See PROJECT_FORMAT.md for versions 1–10 and
RECOVERY.md for save failures after rename.
Phase 31 CLAP/VST2/VST3 loading supports Linux binary modules, one-input mono
float32 zero-latency effects at default configuration. No modern parameter edit,
automation, programs, opaque state, MIDI/instruments, transport, custom editor,
workers, sidechains or true stereo/multichannel buses are implemented. Plugin
bundles must be opened at their actual Linux shared-library binary. Only original
ABI fixtures are qualified; arbitrary third-party modern plugins remain untested.
See PLUGIN_HOSTING.md and decision 0010 for lifecycle and licensing boundaries.

View file

@ -2,7 +2,8 @@
The repository's original code, example and documentation are under the MIT
license in LICENSE (copyright Johannes Findeisen). No energyXT source, artwork,
external plugin SDK, vendored DSP or binary asset is included. The source archive
proprietary SDK, vendored DSP or plugin binary is included. Phase 31 vendors
permissively licensed ABI headers with their own notices. The source archive
contains repository files and an export manifest; it does not bundle system
libraries. Installation includes LICENSE and these documents.
@ -54,3 +55,19 @@ GPL-2.0-or-later). Testing/loading a user-installed module does not grant the ri
to bundle or relicense it. Redistributors must review each chosen module and the
combined distribution's obligations separately; xtc's MIT grant covers only its
original code. No third-party plugin is included in source archives or installs.
## Phase 31 pinned header dependencies
CLAP headers are MIT, copyright Alexandre BIQUE, from upstream commit
`a47f6badb49d948fd009998f28309cdab78979c9`. The generated VST3 C ABI header is
BSD-3-Clause, copyright Steinberg Media Technologies GmbH, from commit
`93a116f7c6c52a317ec3aaee9b13789068b5234e`. Exact licenses are retained under
third_party and installed as CLAP-LICENSE / VST3-C-API-LICENSE. These are header
specifications only: no external runtime SDK or network build step was added.
Review updates explicitly; do not assume future revisions share the same license.
The VST2 compatibility declarations and all three ABI fixtures are original MIT
repository code; no Steinberg VST2 SDK or third-party plugin is bundled. Hosting
an installed binary is distinct from SDK, trademark and plugin redistribution
rights. Review those separately for any proposed distribution. Source archives
retain upstream notices; binary installs also ship both header licenses.

View file

@ -204,3 +204,56 @@ live-sine CC maps without changing plugin state records. Direct static edits do
not override existing lanes. Live CCs do not map to plugins; missing targets or
modules fail without installing partial state. See CONTROL.md for timing,
precedence, reset and backward-jump behavior.
## Phase 31: CLAP, VST2 and VST3 effect loaders
**File → Load plugin** now detects LADSPA, CLAP, VST2 and VST3 entry points in an
explicit trusted Linux module. **Insert plugin on selected wire** and **Replace
selected plugin** use the same browser and transactional graph preparation. The
identity/editor dialog names the format and stable ID. Existing LADSPA controls
and automation continue to work. Modern effects currently use their default
configuration: the editor shows identity but no editable parameters.
Choose the actual binary: `.clap` for CLAP, a VST2 `.so` exporting `VSTPluginMain`,
or a VST3 bundle's `Contents/<architecture>-linux/<module>.so` exporting
`ModuleEntry`, `ModuleExit` and `GetPluginFactory`. The chooser does not resolve
bundle directories or recursively scan plugin folders. On Linux this avoids
executing unrelated plugins just to discover one selected module. Auto-detection
prefers CLAP, then VST2, then VST3, otherwise LADSPA; the C API also provides
`xtc_plugin_probe_format` for an explicit format.
The modern subset is **one mono audio input and one mono output, float32, default
configuration, zero reported latency**. Stereo graph playback uses independent
instances. True stereo/multichannel/sidechain buses, instruments, MIDI/events,
custom editors, parameter changes/automation, programs/presets, opaque state,
transport/time information, workers and latency compensation are not implemented
for these three formats. Modern metadata with controls/automation is rejected,
not silently ignored. VST3 event buses and CLAP note ports are rejected. Plugins
requiring unsupported host extensions may refuse initialization. This is not a
claim that all CLAP/VST2/VST3 plugins will load or sound identically after updates.
Only original effect fixtures have been qualified for the new formats. Trusted
plugin code is in-process and can crash/hang or violate realtime rules. No plugin
binary is included in packages. A VST2 ABI adapter does not provide rights to the
discontinued SDK or plugin redistribution. See decision 0010 and LICENSES.md.
The control/main thread owns discovery, activation, module reference accounting,
retirement and unloading. CLAP's start-processing call runs on the audio owner;
main-thread callbacks are coalesced and serviced via `xtc_plugin_idle` (GUI timer,
currently 100 ms). C hosts using CLAP must pump that API on their serialized main
thread while instances live, and stop/join audio before destruction. Restart and
VST2 I/O-change requests make subsequent blocks fail/silence; stop and rebuild or
reload the plugin rather than reconfiguring inside the callback. CLAP process
errors and VST3 failure results silence a block. VST2 has no process error return.
```sh
make all test gui test-modern-plugins test-gui-modern-plugins
make test-sanitize analyze
```
Original CLAP/VST2/VST3 shared-library fixtures exercise exact in-place and stereo
processing, entry/instance lifetimes, rejected layouts, partial initialization,
CLAP start/process failures, graph replacement rollback, 50 plan retirements per
format, missing modules, v11 save/reopen and GUI add/browser/undo/reopen. Host
allocation/loading/unloading guards remain active while rendering. This evidence
qualifies the subset above, not arbitrary external plugins or physical audio.

View file

@ -1,6 +1,6 @@
# Project format v10 (reads v1–v9)
# Project format v11 (reads v1–v10)
Phases 5–28 use a bounded text format implemented in C99 without a parser library.
Phases 5–31 use a bounded text format implemented in C99 without a parser library.
The extension is `.xtc`. File operations run exclusively on the control thread.
The project owns its graph, tracks and silent/audio arrangement regions. Audio samples remain in external WAV
files; MIDI notes are stored inline.
@ -12,7 +12,7 @@ Fields use ASCII spaces. Integers are unsigned decimal, without signs.
Counts determine the number of subsequent records:
```text
XTC_PROJECT 10
XTC_PROJECT 11
APP 0 1 0
TEMPO 120000
IDS 1 1
@ -104,8 +104,8 @@ node types 1..4, migrating their clips to empty asset paths. Version 2 accepts
node types 1..5 and ASSET records. Both migrate to MIDI=0 and no notes.
Version 3 accepts instrument nodes and MIDI/NOTES records. Versions 1–3 migrate
all tracks to unity gain, centered pan, mute/solo off and no automation.
Saving always writes v10. Unknown versions are rejected without replacing the destination; older
applications without v10 support cannot read current saves. Migration and maximum-path roundtrips are tested.
Saving always writes v11. Unknown versions are rejected without replacing the destination; older
applications without v11 support cannot read current saves. Migration and maximum-path roundtrips are tested.
## Ownership and failures
@ -254,7 +254,7 @@ v9 exact roundtrips and malformed routing.
## Phase 26: version 10 interpolation and controller bindings
The current writer emits v10 and reads v1–v9. Track/bus automation points are
Phase 26 introduced v10 with migration from v1–v9. Track/bus automation points are
`POINT track_id parameter tick value_bits step`, where step is 0 linear or 1
hold for the segment starting there. v1–v9 points migrate to step=0. LADSPA
`PARAM` encoding remains unchanged (already has interpolation mode).
@ -274,8 +274,8 @@ must rebuild and initialize the appended `xtc_automation_point.step` field.
## Phase 28 compatibility and diagnostic contract
The current reader accepts versions 1–10 and the writer always emits version 10.
There is no format change in Phase 28. Saving an older document upgrades it;
The current reader accepts versions 1–11 and the writer always emits version 11.
Phase 28 made no format change; Phase 31 adds plugin format identity in v11. Saving an older document upgrades it;
retain an original backup if an older application must still open it. APP is
informational; compatibility depends on the format version, not the producer's
application version. A future incompatible schema requires a new format number.
@ -337,3 +337,33 @@ preserve the old bytes and remove the temporary. After rename, a sync failure
reports I/O while leaving a complete new document; inspect it before retrying.
Fault wrappers are linked into tests only. These tests complement killed-writer
coverage in `make test-recovery`; they do not qualify power-cut behavior.
## Phase 31: version 11 plugin format identity
Immediately after every plugin MODULE record, v11 requires:
```text
FORMAT format_number hex_identity_or_dash
```
0 = LADSPA, 1 = CLAP, 2 = VST2, 3 = VST3. Identity is `-` for LADSPA/VST2;
CLAP uses its stable plugin ID (1–127 non-NUL bytes); VST3 uses the 32-character lowercase
hex class ID string, itself hex-encoded like other byte strings. PLUGIN's unique
ID remains the VST2/LADSPA integer ID (zero for CLAP/VST3), descriptor index and
label. MODULE is still the actual absolute binary path. Versions 1–10 migrate
to format 0 and empty extra identity. Older readers reject v11. The public plugin
struct has grown; C/C++ consumers must rebuild and initialize it to zero.
Modern adapters accept one-input mono effects, default configuration only, with
zero controls and automation points. Unsupported modern control metadata is
rejected, not discarded. State/editor/preset changes are not exposed, so no opaque
state is serialized. Reloading recreates plugin defaults, which can change after
a plugin update or with its external configuration. Matching ID/name/layout is
not a binary hash or sound-reproducibility guarantee. See PLUGIN_HOSTING.md.
Metadata validation and inspection never initialize modules. Actual graph
preparation verifies format, descriptor, stable identity, name and layout before
publishing. Missing module metadata survives C load/save; GUI preparation retains
the existing document on failure. No automatic path search or plugin substitution
occurs. Current and historical migration fixtures, malformed fields, identity
mismatch, missing-module and exact-render roundtrips cover this extension.

View file

@ -1,6 +1,6 @@
# Persistence and failure recovery
The project format is v10. Readers migrate v1–v9, validate bounded input
The project format is v11. Readers migrate v1–v10, validate bounded input
and atomically install a candidate only after complete success. Existing tests
cover exact migration/roundtrip, truncations, malformed references, counts,
IDs, nonfinite values and failed GUI/backend installation. Native processors
@ -87,5 +87,12 @@ rename and directory-sync errors. Pre-rename failures retain the previous bytes
and clean temporary files. Post-rename sync errors leave a complete new file and
return failure; there is no rollback after replacement. Load diagnostics identify
the expected record and syntax line, or line zero for whole-model/I/O stages.
Unknown versions report the supported range (1–10); unknown records/fields are
Unknown versions report the supported range (1–11); unknown records/fields are
rejected without partially changing the current project.
Modern CLAP/VST2/VST3 module identity is preserved in v11 metadata even when the
binary is unavailable. Restore the compatible saved binary path and retry Open.
CLAP restart and VST2 I/O-change requests fail/silence subsequent blocks; stop
and rebuild/reload rather than attempting callback-time reconfiguration. Modern
instances restart at default configuration; no edited opaque state is exposed
or saved by the initial adapters. Trusted plugin crashes cannot be contained.

View file

@ -15,7 +15,7 @@ undo/redo and a generic LADSPA editor. JACK is the only live audio/MIDI backend;
core validation and offline rendering work without it. Native/LADSPA processors
are trusted in-process code. No proprietary energyXT resources are included.
Project format v10 reads versions 1–10 transactionally. Syntax diagnostics identify
Project format v11 reads versions 1–11 transactionally. Syntax diagnostics identify
records and lines. `xtc-check --inspect` lists dependency paths without executing
plugins. Phase 29 adds timing/CPU/RSS reports, repeatable stress runs and virtual
endurance. Phase 30 adds configurable install directories, shared install/remove
@ -24,7 +24,7 @@ inventory, installed MIDI examples and source archive checksum sidecars.
## Upgrading and removal
Back up documents and external media before upgrading. Opening an older project
does not rewrite it; saving upgrades it to v10, which older readers may reject.
does not rewrite it; saving upgrades it to v11, which older readers may reject.
Use Save As for a separate migrated copy. Moving a project folder preserves media
stored inside it via relative references. Absolute media and plugin module paths
must be restored separately. There is no bundled plugin/media migration or saved
@ -51,3 +51,9 @@ the shared development host; the project timing comparison passed. This alert
was not hidden by changing the baseline. See PERFORMANCE.md before using these
measurements as latency expectations. Sanitizers and virtual endurance qualify
software paths, not hardware timing.
Phase 31 adds default-configuration CLAP/VST2/VST3 mono effect loaders, common
GUI discovery/insertion/replacement and v11 format identity. Pinned MIT CLAP and
BSD-3-Clause VST3 C headers ship with notices; VST2 uses original compatibility
declarations. Modern instruments, parameters/state/editors and multichannel
layouts remain unsupported. No third-party modern plugin has been qualified.

View file

@ -860,6 +860,45 @@ byte-identical binaries and repacks; and binary manifest/hash/relocation checks.
No public release, tag, version bump or system install is performed. Physical
qualification and the Phase 29 graph timing alert remain documented limitations.
## Phase 31 — CLAP, VST2 and VST3 Plugin Loading
### Goal
Load trusted Linux CLAP, VST2 and VST3 audio effects through the graph and GUI,
with explicit lifecycle, format compatibility and realtime ownership contracts.
### Tasks
- Review and pin redistributable ABI headers and license notices; keep C99 adapters.
- Add explicit format probing and compatible mono float32 effect initialization.
- Integrate processing, immutable plans, retirement and failure rollback.
- Share module entry lifetimes across overlapping instances; defer main-thread callbacks.
- Add format/stable identity metadata with v11 migration and missing-module retention.
- Generalize the GUI browser, insertion/replacement and identity presentation.
- Test original fixtures for all three ABIs, partial failure cleanup, callback safety,
save/reopen, missing dependencies and GUI lifecycle.
- Document the initial default-configuration effect subset and unsupported extensions.
### Acceptance criteria
- Compatible fixtures for all three formats render exact expected audio in graphs.
- Failed loading/identity/layout/initialization retains the current project/plan.
- Loading and reclamation remain off the audio callback, with bounded host processing.
- Project files preserve identity and missing references without executing plugins.
- Core/GUI builds, regressions, sanitizers and release installation checks pass.
### Implementation status
Implemented in C99 with pinned permissive ABI headers, shared entry lifetimes,
CLAP main-thread scheduling, graph/GUI integration and v11 plugin identity.
Normal/minimal builds, core and GUI plugin fixtures, live JACK/workflow,
ASan/UBSan core and GUI checks, static analysis, staged installation and
source/binary release checks pass. Tests include activation/start/process and
restart errors, rejected layouts/identities, missing modules and retirement.
GUI leak checking retains only the existing Fontconfig suppression; core checks
use none. Only original ABI fixtures are qualified; arbitrary third-party plugins
and physical audio remain unverified. See PLUGIN_HOSTING.md and decision 0010.
The initial subset excludes instruments/events, editable modern parameters,
opaque state/custom editors, true stereo/multichannel and latency compensation.
These require separate future work; they are not claimed as implemented by loading.
---
## Recommended Execution Order

View file

@ -160,3 +160,11 @@ or starting JACK. Exit codes: 0 = valid metadata and available files, 2 = missin
or unreadable references, 1 = metadata/I/O error. File availability does not
certify WAV contents or plugin compatibility. See [PROJECT_FORMAT.md](PROJECT_FORMAT.md)
for the compatibility and relocation policy.
Phase 31: **File → Load plugin** supports LADSPA plus an initial Linux
CLAP/VST2/VST3 effect subset. Select the actual module binary (`.clap` or `.so`,
including a VST3 bundle's inner binary). Modern effects require one mono input
and output, float32 and zero latency; they use default configuration. Instruments,
modern parameter editing/automation, opaque state and custom editors are not
implemented. Projects now save v11 and read v1–v11. See PLUGIN_HOSTING.md for the
full contract and test/qualification limits.

View file

@ -0,0 +1,42 @@
# 0010 — Bounded CLAP, VST2 and VST3 effect loading
Accepted for Phase 31. The user's request to support these three formats
supersedes the earlier recommendation to choose only one external format.
Keep the engine/model/host adapters in C99. CLAP uses pinned MIT headers and VST3
uses the upstream BSD-3-Clause generated C ABI. No SDK runtime library is needed;
Linux dynamic loading and POSIX thread identity are existing platform facilities.
VST2 uses original minimal compatibility declarations, not the discontinued SDK.
See third_party/README.md and LICENSES.md for exact revisions and notices.
Reuse the existing plugin graph node, paired mono instances and immutable plan
ownership. The common facade routes LADSPA to its existing implementation and
modern formats to a separate adapter. This preserves LADSPA controls/automation
and metadata behavior. All three new adapters initially accept one mono input
and output, float32, zero reported latency and no event buses. Default plugin
configuration is used; no parameter/controller/editor or opaque-state access is
exposed. These are usable effect loaders, not complete implementations of every
extension in the formats. Unsupported layouts fail explicitly.
Project v11 adds format plus CLAP stable ID or VST3 class ID to each saved plugin.
Older plugins migrate to LADSPA with an empty extra ID. VST2 retains its integer
unique ID. Reopening checks format/index/identity/name/layout; metadata operations
never open modules. This does not authenticate a binary or freeze defaults across
plugin releases. No modified opaque state exists in this initial API to persist.
Discovery and instance creation execute trusted module code on one serialized
main/control thread. A module cache balances CLAP entry init/deinit and Linux
VST3 ModuleEntry/ModuleExit across overlapping graph instances and retired plans.
CLAP start_processing runs on the processing owner; stop_processing runs after
quiescence with the symbolic audio-thread context. CLAP callback requests use
lock-free flags and are serviced by xtc_plugin_idle on main/control (the GUI timer
calls it). Restart/I/O-change requests latch an error for re-preparation; the audio
callback does not reconfigure or wait for GUI work. CLAP process wakeups need no
queue because playback processes every block, including silence.
Only preallocated buffers and plugin processing occur in audio. Error status
silences the failed block; nonfinite/subnormal samples are sanitized. Plugin code
can still allocate, block, corrupt memory or crash; there is no sandbox, scanner
subprocess or recoverable crash boundary. Modules unload only after destruction
on a quiescent/control owner. Real third-party plugins and hardware timing remain
unqualified; original ABI fixtures demonstrate the bounded contracts.