Docs file normalization.

This commit is contained in:
Johannes Findeisen 2026-11-06 15:20:20 +01:00
commit 619c2d0808
46 changed files with 3587 additions and 2579 deletions

View file

@ -1,4 +1,4 @@
# External plugin hosting evaluation
# External Plugin Hosting Evaluation
The original decision deferred external hosting. The native source API is useful
for proving processor contracts without adding an SDK or scanning/loading code.
@ -9,27 +9,32 @@ for proving processor contracts without adding an SDK or scanning/loading code.
| CLAP | C ABI, explicit lifecycle and event model | Extension negotiation, parameter/state persistence, host callbacks, main/audio-thread scheduling and UI integration |
| VST3 | Broad plugin availability | SDK/license review for the selected SDK release, C++ adapter outside the C core, component/controller and editor lifecycle, state and event translation |
No candidate was linked, scanned or loaded. API/SDK and plugin
licenses must be checked at the revision actually adopted; they are separate
from xtc's MIT license. Supporting a format does not grant redistribution rights
to individual plugins. Do not search user plugin directories from the callback.
No candidate was linked, scanned or loaded. API/SDK and plugin licenses must be
checked at the revision actually adopted; they are separate from xtc's MIT
license. Supporting a format does not grant redistribution rights to individual
plugins. Do not search user plugin directories from the callback.
Before implementation, require versioned module identity and state, a missing-
plugin recovery policy, preparation failure/partial cleanup tests, bounded events
and parameter publication, latency/tail handling, callback-safe unload after
retirement, a GUI/main-thread boundary and an explicit crash-containment decision.
Native ABI tests cover some ownership mechanics but do not prove third-party
code safe. Event graph ports remain a gap; track instrument selection is described below.
Choose one format with concrete user needs after those contracts are specified;
do not introduce a general multi-format framework now. See decision 0008.
plugin recovery policy, preparation failure/partial cleanup tests, bounded
events and parameter publication, latency/tail handling, callback-safe unload
after retirement, a GUI/main-thread boundary and an explicit crash-containment
decision. Native ABI tests cover some ownership mechanics but do not prove
third-party code safe. Event graph ports remain a gap; track instrument
selection is described below. Choose one format with concrete user needs after
those contracts are specified; do not introduce a general multi-format framework
now. See decision 0008.
## LADSPA implementation (supersedes the earlier deferral)
---
Decision [0009](decisions/0009-parameter-processors-and-ladspa.md) selects a bounded
LADSPA 1.1 host. `xtc_plugin.h` is the C API; no C++ engine or FLTK type is needed.
## LADSPA Implementation (Supersedes the Earlier Deferral)
1. Choose **File → Load LADSPA plugin** and a trusted absolute `.so` path. Loading
executes native code immediately, including constructors during discovery.
Decision [0009](decisions/0009-parameter-processors-and-ladspa.md) selects a
bounded LADSPA 1.1 host. `xtc_plugin.h` is the C API; no C++ engine or FLTK type
is needed.
1. Choose **File → Load LADSPA plugin** and a trusted absolute `.so` path.
Loading executes native code immediately, including constructors during
discovery.
2. The descriptor browser lists names, labels, makers and source/effect roles.
Select a row and Choose. Counts report compatible and skipped descriptors.
3. In the Modular Graph, connect the new source/effect output to an output or
@ -37,18 +42,19 @@ LADSPA 1.1 host. `xtc_plugin.h` is the C API; no C++ engine or FLTK type is need
receive external input, as other graph processors do.
4. Select its node and use **Edit → Selected plugin control**. The editor shows
name, maker, copyright, module path, descriptor index and unique ID, then
actual port IDs, editable values, rate-adjusted bounds, defaults and discrete/
logarithmic hints. Apply validates all values and candidate initialization;
Cancel and window close preserve the document. Toggled controls require 0/1
and integer controls require integral values.
actual port IDs, editable values, rate-adjusted bounds, defaults and
discrete/ logarithmic hints. Apply validates all values and candidate
initialization; Cancel and window close preserve the document. Toggled
controls require 0/1 and integer controls require integral values.
5. Save normally, reopen, reconnect external JACK playback if needed, and Play.
Plugin changes stop/rebuild playback and participate in ordinary undo/redo.
The GUI uses only public graph/model/plugin APIs. Discovery probes explicit module
files by descriptor index, bounded to 1024 descriptors. It never recursively scans
system directories. The C API exposes probe, parameter metadata, instance
create/process/destroy, and add/get/set graph configuration. Missing header means
hosting returns UNSUPPORTED; metadata persistence continues to work.
The GUI uses only public graph/model/plugin APIs. Discovery probes explicit
module files by descriptor index, bounded to 1024 descriptors. It never
recursively scans system directories. The C API exposes probe, parameter
metadata, instance create/process/destroy, and add/get/set graph configuration.
Missing header means hosting returns UNSUPPORTED; metadata persistence continues
to work.
Supported: 0/1 audio input, 1 output, <=64 total ports and <=16 input controls.
Stereo graph channels are two independent mono instances. Stereo/multichannel
@ -65,22 +71,25 @@ incompatible identity/range/layout, or instantiate returning NULL unwinds the
candidate and leaves active/pending plans intact. Only run and bounded host
buffer copies execute in audio. Destruction and unloading happen after callback
quiescence or retirement acknowledgement on the control thread. Transport reset
retains LADSPA history; compile/reopen starts fresh. A LADSPA run callback has no
error return. Nonfinite/subnormal samples become zero, but native crashes,
retains LADSPA history; compile/reopen starts fresh. A LADSPA run callback has
no error return. Nonfinite/subnormal samples become zero, but native crashes,
corruption, runaway CPU, allocations or I/O inside a plugin cannot be contained
or prevented. Use trusted plugins; hard-realtime properties are declarations,
not proof. This is an in-process host, not a crash-isolation service.
Project v5 stores absolute module path, index, label, LADSPA unique ID, mono input
count and ordered input-control port/value pairs. Restore verifies identity,
layout, parameter ports and ranges against the loaded module. No pointers are
serialized. Relocating a module requires restoring it at its saved absolute path
or deliberately modifying its metadata through a C client. GUI Open reports the
missing/incompatible identity/path and retains the current document. Metadata
load/save and `xtc-check --validate` do not execute plugin code and do not certify
module availability. LADSPA IDs are not cryptographic binary/version identities.
Project v5 stores absolute module path, index, label, LADSPA unique ID, mono
input count and ordered input-control port/value pairs. Restore verifies
identity, layout, parameter ports and ranges against the loaded module. No
pointers are serialized. Relocating a module requires restoring it at its saved
absolute path or deliberately modifying its metadata through a C client. GUI
Open reports the missing/incompatible identity/path and retains the current
document. Metadata load/save and `xtc-check --validate` do not execute plugin
code and do not certify module availability. LADSPA IDs are not cryptographic
binary/version identities.
## Repeatable acceptance
---
## Repeatable Acceptance
```sh
make all test gui test-plugins test-gui-plugins analyze
@ -91,9 +100,10 @@ The first plugin target builds an original MIT shared-library fixture with gain,
source, unsupported stereo and failed-initialization descriptors. Tests exercise
identity/range errors, exact in-place gain, save/reopen/exact rendering, missing
module metadata preservation and 100 plan replacements with callback guards
against host allocation/free/dlopen/dlclose. GUI commands cover add, control edit,
invalid-value rollback, undo/redo and save/New/reopen. ASan/UBSan/leak checks cover
host/fixture lifetimes; plugin code from system packages is not instrumented.
against host allocation/free/dlopen/dlclose. GUI commands cover add, control
edit, invalid-value rollback, undo/redo and save/New/reopen. ASan/UBSan/leak
checks cover host/fixture lifetimes; plugin code from system packages is not
instrumented.
`test-plugins-real` requires these separately installed modules (nothing is
bundled or installed by the target):
@ -108,32 +118,35 @@ Tested packages: ladspa 1.17-7 and swh-plugins 0.4.17-7. These zero-latency
processors define the initial compatible set; other plugins remain unqualified.
Physical listening and plugin CPU/endurance qualification remain pending.
## Discovery, editing and graph lifecycle
---
## Discovery, Editing and Graph Lifecycle
Discovery remains explicit-file only, bounded to 1024 descriptor indices; no
recursive scan, plugin database or new dependency is introduced. Unsupported
layouts are skipped with counts; source/effect roles describe audio ports, not
MIDI instrument capabilities. Modern track instruments are described below. LADSPA sources can be identified, edited, replaced and removed in
the graph but cannot receive MIDI events.
MIDI instrument capabilities. Modern track instruments are described below.
LADSPA sources can be identified, edited, replaced and removed in the graph but
cannot receive MIDI events.
**Edit → Insert LADSPA on selected wire** replaces one existing connection with
`source -> effect -> destination`, as one undo step. Only one-input effects are
accepted; stale wires, capacity failures and initialization failures retain the
original graph. **Edit → Replace selected plugin** accepts the same audio input
layout, keeps the node ID and all wires, and installs the new descriptor's default
controls with no inherited automation. It can replace from another module.
A source/effect layout mismatch is rejected. Undo restores the old identity,
values and automation. Every candidate is compiled before adoption even when
the backend is disconnected; no intermediate graph is published.
layout, keeps the node ID and all wires, and installs the new descriptor's
default controls with no inherited automation. It can replace from another
module. A source/effect layout mismatch is rejected. Undo restores the old
identity, values and automation. Every candidate is compiled before adoption
even when the backend is disconnected; no intermediate graph is published.
Ordering is graph signal flow, not descriptor order, creation order or a flat
rack. Use the graph's connection/disconnection tools to place effects in series
or parallel. Insertion on a wire preserves its endpoints and changes only that
stage. Select a plugin and Delete to remove it and incident wires, then reconnect
as desired; deletion does not automatically bridge or sum routes. A now-unwired
effect receives external audio, following existing graph semantics. Undo/redo
restores removal and routing. Independent bus inserts are still outside the
shared-source graph model.
stage. Select a plugin and Delete to remove it and incident wires, then
reconnect as desired; deletion does not automatically bridge or sum routes. A
now-unwired effect receives external audio, following existing graph semantics.
Undo/redo restores removal and routing. Independent bus inserts are still
outside the shared-source graph model.
Reset defaults in the editor previews every control's declared/default-derived
value. Apply also clears that plugin's automation; Cancel preserves it. The
@ -156,8 +169,8 @@ validated; impossible defaults fail discovery rather than reaching the engine.
The generic modal editor owns copied metadata and temporary widget values only.
It never owns or retains module handles, descriptors or audio instance pointers.
Closing it cannot unload active DSP; Apply builds a new immutable plan before
installation and existing retirement/quiescence rules release old instances.
No embedded third-party editor UI is supported.
installation and existing retirement/quiescence rules release old instances. No
embedded third-party editor UI is supported.
### Compatibility and recovery
@ -174,8 +187,8 @@ Missing/incompatible modules reject GUI Open with the offending label/path and
leave the current project intact. Restore a compatible module at that path and
retry; use metadata-only validation/save to preserve an unavailable module's
records. No dummy replacement silently removes its controls. Failed discovery,
replacement or instantiate reports an error and retains the current document.
A LADSPA `run` callback has no error return; finite-sample sanitation does not
replacement or instantiate reports an error and retains the current document. A
LADSPA `run` callback has no error return; finite-sample sanitation does not
contain crashes, hangs, memory corruption or prohibited work inside a plugin.
Only trusted in-process plugins are supported. See RECOVERY.md.
@ -193,71 +206,83 @@ cover process-error silence/reset. The separately installed amp/inverter/sine
modules remain the qualified LADSPA set. Human listening, arbitrary third-party
editors/plugins and extended realtime endurance remain unverified.
## Parameter targets
---
## Parameter Targets
`xtc_control.h` supplies common stable owner/parameter IDs and control-thread
metadata/edit APIs for track/bus gain/pan and LADSPA input ports. The GUI's plugin
automation command uses this contract. Linear/hold LADSPA encoding and its
integer/toggle restrictions remain unchanged; v10 adds mixer interpolation and
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,
metadata/edit APIs for track/bus gain/pan and LADSPA input ports. The GUI's
plugin automation command uses this contract. Linear/hold LADSPA encoding and
its integer/toggle restrictions remain unchanged; v10 adds mixer interpolation
and 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.
## 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.
## CLAP, VST2 and VST3 Effect Loaders
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.
**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.
The modern subset is **one mono audio input and one mono output, float32, default
configuration, zero reported latency**. Stereo graph playback uses independent
instances. For the modern effect subset, 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
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. For the modern effect subset, 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.
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.
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.
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.
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.
## Instrument support
---
## Instrument Support
MIDI tracks can bind CLAP, VST2 and VST3 instruments. In the Track menu, select
**Load instrument plugin** for the selected sequencer track; **Use built-in
@ -268,9 +293,9 @@ their own track's instrument. Independent instances feed track gain/pan,
mute/solo, bus routing and automation. Bindings/live target save in v12.
Supply the actual trusted Linux binary (including the inner .so of a VST3
bundle). Supported instruments have zero audio inputs, one mono output,
float32 processing, zero latency and one note/event input. Default configuration
only: no custom editor, opaque state/preset restoration, modern parameter
bundle). Supported instruments have zero audio inputs, one mono output, float32
processing, zero latency and one note/event input. Default configuration only:
no custom editor, opaque state/preset restoration, modern parameter
editing/automation, stereo/multichannel instruments or MIDI output. No arbitrary
third-party instrument is qualified by the original ABI fixture tests.