Phase 25: improve LADSPA discovery, parameter editing and plugin lifecycle

This commit is contained in:
Johannes Findeisen 2026-10-27 16:24:21 +01:00
commit 7bff7b535d
18 changed files with 591 additions and 42 deletions

View file

@ -30,13 +30,17 @@ LADSPA 1.1 host. `xtc_plugin.h` is the C API; no C++ engine or FLTK type is need
1. Choose **File → Load LADSPA plugin** and a trusted absolute `.so` path. Loading
executes native code immediately, including constructors during discovery.
2. The dialog lists compatible descriptor indices/labels. Select an index.
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
other effect; effects have an optional mono input. Unconnected effect inputs
receive external input, as other graph processors do.
4. Select its node and use **Edit → Selected plugin control**. The dialog shows
actual port IDs, names, values and rate-adjusted ranges. Enter a port and value.
Toggled controls require 0/1 and integer controls require integral values.
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.
5. Save normally, reopen, reconnect external JACK playback if needed, and Play.
Plugin changes stop/rebuild playback and participate in ordinary undo/redo.
@ -103,3 +107,89 @@ bundled or installed by the target):
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.
## Phase 25: 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. Built-in MIDI synthesis remains the only GUI MIDI
instrument. 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.
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.
Reset defaults in the editor previews every control's declared/default-derived
value. Apply also clears that plugin's automation; Cancel preserves it. The
**Edit → Reset selected plugin** command does the same in one undo step. The
public control-thread `xtc_plugin_reset` can reset one port (removing only its
lane) or UINT32_MAX for all controls. Automation otherwise overrides static
values, so editing a static control does not remove an existing lane.
`xtc_plugin_describe` returns copied name/maker/copyright (bounded/truncated),
parameter ranges/defaults and integer/toggle/logarithmic/sample-rate/boundedness
flags. Missing maker/copyright receive explicit fallback labels. LADSPA has no
standard unit metadata: unit stays empty and the editor says unspecified rather
than guessing Hz/dB from names. Numeric inputs use linear parameter values;
logarithmic is a descriptor hint, not an extra host conversion. Unbounded ends
are labeled unbounded; finite float extrema remain the validation bounds.
Sample-rate hints scale bounds and defaults once at the engine's actual rate;
nonrepresentable scaled bounds are rejected. Discrete defaults are rounded and
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.
### Compatibility and recovery
LADSPA 1.1 descriptor identity is module path + index + label + unique ID, with
exact supported port/control layout verified on restore. A unique ID is not a
binary version/hash guarantee. Parameter values and bounded automation persist
in existing project v9 records; this phase adds no file format change. Transient
history/tails and opaque state remain unsupported. Native processor ABI 2 and
its exact `struct_size` contract are unchanged; it remains parameter-only state.
Consumers rebuild against public headers; the new copied details API adds no
callbacks or GUI types to the C core.
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
contain crashes, hangs, memory corruption or prohibited work inside a plugin.
Only trusted in-process plugins are supported. See RECOVERY.md.
### Phase 25 verification
Fixture tests cover copied identity/hints, integer and toggle defaults and range
rejection, logarithmic/sample-rate hints, scaled-range overflow rejection, reset
and unchanged-on-error behavior, parameter/automation save/reopen and exact
rendering. Noncommutative gain/offset effects prove that graph order changes
output as expected. GUI tests drive the actual chooser/editor, reset/Apply and
Cancel, replacement layout/init/missing-module rollback, insertion/stale-wire
failure, deletion and undo. Existing fixture tests exercise 100 live plan
replacements with host allocation/free/dlopen/dlclose guards. Native ABI tests
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.