xtc/docs/decisions/0010-modern-plugin-effects.md
2026-11-06 15:20:20 +01:00

2.7 KiB

0010 — Bounded CLAP, VST2 and VST3 Effect Loading

Accepted. 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.