Phase 31: add CLAP, VST2 and VST3 mono effect hosting
This commit is contained in:
parent
90eac33a71
commit
9e0e4562d7
114 changed files with 10369 additions and 75 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Retain upstream header/license snapshots byte-for-byte.
|
||||
third_party/** -whitespace
|
||||
31
Makefile
31
Makefile
|
|
@ -27,7 +27,7 @@ CXXFLAGS ?= -O2 -g
|
|||
CXXFLAGS += -std=c++17 -Wall -Wextra -Wpedantic -Iinclude
|
||||
LDFLAGS ?=
|
||||
|
||||
CORE_SOURCES := src/control/model.c src/audio/waveform.c src/plugin/ladspa.c src/native/processor.c src/audio/recovery.c src/dsp/ramp.c src/native/native.c src/mixer/model.c src/mixer/render.c src/project/history.c src/midi/model.c src/midi/instrument.c src/audio/wave.c src/audio/arrangement.c src/audio/recorder.c src/core/xtc.c src/project/project.c src/persistence/project_file.c src/graph/graph.c src/dsp/gain.c src/engine/offline_engine.c src/engine/realtime.c src/backend/jack_backend.c
|
||||
CORE_SOURCES := src/control/model.c src/audio/waveform.c src/plugin/ladspa.c src/plugin/host.c src/plugin/modern.c src/native/processor.c src/audio/recovery.c src/dsp/ramp.c src/native/native.c src/mixer/model.c src/mixer/render.c src/project/history.c src/midi/model.c src/midi/instrument.c src/audio/wave.c src/audio/arrangement.c src/audio/recorder.c src/core/xtc.c src/project/project.c src/persistence/project_file.c src/graph/graph.c src/dsp/gain.c src/engine/offline_engine.c src/engine/realtime.c src/backend/jack_backend.c
|
||||
JACK_AVAILABLE := $(shell $(PKG_CONFIG) --exists jack 2>/dev/null && echo yes)
|
||||
ifeq ($(JACK_AVAILABLE),yes)
|
||||
JACK_CFLAGS := $(shell $(PKG_CONFIG) --cflags jack)
|
||||
|
|
@ -461,3 +461,32 @@ test-stress-plugins: $(BUILD_DIR)/test_realtime $(BUILD_DIR)/test_reliability $(
|
|||
.PHONY: test-install-layout
|
||||
test-install-layout: all $(if $(GUI_AVAILABLE),gui)
|
||||
$(PYTHON) tests/integration/test_install.py --build-dir "$(abspath $(BUILD_DIR))" --custom-layout $(if $(GUI_AVAILABLE),--gui)
|
||||
|
||||
$(BUILD_DIR)/src/plugin/modern.o: override CPPFLAGS += -isystem third_party/clap/include -isystem third_party/vst3
|
||||
|
||||
$(BUILD_DIR)/clap-fixture.clap: tests/plugins/clap_fixture.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -isystem third_party/clap/include $(LDFLAGS) -fPIC -shared -o $@ $<
|
||||
$(BUILD_DIR)/vst2-fixture.so: tests/plugins/vst2_fixture.c src/plugin/vst2_abi.h
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -fPIC -shared -o $@ $<
|
||||
$(BUILD_DIR)/vst3-fixture.so: tests/plugins/vst3_fixture.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -isystem third_party/vst3 $(LDFLAGS) -fPIC -shared -o $@ $<
|
||||
$(BUILD_DIR)/test_modern_plugins: $(BUILD_DIR)/tests/integration/test_modern_plugins.o $(BUILD_DIR)/libxtc.a
|
||||
$(CC) $(LDFLAGS) -o $@ $^ -lm -ldl -Wl,--wrap=malloc,--wrap=calloc,--wrap=realloc,--wrap=free,--wrap=dlopen,--wrap=dlclose
|
||||
.PHONY: test-modern-plugins
|
||||
test-modern-plugins: $(BUILD_DIR)/test_modern_plugins $(BUILD_DIR)/clap-fixture.clap $(BUILD_DIR)/vst2-fixture.so $(BUILD_DIR)/vst3-fixture.so
|
||||
./$(BUILD_DIR)/test_modern_plugins "$(abspath $(BUILD_DIR))/clap-fixture.clap" "$(abspath $(BUILD_DIR))/vst2-fixture.so" "$(abspath $(BUILD_DIR))/vst3-fixture.so"
|
||||
test: test-modern-plugins
|
||||
-include $(BUILD_DIR)/tests/integration/test_modern_plugins.d
|
||||
|
||||
.PHONY: test-gui-modern-plugins
|
||||
ifeq ($(GUI_AVAILABLE),yes)
|
||||
test-gui-modern-plugins: $(BUILD_DIR)/test_gui $(BUILD_DIR)/clap-fixture.clap $(BUILD_DIR)/vst2-fixture.so $(BUILD_DIR)/vst3-fixture.so
|
||||
XTC_TEST_CLAP="$(abspath $(BUILD_DIR))/clap-fixture.clap" XTC_TEST_VST2="$(abspath $(BUILD_DIR))/vst2-fixture.so" XTC_TEST_VST3="$(abspath $(BUILD_DIR))/vst3-fixture.so" xvfb-run -a -s "-screen 0 1280x800x24" ./$(BUILD_DIR)/test_gui
|
||||
else
|
||||
test-gui-modern-plugins:
|
||||
@echo "FLTK development files are required for modern plugin GUI tests."
|
||||
@exit 1
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -161,3 +161,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](docs/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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
42
docs/decisions/0010-modern-plugin-effects.md
Normal file
42
docs/decisions/0010-modern-plugin-effects.md
Normal 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.
|
||||
|
|
@ -11,6 +11,9 @@ extern "C" {
|
|||
typedef struct xtc_app xtc_app;
|
||||
#define XTC_FEATURE_JACK 1U
|
||||
#define XTC_FEATURE_LADSPA 2U
|
||||
#define XTC_FEATURE_CLAP 4U
|
||||
#define XTC_FEATURE_VST2 8U
|
||||
#define XTC_FEATURE_VST3 16U
|
||||
/* Compile-time capabilities, no loading/server connection or I/O. */
|
||||
unsigned int xtc_build_features(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef enum { XTC_PLUGIN_LADSPA = 0, XTC_PLUGIN_CLAP, XTC_PLUGIN_VST2, XTC_PLUGIN_VST3 } xtc_plugin_format;
|
||||
const char *xtc_plugin_format_name(xtc_plugin_format format);
|
||||
#define XTC_PLUGIN_CONTROLS 16U
|
||||
#define XTC_PLUGIN_POINTS 32U
|
||||
/* Absolute project ticks. Mode belongs to segment starting at this point:
|
||||
|
|
@ -11,17 +13,21 @@ extern "C" {
|
|||
* sample rounding collides. Integer/toggle controls require mode 1. */
|
||||
typedef struct { uint64_t tick; unsigned int port, step; float value; } xtc_plugin_point;
|
||||
/* Plain copied model: no library handles or callback pointers. Absolute trusted
|
||||
* module path, descriptor index + unique ID + label checked again on compile.
|
||||
* Controls are actual LADSPA port indices, in ascending order. */
|
||||
* binary path, format/index/integer or string identity/label verified on compile.
|
||||
* Controls are LADSPA port indices; modern effects use default configuration
|
||||
* with zero controls/points. Initialize the complete struct to zero. */
|
||||
typedef struct {
|
||||
char path[512], label[64];
|
||||
xtc_plugin_format format;
|
||||
char identifier[128]; /* CLAP stable ID / VST3 class hex; empty for LADSPA/VST2. */
|
||||
unsigned int index, unique_id, inputs, control_count;
|
||||
unsigned int ports[XTC_PLUGIN_CONTROLS];
|
||||
float values[XTC_PLUGIN_CONTROLS];
|
||||
unsigned int tempo, point_count; /* milli-BPM, 20000..300000 */
|
||||
xtc_plugin_point points[XTC_PLUGIN_POINTS];
|
||||
} xtc_plugin_spec;
|
||||
/* Copied discovery metadata, never descriptor/module pointers. LADSPA provides
|
||||
/* Copied discovery metadata, never descriptor/module pointers. Modern adapters
|
||||
* currently expose the name only (zero controls). LADSPA provides
|
||||
* no standardized units; unit is empty. Flags describe input control hints. */
|
||||
#define XTC_PLUGIN_INTEGER 1U
|
||||
#define XTC_PLUGIN_TOGGLED 2U
|
||||
|
|
@ -44,9 +50,14 @@ xtc_result xtc_plugin_reset(xtc_plugin_spec *spec, double rate, unsigned int por
|
|||
* are accepted, preserving all wires. Metadata-only; compile before adoption. */
|
||||
xtc_result xtc_graph_replace_plugin(xtc_graph *graph, size_t id, const xtc_plugin_spec *spec);
|
||||
typedef struct xtc_plugin xtc_plugin;
|
||||
/* Control thread only. Probe explicitly enumerates a file by descriptor index;
|
||||
/* Serialized control/main thread: service CLAP callback requests. */
|
||||
void xtc_plugin_idle(void);
|
||||
/* Serialized main/control thread only (also create/destroy/idle). Probe explicitly
|
||||
* enumerates a Linux binary file by descriptor index;
|
||||
* NOT_FOUND means end, UNSUPPORTED means descriptor/layout unsupported. Loading
|
||||
* trusted libraries can execute arbitrary constructors. Never probe in audio. */
|
||||
xtc_result xtc_plugin_probe_format(xtc_plugin_format format, const char *path, unsigned int index, double rate, xtc_plugin_spec *out);
|
||||
/* Auto-detect exported entry point; may execute module constructors. */
|
||||
xtc_result xtc_plugin_probe(const char *path, unsigned int index, double rate, xtc_plugin_spec *out);
|
||||
/* Control-thread parameter names, computed ranges/defaults at this sample rate.
|
||||
* Output has spec->control_count entries; IDs are LADSPA port indices. */
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define XTC_PROJECT_FORMAT_VERSION 10U
|
||||
#define XTC_PROJECT_FORMAT_VERSION 11U
|
||||
#define XTC_PROJECT_MAX_TRACKS 64U
|
||||
#define XTC_PROJECT_MAX_CLIPS 1024U
|
||||
#define XTC_PROJECT_NAME_BYTES 64U
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ Name: xtc
|
|||
Description: Modular C audio engine and project library
|
||||
Version: @VERSION@
|
||||
Requires.private: @JACK@
|
||||
Libs: -L"${libdir}" -lxtc -lm -ldl
|
||||
Libs: -L"${libdir}" -lxtc -lm -ldl -pthread
|
||||
Cflags: -I"${includedir}"
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void xtc_app_destroy(xtc_app *app)
|
|||
|
||||
unsigned int xtc_build_features(void)
|
||||
{
|
||||
unsigned int features = 0;
|
||||
unsigned int features = XTC_FEATURE_CLAP | XTC_FEATURE_VST2 | XTC_FEATURE_VST3;
|
||||
#ifdef XTC_HAVE_JACK
|
||||
features |= XTC_FEATURE_JACK;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -590,7 +590,8 @@ xtc_result xtc_graph_set_plugin(xtc_graph *g, size_t id, const xtc_plugin_spec *
|
|||
if (i == SIZE_MAX) return XTC_ERR_NOT_FOUND;
|
||||
if (g->nodes[i].type != XTC_NODE_PLUGIN) return XTC_ERR_INVALID_ARGUMENT;
|
||||
/* Parameter edits cannot replace identity/layout or invalidate wiring. */
|
||||
if (strcmp(s->path,g->nodes[i].plugin.path) || strcmp(s->label,g->nodes[i].plugin.label) ||
|
||||
if (s->format != g->nodes[i].plugin.format || strcmp(s->identifier,g->nodes[i].plugin.identifier) ||
|
||||
strcmp(s->path,g->nodes[i].plugin.path) || strcmp(s->label,g->nodes[i].plugin.label) ||
|
||||
s->index != g->nodes[i].plugin.index || s->unique_id != g->nodes[i].plugin.unique_id ||
|
||||
s->inputs != g->nodes[i].plugin.inputs || s->control_count != g->nodes[i].plugin.control_count ||
|
||||
memcmp(s->ports,g->nodes[i].plugin.ports,s->control_count*sizeof(*s->ports))) return XTC_ERR_UNSUPPORTED;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
if (argc == 2 && !std::strcmp(argv[1], "--diagnose")) {
|
||||
unsigned int features = xtc_build_features();
|
||||
std::printf("xtc %s; project formats 1..%u; JACK %s; LADSPA %s\nFor limits and recovery commands run xtc-check --diagnose/--help.\n",
|
||||
std::printf("xtc %s; project formats 1..%u; JACK %s; LADSPA %s; CLAP/VST2/VST3 mono effects compiled\nFor limits and recovery commands run xtc-check --diagnose/--help.\n",
|
||||
XTC_VERSION_STRING,XTC_PROJECT_FORMAT_VERSION,features & XTC_FEATURE_JACK ? "compiled" : "disabled",
|
||||
features & XTC_FEATURE_LADSPA ? "compiled" : "disabled");
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -88,9 +88,9 @@ MainWindow::MainWindow(bool prompt_unsaved)
|
|||
menu->add("Audio/Panic", FL_F + 9, panic_callback, this);
|
||||
menu->add("View/Piano roll", FL_CTRL + '4', piano_callback, this);
|
||||
menu->add("Audio/Record WAV", FL_SHIFT + FL_F + 5, audio_file_callback, this);
|
||||
menu->add("File/Load LADSPA plugin", 0, plugin_callback, this);
|
||||
menu->add("File/Load plugin", 0, plugin_callback, this);
|
||||
menu->add("Edit/Replace selected plugin", 0, plugin_callback, this);
|
||||
menu->add("Edit/Insert LADSPA on selected wire", 0, plugin_callback, this);
|
||||
menu->add("Edit/Insert plugin on selected wire", 0, plugin_callback, this);
|
||||
menu->add("Edit/Reset selected plugin", 0, plugin_callback, this);
|
||||
menu->add("Edit/Selected plugin automation", 0, plugin_callback, this);
|
||||
menu->add("Edit/Selected plugin control", 0, plugin_callback, this);
|
||||
|
|
@ -765,6 +765,7 @@ void MainWindow::about_callback(Fl_Widget *, void *)
|
|||
*/
|
||||
void MainWindow::timer_callback(void *context)
|
||||
{
|
||||
xtc_plugin_idle();
|
||||
auto *window = static_cast<MainWindow *>(context);
|
||||
if (window->recorder_) {
|
||||
xtc_result r = xtc_recorder_drain(window->recorder_);
|
||||
|
|
@ -1579,12 +1580,12 @@ void MainWindow::plugin_callback(Fl_Widget *widget, void *context)
|
|||
xtc_result r;
|
||||
if (std::strcmp(label,"Reset selected plugin") == 0) {
|
||||
r = w->reset_plugin(w->graph_widget_->selected_node());
|
||||
} else if (std::strcmp(label,"Load LADSPA plugin") == 0 ||
|
||||
} else if (std::strcmp(label,"Load plugin") == 0 ||
|
||||
std::strcmp(label,"Replace selected plugin") == 0 ||
|
||||
std::strcmp(label,"Insert LADSPA on selected wire") == 0) {
|
||||
std::strcmp(label,"Insert plugin on selected wire") == 0) {
|
||||
const size_t selected = w->graph_widget_->selected_node();
|
||||
xtc_connection_info wire{};
|
||||
const bool insert = std::strcmp(label,"Insert LADSPA on selected wire") == 0;
|
||||
const bool insert = std::strcmp(label,"Insert plugin on selected wire") == 0;
|
||||
const bool replace = std::strcmp(label,"Replace selected plugin") == 0;
|
||||
if (insert && !w->graph_widget_->selected_connection(wire)) {
|
||||
w->report_error("Select an existing wire before inserting an effect",XTC_ERR_INVALID_STATE); return;
|
||||
|
|
@ -1592,10 +1593,10 @@ void MainWindow::plugin_callback(Fl_Widget *widget, void *context)
|
|||
if (replace) {
|
||||
xtc_plugin_spec old{};
|
||||
r = xtc_graph_get_plugin(xtc_project_graph(w->project_.get()),selected,&old);
|
||||
if (r != XTC_OK) { w->report_error("Select a LADSPA node to replace",r); return; }
|
||||
if (r != XTC_OK) { w->report_error("Select a plugin node to replace",r); return; }
|
||||
}
|
||||
Fl_Native_File_Chooser chooser;
|
||||
chooser.title("Choose trusted LADSPA module (executes native code)"); chooser.filter("LADSPA\t*.so");
|
||||
chooser.title("Choose trusted plugin binary (LADSPA, CLAP, VST2, VST3)"); chooser.filter("Plugin binaries\t*.{so,clap}\nAll files\t*");
|
||||
if (chooser.show() != 0 || !chooser.filename()) return;
|
||||
double rate = 48000; xtc_backend_status status{};
|
||||
if (w->ready_ && xtc_backend_get_status(w->backend_,&status) == XTC_OK) rate = status.sample_rate;
|
||||
|
|
@ -1603,7 +1604,7 @@ void MainWindow::plugin_callback(Fl_Widget *widget, void *context)
|
|||
xtc_plugin_spec probe{};
|
||||
r = xtc_plugin_probe(chooser.filename(),0,rate,&probe);
|
||||
if (r != XTC_OK && r != XTC_ERR_UNSUPPORTED) {
|
||||
w->report_error("Cannot discover LADSPA module; check path, dependencies and ladspa_descriptor export",r); return;
|
||||
w->report_error("Cannot discover plugin; check binary path, format, mono layout and dependencies",r); return;
|
||||
}
|
||||
if (!xtc_choose_plugin(chooser.filename(),rate,index)) return;
|
||||
if (replace) r = w->replace_plugin(selected,chooser.filename(),index);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ struct Dialog : Fl_Double_Window {
|
|||
}
|
||||
bool xtc_choose_plugin(const char *path, double rate, unsigned int &index)
|
||||
{
|
||||
Dialog dialog(760,450,"LADSPA descriptors");
|
||||
Dialog dialog(760,450,"Plugin descriptors");
|
||||
auto *heading = new Fl_Box(15,10,730,40);
|
||||
heading->copy_label(path); heading->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP);
|
||||
auto *list = new Fl_Hold_Browser(15,55,730,325);
|
||||
|
|
@ -56,9 +56,9 @@ bool xtc_edit_plugin(const xtc_plugin_spec &spec, const xtc_plugin_details &deta
|
|||
Dialog dialog(800,600,"Plugin identity and controls");
|
||||
auto *identity = new Fl_Box(15,10,770,125);
|
||||
std::string text = std::string(details.name) + " — " + details.maker + "\n" + spec.label +
|
||||
" | LADSPA ID " + std::to_string(spec.unique_id) + " | descriptor " + std::to_string(spec.index) +
|
||||
" | " + std::string(xtc_plugin_format_name(spec.format)) + " ID " + std::to_string(spec.unique_id) + " | descriptor " + std::to_string(spec.index) + " | identity " + spec.identifier +
|
||||
"\n" + spec.path + "\n" + details.copyright +
|
||||
"\nMetadata verified; Apply validates initialization. Units unspecified by LADSPA.";
|
||||
"\nMetadata verified; Apply validates initialization. Adapter may not expose units or editable controls.";
|
||||
identity->copy_label(text.c_str()); identity->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
|
||||
auto *scroll = new Fl_Scroll(10,140,780,370);
|
||||
std::array<Fl_Value_Input *,XTC_PLUGIN_CONTROLS> inputs{};
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ static int inspect(const xtc_project *project, uint64_t version)
|
|||
xtc_graph_get_node(graph,i,&node);
|
||||
if (xtc_graph_get_plugin(graph,node.id,&spec) == XTC_OK) {
|
||||
int available = readable_file(spec.path);
|
||||
printf("LADSPA node %zu ID %u descriptor %u ",node.id,spec.unique_id,spec.index);
|
||||
printf("%s node %zu ID %u descriptor %u ",xtc_plugin_format_name(spec.format),node.id,spec.unique_id,spec.index);
|
||||
if (spec.identifier[0]) { quoted(spec.identifier); putchar(' '); }
|
||||
quoted(spec.label); printf(": %s ",available ? "available" : "missing/unreadable");
|
||||
quoted(spec.path); putchar('\n');
|
||||
if (!available) ++missing;
|
||||
|
|
@ -86,7 +87,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
if (argc == 2 && !strcmp(argv[1], "--diagnose")) {
|
||||
unsigned int features = xtc_build_features();
|
||||
printf("xtc %s; %zu-bit process\nProject formats: 1..%u\nJACK compiled: %s\nLADSPA compiled: %s\n"
|
||||
printf("xtc %s; %zu-bit process\nProject formats: 1..%u\nJACK compiled: %s\nLADSPA compiled: %s\nCLAP/VST2/VST3: compiled (mono effects, default configuration)\n"
|
||||
"Limits: 256 graph nodes (64/project), %u tracks, %u clips, %u notes, 65536 frames/block\n"
|
||||
"No server, device or plugin probed. Runtime errors appear in GUI status/stderr.\n",
|
||||
XTC_VERSION_STRING,sizeof(void *)*CHAR_BIT,XTC_PROJECT_FORMAT_VERSION,
|
||||
|
|
|
|||
|
|
@ -259,6 +259,12 @@ static xtc_result read_project(reader *input, xtc_project *project, const char *
|
|||
if (!decode_bytes(input->tokens[5],p->label,sizeof(p->label))) return XTC_ERR_FORMAT;
|
||||
READ("MODULE",2U);
|
||||
if (!decode_bytes(input->tokens[1],p->path,sizeof(p->path))) return XTC_ERR_FORMAT;
|
||||
if (format_version >= 11U) {
|
||||
READ("FORMAT",3U); NUM(1U,value);
|
||||
if (value > XTC_PLUGIN_VST3) return XTC_ERR_UNSUPPORTED;
|
||||
p->format = (xtc_plugin_format)value;
|
||||
if (strcmp(input->tokens[2],"-") && !decode_bytes(input->tokens[2],p->identifier,sizeof(p->identifier))) return XTC_ERR_FORMAT;
|
||||
}
|
||||
for (k = 0; k < p->control_count; ++k) {
|
||||
READ("CONTROL",3U); NUM(1U,value);
|
||||
if (value >= 64 || !decode_float(input->tokens[2],p->values+k)) return XTC_ERR_FORMAT;
|
||||
|
|
@ -506,6 +512,7 @@ static xtc_result write_project(FILE *file, const xtc_project *project, const ch
|
|||
if (xtc_plugin_spec_validate(p) != XTC_OK) return XTC_ERR_FORMAT;
|
||||
if (fprintf(file,"PLUGIN %u %u %u %u ",p->unique_id,p->index,p->inputs,p->control_count) < 0 ||
|
||||
!write_name(file,p->label) || fputs("MODULE ",file) == EOF || !write_name(file,p->path)) return XTC_ERR_IO;
|
||||
if (fprintf(file,"FORMAT %u ",(unsigned int)p->format) < 0 || (p->identifier[0] ? !write_name(file,p->identifier) : fputs("-\n",file) == EOF)) return XTC_ERR_IO;
|
||||
for (k = 0; k < p->control_count; ++k) {
|
||||
uint32_t value; memcpy(&value,p->values+k,4);
|
||||
if (fprintf(file,"CONTROL %u %08" PRIx32 "\n",p->ports[k],value) < 0) return XTC_ERR_IO;
|
||||
|
|
|
|||
108
src/plugin/host.c
Normal file
108
src/plugin/host.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include "modern.h"
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
typedef struct xtc_ladspa_plugin xtc_ladspa_plugin;
|
||||
xtc_result xtc_ladspa_probe(const char *, unsigned int, double, xtc_plugin_spec *);
|
||||
xtc_result xtc_ladspa_describe(const xtc_plugin_spec *, double, xtc_plugin_details *);
|
||||
xtc_result xtc_ladspa_create(const xtc_plugin_spec *, double, size_t, xtc_ladspa_plugin **);
|
||||
void xtc_ladspa_destroy(xtc_ladspa_plugin *);
|
||||
xtc_result xtc_ladspa_process_at(xtc_ladspa_plugin *, const float *, float *, size_t, uint64_t);
|
||||
struct xtc_plugin { xtc_ladspa_plugin *ladspa; xtc_modern *modern; uint64_t next; };
|
||||
const char *xtc_plugin_format_name(xtc_plugin_format f)
|
||||
{ static const char *names[] = {"LADSPA", "CLAP", "VST2", "VST3"}; return f >= 0 && f <= XTC_PLUGIN_VST3 ? names[f] : "Unknown"; }
|
||||
xtc_result xtc_plugin_probe_format(xtc_plugin_format f, const char *path, unsigned int index, double rate, xtc_plugin_spec *out)
|
||||
{
|
||||
xtc_modern *p = NULL; xtc_result r;
|
||||
if (!out || !path || path[0] != '/' || strlen(path) >= 512 || index >= 1024 || !isfinite(rate) || rate < 1 || rate > 768000)
|
||||
return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (f == XTC_PLUGIN_LADSPA) return xtc_ladspa_probe(path,index,rate,out);
|
||||
if (f < XTC_PLUGIN_CLAP || f > XTC_PLUGIN_VST3) return XTC_ERR_INVALID_ARGUMENT;
|
||||
r = xtc_modern_open(f,path,index,rate,256,&p,out);
|
||||
xtc_modern_destroy(p); return r;
|
||||
}
|
||||
xtc_result xtc_plugin_probe(const char *path, unsigned int index, double rate, xtc_plugin_spec *out)
|
||||
{
|
||||
void *module; xtc_plugin_format f = XTC_PLUGIN_LADSPA;
|
||||
if (!path || path[0] != '/' || strlen(path) >= 512) return XTC_ERR_INVALID_ARGUMENT;
|
||||
module = dlopen(path,RTLD_NOW | RTLD_LOCAL);
|
||||
if (!module) return XTC_ERR_NOT_FOUND;
|
||||
if (dlsym(module,"clap_entry")) f = XTC_PLUGIN_CLAP;
|
||||
else if (dlsym(module,"VSTPluginMain")) f = XTC_PLUGIN_VST2;
|
||||
else if (dlsym(module,"GetPluginFactory")) f = XTC_PLUGIN_VST3;
|
||||
dlclose(module);
|
||||
return xtc_plugin_probe_format(f,path,index,rate,out);
|
||||
}
|
||||
xtc_result xtc_plugin_describe(const xtc_plugin_spec *s, double rate, xtc_plugin_details *out)
|
||||
{
|
||||
xtc_plugin_spec actual; xtc_result r;
|
||||
if (!out || xtc_plugin_spec_validate(s) != XTC_OK) return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (s->format == XTC_PLUGIN_LADSPA) return xtc_ladspa_describe(s,rate,out);
|
||||
r = xtc_plugin_probe_format(s->format,s->path,s->index,rate,&actual);
|
||||
if (r != XTC_OK) return r;
|
||||
if (actual.unique_id != s->unique_id || strcmp(actual.identifier,s->identifier) || strcmp(actual.label,s->label)) return XTC_ERR_UNSUPPORTED;
|
||||
memset(out,0,sizeof(*out)); snprintf(out->name,sizeof(out->name),"%s",s->label);
|
||||
snprintf(out->maker,sizeof(out->maker),"Not exposed by this adapter");
|
||||
snprintf(out->copyright,sizeof(out->copyright),"See plugin license");
|
||||
return XTC_OK;
|
||||
}
|
||||
void xtc_plugin_destroy(xtc_plugin *p)
|
||||
{ if (p) { xtc_ladspa_destroy(p->ladspa); xtc_modern_destroy(p->modern); free(p); } }
|
||||
xtc_result xtc_plugin_create(const xtc_plugin_spec *s, double rate, size_t frames, xtc_plugin **out)
|
||||
{
|
||||
xtc_plugin *p; xtc_result r; xtc_plugin_spec actual;
|
||||
if (!out) return XTC_ERR_INVALID_ARGUMENT;
|
||||
*out = NULL;
|
||||
r = xtc_plugin_spec_validate(s); if (r != XTC_OK) return r;
|
||||
if (!frames || frames > 65536 || !isfinite(rate) || rate < 1 || rate > 768000) return XTC_ERR_INVALID_ARGUMENT;
|
||||
p = calloc(1,sizeof(*p)); if (!p) return XTC_ERR_OUT_OF_MEMORY;
|
||||
if (s->format == XTC_PLUGIN_LADSPA) r = xtc_ladspa_create(s,rate,frames,&p->ladspa);
|
||||
else {
|
||||
r = xtc_modern_open(s->format,s->path,s->index,rate,frames,&p->modern,&actual);
|
||||
if (r == XTC_OK && (actual.unique_id != s->unique_id || actual.inputs != s->inputs ||
|
||||
strcmp(actual.identifier,s->identifier) || strcmp(actual.label,s->label))) r = XTC_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (r != XTC_OK) { xtc_plugin_destroy(p); return r; }
|
||||
*out = p; return XTC_OK;
|
||||
}
|
||||
xtc_result xtc_plugin_process_at(xtc_plugin *p, const float *in, float *out, size_t frames, uint64_t position)
|
||||
{
|
||||
xtc_result r;
|
||||
if (!p) return XTC_ERR_INVALID_ARGUMENT;
|
||||
r = p->modern ? xtc_modern_process(p->modern,in,out,frames) : xtc_ladspa_process_at(p->ladspa,in,out,frames,position);
|
||||
if (r == XTC_OK) p->next = position <= UINT64_MAX-frames ? position+frames : 0;
|
||||
return r;
|
||||
}
|
||||
xtc_result xtc_plugin_process(xtc_plugin *p, const float *in, float *out, size_t frames)
|
||||
{ return xtc_plugin_process_at(p,in,out,frames,p ? p->next : 0); }
|
||||
xtc_result xtc_plugin_parameters(const xtc_plugin_spec *s, double rate, xtc_parameter_info out[XTC_PLUGIN_CONTROLS])
|
||||
{
|
||||
xtc_plugin_details details;
|
||||
xtc_result r;
|
||||
if (!out) return XTC_ERR_INVALID_ARGUMENT;
|
||||
r = xtc_plugin_describe(s,rate,&details);
|
||||
if (r == XTC_OK) memcpy(out,details.parameters,sizeof(details.parameters));
|
||||
return r;
|
||||
}
|
||||
xtc_result xtc_plugin_reset(xtc_plugin_spec *s, double rate, unsigned int port)
|
||||
{
|
||||
xtc_plugin_details details;
|
||||
xtc_plugin_spec candidate;
|
||||
size_t i, count = 0;
|
||||
int found = port == UINT32_MAX;
|
||||
xtc_result r = xtc_plugin_describe(s,rate,&details);
|
||||
if (r != XTC_OK) return r;
|
||||
candidate = *s;
|
||||
for (i = 0; i < s->control_count; ++i) if (port == UINT32_MAX || s->ports[i] == port) {
|
||||
candidate.values[i] = details.parameters[i].default_value;
|
||||
found = 1;
|
||||
}
|
||||
if (!found) return XTC_ERR_NOT_FOUND;
|
||||
for (i = 0; i < s->point_count; ++i)
|
||||
if (port != UINT32_MAX && s->points[i].port != port) candidate.points[count++] = s->points[i];
|
||||
candidate.point_count = (unsigned int)count;
|
||||
*s = candidate;
|
||||
return XTC_OK;
|
||||
}
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
#define xtc_plugin xtc_ladspa_plugin
|
||||
#define xtc_plugin_probe xtc_ladspa_probe
|
||||
#define xtc_plugin_describe xtc_ladspa_describe
|
||||
#define xtc_plugin_create xtc_ladspa_create
|
||||
#define xtc_plugin_destroy xtc_ladspa_destroy
|
||||
#define xtc_plugin_process_at xtc_ladspa_process_at
|
||||
#define xtc_plugin_process xtc_ladspa_process
|
||||
#include "xtc/xtc_plugin.h"
|
||||
#include "xtc/xtc_dsp.h"
|
||||
#include "xtc/xtc_project.h"
|
||||
|
|
@ -17,6 +24,20 @@ xtc_result xtc_plugin_spec_validate(const xtc_plugin_spec *s)
|
|||
!terminated(s->label,sizeof(s->label)) || !s->label[0] || s->index >= 1024 ||
|
||||
s->inputs > 1 || s->control_count > XTC_PLUGIN_CONTROLS ||
|
||||
s->tempo < 20000 || s->tempo > 300000 || s->point_count > XTC_PLUGIN_POINTS) return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (s->format < XTC_PLUGIN_LADSPA || s->format > XTC_PLUGIN_VST3 ||
|
||||
!terminated(s->identifier,sizeof(s->identifier))) return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (s->format != XTC_PLUGIN_LADSPA) {
|
||||
if (s->inputs != 1 || s->control_count || s->point_count ||
|
||||
((s->format == XTC_PLUGIN_CLAP || s->format == XTC_PLUGIN_VST3) && !s->identifier[0]))
|
||||
return XTC_ERR_UNSUPPORTED;
|
||||
if (s->format == XTC_PLUGIN_VST2 && s->identifier[0]) return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (s->format == XTC_PLUGIN_VST3) {
|
||||
if (strlen(s->identifier) != 32) return XTC_ERR_INVALID_ARGUMENT;
|
||||
for (i = 0; i < 32; ++i)
|
||||
if (!((s->identifier[i] >= '0' && s->identifier[i] <= '9') ||
|
||||
(s->identifier[i] >= 'a' && s->identifier[i] <= 'f'))) return XTC_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
} else if (s->identifier[0]) return XTC_ERR_INVALID_ARGUMENT;
|
||||
for (i = 0; i < s->control_count; ++i)
|
||||
if (s->ports[i] >= 64 || (i && s->ports[i] <= s->ports[i-1]) || !isfinite(s->values[i]))
|
||||
return XTC_ERR_INVALID_ARGUMENT;
|
||||
|
|
@ -282,33 +303,3 @@ xtc_result xtc_plugin_process_at(xtc_plugin *p, const float *i, float *o, size_t
|
|||
xtc_result xtc_plugin_process(xtc_plugin *p, const float *i, float *o, size_t f)
|
||||
{ (void)p; (void)i; (void)o; (void)f; return XTC_ERR_UNSUPPORTED; }
|
||||
#endif
|
||||
|
||||
xtc_result xtc_plugin_parameters(const xtc_plugin_spec *s, double rate, xtc_parameter_info out[XTC_PLUGIN_CONTROLS])
|
||||
{
|
||||
xtc_plugin_details details;
|
||||
xtc_result r;
|
||||
if (!out) return XTC_ERR_INVALID_ARGUMENT;
|
||||
r = xtc_plugin_describe(s,rate,&details);
|
||||
if (r == XTC_OK) memcpy(out,details.parameters,sizeof(details.parameters));
|
||||
return r;
|
||||
}
|
||||
xtc_result xtc_plugin_reset(xtc_plugin_spec *s, double rate, unsigned int port)
|
||||
{
|
||||
xtc_plugin_details details;
|
||||
xtc_plugin_spec candidate;
|
||||
size_t i, count = 0;
|
||||
int found = port == UINT32_MAX;
|
||||
xtc_result r = xtc_plugin_describe(s,rate,&details);
|
||||
if (r != XTC_OK) return r;
|
||||
candidate = *s;
|
||||
for (i = 0; i < s->control_count; ++i) if (port == UINT32_MAX || s->ports[i] == port) {
|
||||
candidate.values[i] = details.parameters[i].default_value;
|
||||
found = 1;
|
||||
}
|
||||
if (!found) return XTC_ERR_NOT_FOUND;
|
||||
for (i = 0; i < s->point_count; ++i)
|
||||
if (port != UINT32_MAX && s->points[i].port != port) candidate.points[count++] = s->points[i];
|
||||
candidate.point_count = (unsigned int)count;
|
||||
*s = candidate;
|
||||
return XTC_OK;
|
||||
}
|
||||
|
|
|
|||
315
src/plugin/modern.c
Normal file
315
src/plugin/modern.c
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "modern.h"
|
||||
#include "vst2_abi.h"
|
||||
#include "xtc/xtc_dsp.h"
|
||||
#include "xtc/xtc_version.h"
|
||||
#include <clap/clap.h>
|
||||
#include <clap/ext/thread-check.h>
|
||||
#include <vst3_c_api.h>
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Module cache is control-thread owned. Entry initialization is once per loaded
|
||||
* module, even when stereo preparation and retired plans overlap. */
|
||||
typedef struct module {
|
||||
void *handle;
|
||||
xtc_plugin_format format;
|
||||
unsigned int references;
|
||||
const clap_plugin_entry_t *entry;
|
||||
bool (*exit3)(void);
|
||||
struct module *next;
|
||||
} module;
|
||||
static module *modules;
|
||||
struct xtc_modern {
|
||||
module *module;
|
||||
xtc_plugin_format format;
|
||||
const clap_plugin_t *clap;
|
||||
clap_host_t host;
|
||||
xtc_v2_effect *v2;
|
||||
Steinberg_IPluginFactory *factory;
|
||||
Steinberg_Vst_IComponent *component;
|
||||
Steinberg_Vst_IAudioProcessor *processor;
|
||||
float *input, *output;
|
||||
size_t frames;
|
||||
double rate;
|
||||
pthread_t control_thread;
|
||||
int initialized, active, started;
|
||||
unsigned int callback, restart;
|
||||
struct xtc_modern *next;
|
||||
};
|
||||
static xtc_modern *instances;
|
||||
static __thread int in_audio;
|
||||
static __thread xtc_modern *constructing;
|
||||
|
||||
static int symbol(void *handle, const char *name, void *out, size_t size)
|
||||
{
|
||||
void *value = dlsym(handle,name);
|
||||
if (!value || size != sizeof(value)) return 0;
|
||||
memcpy(out,&value,size); return 1;
|
||||
}
|
||||
static void module_release(module *m)
|
||||
{
|
||||
module **slot;
|
||||
if (!m || --m->references) return;
|
||||
for (slot = &modules; *slot && *slot != m; slot = &(*slot)->next) {}
|
||||
if (*slot) *slot = m->next;
|
||||
if (m->entry) m->entry->deinit();
|
||||
if (m->exit3) m->exit3();
|
||||
dlclose(m->handle); free(m);
|
||||
}
|
||||
static xtc_result module_open(xtc_plugin_format format, const char *path, module **out)
|
||||
{
|
||||
void *handle = dlopen(path,RTLD_NOW | RTLD_LOCAL);
|
||||
module *m; xtc_result r = XTC_ERR_UNSUPPORTED;
|
||||
if (!handle) return XTC_ERR_NOT_FOUND;
|
||||
for (m = modules; m; m = m->next) if (m->handle == handle && m->format == format) {
|
||||
++m->references; dlclose(handle); *out = m; return XTC_OK;
|
||||
}
|
||||
m = calloc(1,sizeof(*m));
|
||||
if (!m) { dlclose(handle); return XTC_ERR_OUT_OF_MEMORY; }
|
||||
m->handle = handle; m->format = format; m->references = 1;
|
||||
if (format == XTC_PLUGIN_CLAP) {
|
||||
const clap_plugin_entry_t *entry = dlsym(handle,"clap_entry");
|
||||
if (!entry || !clap_version_is_compatible(entry->clap_version) || !entry->init || !entry->deinit || !entry->get_factory) goto fail;
|
||||
if (!entry->init(path)) { r = XTC_ERR_INVALID_STATE; goto fail; }
|
||||
m->entry = entry;
|
||||
} else if (format == XTC_PLUGIN_VST3) {
|
||||
bool (*entry)(void *) = NULL; bool (*exit_module)(void) = NULL;
|
||||
if (!symbol(handle,"ModuleEntry",&entry,sizeof(entry)) || !symbol(handle,"ModuleExit",&exit_module,sizeof(exit_module))) goto fail;
|
||||
if (!entry(handle)) { r = XTC_ERR_INVALID_STATE; goto fail; }
|
||||
m->exit3 = exit_module;
|
||||
}
|
||||
m->next = modules; modules = m; *out = m; return XTC_OK;
|
||||
fail:
|
||||
module_release(m); return r;
|
||||
}
|
||||
static void request_callback(const clap_host_t *h)
|
||||
{ xtc_modern *p = h->host_data; __atomic_store_n(&p->callback,1U,__ATOMIC_RELEASE); }
|
||||
static void request_restart(const clap_host_t *h)
|
||||
{ xtc_modern *p = h->host_data; __atomic_store_n(&p->restart,1U,__ATOMIC_RELEASE); }
|
||||
static void request_process(const clap_host_t *h) { (void)h; /* Always processed when transport runs. */ }
|
||||
static bool is_main(const clap_host_t *h)
|
||||
{ const xtc_modern *p = h->host_data; return !in_audio && pthread_equal(pthread_self(),p->control_thread); }
|
||||
static bool is_audio(const clap_host_t *h) { (void)h; return in_audio != 0; }
|
||||
static const void *host_extension(const clap_host_t *h, const char *id)
|
||||
{
|
||||
static const clap_host_thread_check_t check = {is_main,is_audio};
|
||||
(void)h; return id && !strcmp(id,CLAP_EXT_THREAD_CHECK) ? &check : NULL;
|
||||
}
|
||||
void xtc_plugin_idle(void)
|
||||
{
|
||||
xtc_modern *p;
|
||||
for (p = instances; p; p = p->next)
|
||||
if (p->clap && __atomic_exchange_n(&p->callback,0U,__ATOMIC_ACQ_REL)) p->clap->on_main_thread(p->clap);
|
||||
}
|
||||
static uint32_t event_count(const clap_input_events_t *list) { (void)list; return 0; }
|
||||
static const clap_event_header_t *event_get(const clap_input_events_t *list, uint32_t index)
|
||||
{ (void)list; (void)index; return NULL; }
|
||||
static bool event_push(const clap_output_events_t *list, const clap_event_header_t *event)
|
||||
{ (void)list; (void)event; return false; }
|
||||
static xtc_result open_clap(xtc_modern *p, unsigned int index, xtc_plugin_spec *s)
|
||||
{
|
||||
const clap_plugin_factory_t *factory = p->module->entry->get_factory(CLAP_PLUGIN_FACTORY_ID);
|
||||
const clap_plugin_descriptor_t *d; const clap_plugin_audio_ports_t *ports;
|
||||
clap_audio_port_info_t info;
|
||||
if (!factory || !factory->get_plugin_count || !factory->get_plugin_descriptor || !factory->create_plugin) return XTC_ERR_UNSUPPORTED;
|
||||
if (index >= factory->get_plugin_count(factory)) return XTC_ERR_NOT_FOUND;
|
||||
d = factory->get_plugin_descriptor(factory,index);
|
||||
if (!d || !clap_version_is_compatible(d->clap_version) || !d->id || !d->name ||
|
||||
!d->id[0] || strlen(d->id) >= sizeof(s->identifier) || !d->name[0]) return XTC_ERR_UNSUPPORTED;
|
||||
snprintf(s->identifier,sizeof(s->identifier),"%s",d->id); snprintf(s->label,sizeof(s->label),"%s",d->name);
|
||||
p->host = (clap_host_t){CLAP_VERSION,p,"xtc","xtc","",XTC_VERSION_STRING,host_extension,request_restart,request_process,request_callback};
|
||||
p->clap = factory->create_plugin(factory,&p->host,d->id);
|
||||
if (!p->clap) return XTC_ERR_INVALID_STATE;
|
||||
if (!p->clap->init || !p->clap->destroy || !p->clap->activate || !p->clap->deactivate ||
|
||||
!p->clap->start_processing || !p->clap->stop_processing || !p->clap->process || !p->clap->get_extension || !p->clap->on_main_thread)
|
||||
return XTC_ERR_UNSUPPORTED;
|
||||
if (!p->clap->init(p->clap)) return XTC_ERR_INVALID_STATE;
|
||||
ports = p->clap->get_extension(p->clap,CLAP_EXT_AUDIO_PORTS);
|
||||
if (!ports || !ports->count || !ports->get || ports->count(p->clap,true) != 1 || ports->count(p->clap,false) != 1 ||
|
||||
!ports->get(p->clap,0,true,&info) || info.channel_count != 1 ||
|
||||
!ports->get(p->clap,0,false,&info) || info.channel_count != 1) return XTC_ERR_UNSUPPORTED;
|
||||
{ const clap_plugin_note_ports_t *notes = p->clap->get_extension(p->clap,CLAP_EXT_NOTE_PORTS);
|
||||
if (notes && (!notes->count || notes->count(p->clap,true) || notes->count(p->clap,false))) return XTC_ERR_UNSUPPORTED; }
|
||||
if (!p->clap->activate(p->clap,p->rate,1,(uint32_t)p->frames)) return XTC_ERR_INVALID_STATE;
|
||||
p->active = 1;
|
||||
{ const clap_plugin_latency_t *latency = p->clap->get_extension(p->clap,CLAP_EXT_LATENCY);
|
||||
if (latency && (!latency->get || latency->get(p->clap))) return XTC_ERR_UNSUPPORTED; }
|
||||
return XTC_OK;
|
||||
}
|
||||
static intptr_t v2_host(xtc_v2_effect *effect, int32_t opcode, int32_t index, intptr_t value, void *ptr, float option)
|
||||
{
|
||||
xtc_modern *p = constructing ? constructing : effect ? effect->user : NULL;
|
||||
(void)index; (void)value; (void)option;
|
||||
switch (opcode) {
|
||||
case 1: return 2400; /* host API version */
|
||||
case 13: if (p) __atomic_store_n(&p->restart,1U,__ATOMIC_RELEASE); return 0;
|
||||
case 16: return p ? (intptr_t)p->rate : 48000;
|
||||
case 17: return p ? (intptr_t)p->frames : 256;
|
||||
case 32: if (ptr) memcpy(ptr,"xtc",4); return 1;
|
||||
case 33: if (ptr) memcpy(ptr,"xtc",4); return 1;
|
||||
case 34: return 1;
|
||||
case 23: return in_audio ? 2 : 1; /* Realtime or user/main process level. */
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
static xtc_result open_v2(xtc_modern *p, unsigned int index, xtc_plugin_spec *s)
|
||||
{
|
||||
xtc_v2_effect *(*entry)(xtc_v2_host) = NULL;
|
||||
char name[64] = {0};
|
||||
if (index) return XTC_ERR_NOT_FOUND;
|
||||
if (!symbol(p->module->handle,"VSTPluginMain",&entry,sizeof(entry))) return XTC_ERR_UNSUPPORTED;
|
||||
constructing = p; p->v2 = entry(v2_host); constructing = NULL;
|
||||
if (!p->v2 || p->v2->magic != XTC_V2_MAGIC || !p->v2->dispatch) return XTC_ERR_UNSUPPORTED;
|
||||
p->v2->user = p;
|
||||
p->v2->dispatch(p->v2,0,0,0,NULL,0); p->initialized = 1;
|
||||
if (p->v2->inputs != 1 || p->v2->outputs != 1 || !p->v2->replace || !(p->v2->flags & 16) ||
|
||||
(p->v2->flags & 256) || p->v2->initial_delay) return XTC_ERR_UNSUPPORTED;
|
||||
p->v2->dispatch(p->v2,45,0,0,name,0); name[63] = 0;
|
||||
if (!name[0]) return XTC_ERR_UNSUPPORTED;
|
||||
snprintf(s->label,sizeof(s->label),"%s",name); s->unique_id = (unsigned int)p->v2->unique_id;
|
||||
p->v2->dispatch(p->v2,10,0,0,NULL,(float)p->rate);
|
||||
p->v2->dispatch(p->v2,11,0,(intptr_t)p->frames,NULL,0);
|
||||
p->v2->dispatch(p->v2,12,0,1,NULL,0); p->active = 1;
|
||||
p->v2->dispatch(p->v2,71,0,0,NULL,0); p->started = 1;
|
||||
return XTC_OK;
|
||||
}
|
||||
static Steinberg_tresult host_query(void *self, const Steinberg_TUID iid, void **out)
|
||||
{
|
||||
if (!out || !iid) return Steinberg_kInvalidArgument;
|
||||
*out = NULL;
|
||||
if (!memcmp(iid,Steinberg_FUnknown_iid,16) || !memcmp(iid,Steinberg_Vst_IHostApplication_iid,16)) { *out = self; return 0; }
|
||||
return Steinberg_kNoInterface;
|
||||
}
|
||||
static Steinberg_uint32 host_ref(void *self) { (void)self; return 1; }
|
||||
static Steinberg_tresult host_name(void *self, Steinberg_Vst_String128 name)
|
||||
{ (void)self; if (!name) return Steinberg_kInvalidArgument; memset(name,0,sizeof(Steinberg_Vst_String128)); name[0] = 'x'; name[1] = 't'; name[2] = 'c'; return 0; }
|
||||
static Steinberg_tresult host_create(void *self, Steinberg_TUID cid, Steinberg_TUID iid, void **out)
|
||||
{ (void)self; (void)cid; (void)iid; if (!out) return Steinberg_kInvalidArgument; *out = NULL; return Steinberg_kNoInterface; }
|
||||
static Steinberg_Vst_IHostApplicationVtbl host_vtable = {host_query,host_ref,host_ref,host_name,host_create};
|
||||
static Steinberg_Vst_IHostApplication application = {&host_vtable};
|
||||
static xtc_result open_v3(xtc_modern *p, unsigned int index, xtc_plugin_spec *s)
|
||||
{
|
||||
Steinberg_IPluginFactory *(*entry)(void) = NULL;
|
||||
struct Steinberg_PClassInfo info;
|
||||
struct Steinberg_Vst_ProcessSetup setup = {0,0,(Steinberg_int32)p->frames,p->rate};
|
||||
Steinberg_Vst_SpeakerArrangement mono = Steinberg_Vst_SpeakerArr_kMono;
|
||||
unsigned int i;
|
||||
if (!symbol(p->module->handle,"GetPluginFactory",&entry,sizeof(entry))) return XTC_ERR_UNSUPPORTED;
|
||||
p->factory = entry();
|
||||
if (!p->factory || !p->factory->lpVtbl || !p->factory->lpVtbl->release ||
|
||||
!p->factory->lpVtbl->countClasses || !p->factory->lpVtbl->getClassInfo || !p->factory->lpVtbl->createInstance) return XTC_ERR_UNSUPPORTED;
|
||||
if ((Steinberg_int32)index >= p->factory->lpVtbl->countClasses(p->factory)) return XTC_ERR_NOT_FOUND;
|
||||
memset(&info,0,sizeof(info));
|
||||
if (p->factory->lpVtbl->getClassInfo(p->factory,(Steinberg_int32)index,&info) != 0 ||
|
||||
!memchr(info.category,0,sizeof(info.category)) || strcmp(info.category,"Audio Module Class") ||
|
||||
!memchr(info.name,0,sizeof(info.name)) || !info.name[0]) return XTC_ERR_UNSUPPORTED;
|
||||
for (i = 0; i < 16; ++i) snprintf(s->identifier+i*2,3,"%02x",(unsigned char)info.cid[i]);
|
||||
snprintf(s->label,sizeof(s->label),"%s",info.name);
|
||||
if (p->factory->lpVtbl->createInstance(p->factory,info.cid,Steinberg_Vst_IComponent_iid,(void **)&p->component) != 0 || !p->component)
|
||||
return XTC_ERR_INVALID_STATE;
|
||||
if (!p->component->lpVtbl || !p->component->lpVtbl->initialize || !p->component->lpVtbl->terminate ||
|
||||
!p->component->lpVtbl->queryInterface || !p->component->lpVtbl->release || !p->component->lpVtbl->getBusCount ||
|
||||
!p->component->lpVtbl->getBusInfo || !p->component->lpVtbl->activateBus || !p->component->lpVtbl->setActive) return XTC_ERR_UNSUPPORTED;
|
||||
if (p->component->lpVtbl->initialize(p->component,(Steinberg_FUnknown *)&application) != 0) return XTC_ERR_INVALID_STATE;
|
||||
p->initialized = 1;
|
||||
if (p->component->lpVtbl->queryInterface(p->component,Steinberg_Vst_IAudioProcessor_iid,(void **)&p->processor) != 0 || !p->processor)
|
||||
return XTC_ERR_UNSUPPORTED;
|
||||
if (!p->processor->lpVtbl || !p->processor->lpVtbl->release || !p->processor->lpVtbl->canProcessSampleSize ||
|
||||
!p->processor->lpVtbl->setBusArrangements || !p->processor->lpVtbl->setupProcessing || !p->processor->lpVtbl->getLatencySamples ||
|
||||
!p->processor->lpVtbl->setProcessing || !p->processor->lpVtbl->process) return XTC_ERR_UNSUPPORTED;
|
||||
if (p->component->lpVtbl->getBusCount(p->component,0,0) != 1 || p->component->lpVtbl->getBusCount(p->component,0,1) != 1 ||
|
||||
p->component->lpVtbl->getBusCount(p->component,1,0) || p->component->lpVtbl->getBusCount(p->component,1,1) ||
|
||||
p->processor->lpVtbl->canProcessSampleSize(p->processor,0) != 0 ||
|
||||
p->processor->lpVtbl->setBusArrangements(p->processor,&mono,1,&mono,1) != 0) return XTC_ERR_UNSUPPORTED;
|
||||
for (i = 0; i < 2; ++i) {
|
||||
struct Steinberg_Vst_BusInfo bus;
|
||||
if (p->component->lpVtbl->getBusInfo(p->component,0,(Steinberg_int32)i,0,&bus) != 0 || bus.channelCount != 1 ||
|
||||
p->component->lpVtbl->activateBus(p->component,0,(Steinberg_int32)i,0,1) != 0) return XTC_ERR_UNSUPPORTED;
|
||||
}
|
||||
if (p->processor->lpVtbl->setupProcessing(p->processor,&setup) != 0 || p->processor->lpVtbl->getLatencySamples(p->processor)) return XTC_ERR_UNSUPPORTED;
|
||||
if (p->component->lpVtbl->setActive(p->component,1) != 0) return XTC_ERR_INVALID_STATE;
|
||||
p->active = 1;
|
||||
if (p->processor->lpVtbl->setProcessing(p->processor,1) != 0) return XTC_ERR_INVALID_STATE;
|
||||
p->started = 1; return XTC_OK;
|
||||
}
|
||||
xtc_result xtc_modern_open(xtc_plugin_format format, const char *path, unsigned int index, double rate, size_t frames, xtc_modern **out, xtc_plugin_spec *spec)
|
||||
{
|
||||
xtc_modern *p; xtc_plugin_spec s = {0}; xtc_result r;
|
||||
if (!__atomic_always_lock_free(sizeof(unsigned int),0)) return XTC_ERR_UNSUPPORTED;
|
||||
p = calloc(1,sizeof(*p));
|
||||
if (!p) return XTC_ERR_OUT_OF_MEMORY;
|
||||
p->format = format; p->frames = frames; p->rate = rate; p->control_thread = pthread_self();
|
||||
p->input = calloc(frames,sizeof(float)); p->output = calloc(frames,sizeof(float));
|
||||
if (!p->input || !p->output) { xtc_modern_destroy(p); return XTC_ERR_OUT_OF_MEMORY; }
|
||||
r = module_open(format,path,&p->module);
|
||||
s.format = format; s.index = index; s.inputs = 1; s.tempo = 120000;
|
||||
snprintf(s.path,sizeof(s.path),"%s",path);
|
||||
if (r == XTC_OK) r = format == XTC_PLUGIN_CLAP ? open_clap(p,index,&s) : format == XTC_PLUGIN_VST2 ? open_v2(p,index,&s) : open_v3(p,index,&s);
|
||||
if (r != XTC_OK) { xtc_modern_destroy(p); return r; }
|
||||
p->next = instances; instances = p; *out = p; *spec = s; return XTC_OK;
|
||||
}
|
||||
void xtc_modern_destroy(xtc_modern *p)
|
||||
{
|
||||
xtc_modern **slot;
|
||||
if (!p) return;
|
||||
for (slot = &instances; *slot && *slot != p; slot = &(*slot)->next) {}
|
||||
if (*slot) *slot = p->next;
|
||||
if (p->clap) {
|
||||
if (p->started) { in_audio = 1; p->clap->stop_processing(p->clap); in_audio = 0; }
|
||||
if (p->active) p->clap->deactivate(p->clap);
|
||||
if (p->clap->destroy) p->clap->destroy(p->clap);
|
||||
}
|
||||
if (p->v2 && p->v2->magic == XTC_V2_MAGIC && p->v2->dispatch && p->initialized) {
|
||||
if (p->started) p->v2->dispatch(p->v2,72,0,0,NULL,0);
|
||||
if (p->active) p->v2->dispatch(p->v2,12,0,0,NULL,0);
|
||||
p->v2->dispatch(p->v2,1,0,0,NULL,0);
|
||||
}
|
||||
if (p->processor && p->processor->lpVtbl) {
|
||||
if (p->started) p->processor->lpVtbl->setProcessing(p->processor,0);
|
||||
if (p->active) p->component->lpVtbl->setActive(p->component,0);
|
||||
if (p->processor->lpVtbl->release) p->processor->lpVtbl->release(p->processor);
|
||||
}
|
||||
if (p->component && p->component->lpVtbl) {
|
||||
if (p->initialized) p->component->lpVtbl->terminate(p->component);
|
||||
if (p->component->lpVtbl->release) p->component->lpVtbl->release(p->component);
|
||||
}
|
||||
if (p->factory && p->factory->lpVtbl && p->factory->lpVtbl->release) p->factory->lpVtbl->release(p->factory);
|
||||
module_release(p->module); free(p->input); free(p->output); free(p);
|
||||
}
|
||||
xtc_result xtc_modern_process(xtc_modern *p, const float *input, float *output, size_t frames)
|
||||
{
|
||||
size_t i; int ok = 1;
|
||||
if (!p || !output || frames > p->frames) return XTC_ERR_INVALID_ARGUMENT;
|
||||
if (!frames) return XTC_OK;
|
||||
if (__atomic_load_n(&p->restart,__ATOMIC_ACQUIRE)) { memset(output,0,frames*sizeof(float)); return XTC_ERR_INVALID_STATE; }
|
||||
for (i = 0; i < frames; ++i) p->input[i] = input ? xtc_dsp_finite(input[i]) : 0;
|
||||
memset(p->output,0,frames*sizeof(float));
|
||||
in_audio = 1;
|
||||
if (p->clap) {
|
||||
clap_input_events_t events = {NULL,event_count,event_get}; clap_output_events_t sink = {NULL,event_push};
|
||||
clap_audio_buffer_t in = {&p->input,NULL,1,0,0}, out = {&p->output,NULL,1,0,0};
|
||||
clap_process_t block = {-1,(uint32_t)frames,NULL,&in,&out,1,1,&events,&sink};
|
||||
if (!p->started) { p->started = p->clap->start_processing(p->clap); if (!p->started) ok = 0; }
|
||||
if (ok) {
|
||||
clap_process_status status = p->clap->process(p->clap,&block);
|
||||
ok = status >= CLAP_PROCESS_CONTINUE && status <= CLAP_PROCESS_SLEEP;
|
||||
}
|
||||
} else if (p->v2) p->v2->replace(p->v2,&p->input,&p->output,(int32_t)frames);
|
||||
else {
|
||||
struct Steinberg_Vst_AudioBusBuffers in = {0}, out = {0};
|
||||
struct Steinberg_Vst_ProcessData data = {0};
|
||||
in.numChannels = out.numChannels = 1;
|
||||
in.Steinberg_Vst_AudioBusBuffers_channelBuffers32 = &p->input;
|
||||
out.Steinberg_Vst_AudioBusBuffers_channelBuffers32 = &p->output;
|
||||
data.numSamples = (Steinberg_int32)frames; data.numInputs = data.numOutputs = 1; data.inputs = ∈ data.outputs = &out;
|
||||
ok = p->processor->lpVtbl->process(p->processor,&data) == 0;
|
||||
}
|
||||
in_audio = 0;
|
||||
for (i = 0; i < frames; ++i) output[i] = ok ? xtc_dsp_finite(p->output[i]) : 0;
|
||||
return ok ? XTC_OK : XTC_ERR_INVALID_STATE;
|
||||
}
|
||||
8
src/plugin/modern.h
Normal file
8
src/plugin/modern.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef XTC_MODERN_H
|
||||
#define XTC_MODERN_H
|
||||
#include "xtc/xtc_plugin.h"
|
||||
typedef struct xtc_modern xtc_modern;
|
||||
xtc_result xtc_modern_open(xtc_plugin_format format, const char *path, unsigned int index, double rate, size_t frames, xtc_modern **out, xtc_plugin_spec *spec);
|
||||
xtc_result xtc_modern_process(xtc_modern *plugin, const float *input, float *output, size_t frames);
|
||||
void xtc_modern_destroy(xtc_modern *plugin);
|
||||
#endif
|
||||
26
src/plugin/vst2_abi.h
Normal file
26
src/plugin/vst2_abi.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef XTC_VST2_ABI_H
|
||||
#define XTC_VST2_ABI_H
|
||||
/* Original, minimal Linux ABI declarations for legacy VST2 interoperability.
|
||||
* No Steinberg VST2 SDK code is included. Not a complete SDK or VST2 wrapper. */
|
||||
#include <stdint.h>
|
||||
typedef struct xtc_v2_effect xtc_v2_effect;
|
||||
typedef intptr_t (*xtc_v2_host)(xtc_v2_effect *, int32_t, int32_t, intptr_t, void *, float);
|
||||
typedef intptr_t (*xtc_v2_dispatch)(xtc_v2_effect *, int32_t, int32_t, intptr_t, void *, float);
|
||||
struct xtc_v2_effect {
|
||||
int32_t magic;
|
||||
xtc_v2_dispatch dispatch;
|
||||
void (*process)(xtc_v2_effect *, float **, float **, int32_t);
|
||||
void (*set_parameter)(xtc_v2_effect *, int32_t, float);
|
||||
float (*get_parameter)(xtc_v2_effect *, int32_t);
|
||||
int32_t programs, parameters, inputs, outputs, flags;
|
||||
intptr_t reserved1, reserved2;
|
||||
int32_t initial_delay, quality1, quality2;
|
||||
float ratio;
|
||||
void *object, *user;
|
||||
int32_t unique_id, version;
|
||||
void (*replace)(xtc_v2_effect *, float **, float **, int32_t);
|
||||
void (*replace64)(xtc_v2_effect *, double **, double **, int32_t);
|
||||
char future[56];
|
||||
};
|
||||
#define XTC_V2_MAGIC INT32_C(0x56737450)
|
||||
#endif
|
||||
2
tests/fixtures/README.md
vendored
2
tests/fixtures/README.md
vendored
|
|
@ -3,7 +3,7 @@
|
|||
Store small, redistributable fixtures here. Document their origin and license.
|
||||
Do not commit large recordings or assets with unclear licensing.
|
||||
|
||||
`project-v1.xtc` through `project-v10.xtc` are hand-authored xtc metadata fixtures
|
||||
`project-v1.xtc` through `project-v11.xtc` are hand-authored xtc metadata fixtures
|
||||
created for this repository, under the project license. They contain no audio
|
||||
or third-party resources. The v5/v6 plugin fixtures intentionally reference a
|
||||
missing module to exercise metadata migration without loading code.
|
||||
|
|
|
|||
39
tests/fixtures/project-v11.xtc
vendored
Normal file
39
tests/fixtures/project-v11.xtc
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
XTC_PROJECT 11
|
||||
APP 0 1 0
|
||||
TEMPO 120000
|
||||
IDS 1 1
|
||||
GRAPH 1 2 2 1
|
||||
NODE 0 1 3f000000
|
||||
NODE 1 4 00000000
|
||||
EDGE 0 1
|
||||
TRACKS 1
|
||||
TRACK 0 4b657973
|
||||
MIX 3f800000 00000000 0 0
|
||||
ROUTE 0 18446744073709551615
|
||||
CLIPS 1
|
||||
CLIP 0 0 0 960 0 960 5665727365
|
||||
ASSET -
|
||||
MIDI 1
|
||||
AUDIO 3f800000 0 0
|
||||
NOTES 1 1
|
||||
NOTE 0 0 0 480 69 100 0
|
||||
AUTOMATION 1
|
||||
POINT 0 0 0 3f800000 0
|
||||
CONTROL_MAPS 16
|
||||
MAP 0 7 10 64
|
||||
MAP 1 7 10 64
|
||||
MAP 2 7 10 64
|
||||
MAP 3 7 10 64
|
||||
MAP 4 7 10 64
|
||||
MAP 5 7 10 64
|
||||
MAP 6 7 10 64
|
||||
MAP 7 7 10 64
|
||||
MAP 8 7 10 64
|
||||
MAP 9 7 10 64
|
||||
MAP 10 7 10 64
|
||||
MAP 11 7 10 64
|
||||
MAP 12 7 10 64
|
||||
MAP 13 7 10 64
|
||||
MAP 14 7 10 64
|
||||
MAP 15 7 10 64
|
||||
END
|
||||
|
|
@ -711,7 +711,7 @@ int main(int argc, char **argv)
|
|||
// Exercise the actual modal chooser/editor with copied metadata only.
|
||||
Fl::add_timeout(.05,[](void *) {
|
||||
auto *dialog = Fl::first_window();
|
||||
CHECK(dialog && dialog->label() && std::strcmp(dialog->label(),"LADSPA descriptors") == 0);
|
||||
CHECK(dialog && dialog->label() && std::strcmp(dialog->label(),"Plugin descriptors") == 0);
|
||||
if (!dialog) return;
|
||||
for (int i = 0; i < dialog->children(); ++i)
|
||||
if (auto *list = dynamic_cast<Fl_Hold_Browser *>(dialog->child(i))) {
|
||||
|
|
@ -803,6 +803,30 @@ int main(int argc, char **argv)
|
|||
unlink("/tmp/xtc-gui-plugin-test.xtc");
|
||||
window.do_callback();
|
||||
}
|
||||
for (const char *variable : {"XTC_TEST_CLAP","XTC_TEST_VST2","XTC_TEST_VST3"}) {
|
||||
if (const char *module = std::getenv(variable)) {
|
||||
reset(); MainWindow window(false); auto *sequence = timeline(&window);
|
||||
size_t id = SIZE_MAX; xtc_plugin_spec spec{};
|
||||
CHECK(window.add_plugin(module,0,&id) == XTC_OK);
|
||||
CHECK(xtc_graph_get_plugin(xtc_project_graph(sequence->project()),id,&spec) == XTC_OK);
|
||||
CHECK(spec.format != XTC_PLUGIN_LADSPA && spec.inputs == 1 && !spec.control_count);
|
||||
CHECK(window.undo(false) == XTC_OK && window.undo(true) == XTC_OK);
|
||||
Fl::add_timeout(.05,[](void *) {
|
||||
auto *dialog = Fl::first_window(); CHECK(dialog);
|
||||
auto *choose = find(dialog,"Choose"); CHECK(choose); if (choose) choose->do_callback();
|
||||
});
|
||||
unsigned int chosen = UINT32_MAX;
|
||||
CHECK(xtc_choose_plugin(module,48000,chosen) && chosen == 0);
|
||||
CHECK(window.save_project("/tmp/xtc-gui-modern-test.xtc") == XTC_OK);
|
||||
CHECK(window.new_project() == XTC_OK);
|
||||
CHECK(window.open_project("/tmp/xtc-gui-modern-test.xtc") == XTC_OK);
|
||||
xtc_plugin_spec loaded{};
|
||||
CHECK(xtc_graph_get_plugin(xtc_project_graph(sequence->project()),id,&loaded) == XTC_OK && loaded.format == spec.format);
|
||||
const xtc_project *before = sequence->project();
|
||||
CHECK(window.replace_plugin(id,"/absent/modern.so",0) == XTC_ERR_NOT_FOUND && sequence->project() == before);
|
||||
unlink("/tmp/xtc-gui-modern-test.xtc"); window.do_callback();
|
||||
}
|
||||
}
|
||||
if (failures != 0) return 1;
|
||||
std::printf("GUI controls/errors/views/timers/cleanup passed: %u opens, %u closes.\n", opens, closes);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ def main():
|
|||
assert not (binaries / 'xtc').exists()
|
||||
assert (resources / 'licenses/xtc/LICENSE').read_bytes() == (source / 'LICENSE').read_bytes()
|
||||
assert (docs / 'PROJECT_FORMAT.md').is_file()
|
||||
assert (resources / 'licenses/xtc/CLAP-LICENSE').is_file()
|
||||
assert (resources / 'licenses/xtc/VST3-C-API-LICENSE').is_file()
|
||||
assert os.access(binaries / 'xtc-check', os.X_OK)
|
||||
run([str(binaries / 'xtc-check')])
|
||||
for filename in ('performance-baseline.json', 'project-performance-baseline.json', 'graph-performance-phase29.json'):
|
||||
|
|
@ -52,7 +54,7 @@ def main():
|
|||
run([str(binaries / 'xtc-check'), '--inspect', str(example)])
|
||||
assert (resources / 'xtc/examples/README.md').is_file()
|
||||
diagnose = subprocess.check_output([str(binaries / 'xtc-check'), '--diagnose'], text=True)
|
||||
assert 'Project formats: 1..10' in diagnose and 'JACK compiled:' in diagnose
|
||||
assert 'Project formats: 1..11' in diagnose and 'JACK compiled:' in diagnose
|
||||
# Replacing a file symlink must not overwrite an unrelated target.
|
||||
protected = stage / 'unrelated-target'
|
||||
protected.write_text('keep unrelated target\n')
|
||||
|
|
|
|||
116
tests/integration/test_modern_plugins.c
Normal file
116
tests/integration/test_modern_plugins.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "xtc/xtc_plugin.h"
|
||||
#include "xtc/xtc_project.h"
|
||||
#include "xtc/xtc_realtime.h"
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
static int audio;
|
||||
void *__real_malloc(size_t);
|
||||
void *__real_calloc(size_t,size_t);
|
||||
void *__real_realloc(void *,size_t);
|
||||
void __real_free(void *);
|
||||
void *__real_dlopen(const char *,int);
|
||||
int __real_dlclose(void *);
|
||||
void *__wrap_malloc(size_t n) { assert(!audio); return __real_malloc(n); }
|
||||
void *__wrap_calloc(size_t n,size_t s) { assert(!audio); return __real_calloc(n,s); }
|
||||
void *__wrap_realloc(void *p,size_t n) { assert(!audio); return __real_realloc(p,n); }
|
||||
void __wrap_free(void *p) { assert(!audio); __real_free(p); }
|
||||
void *__wrap_dlopen(const char *p,int mode) { assert(!audio); return __real_dlopen(p,mode); }
|
||||
int __wrap_dlclose(void *p) { assert(!audio); return __real_dlclose(p); }
|
||||
static void render(xtc_realtime *rt)
|
||||
{
|
||||
float in[31],left[31],right[31]; size_t i;
|
||||
for (i = 0; i < 31; ++i) in[i] = i % 2 ? -.5f : .25f;
|
||||
audio = 1;
|
||||
assert(xtc_realtime_process_stereo(rt,in,NULL,NULL,NULL,NULL,left,right,31) == XTC_OK);
|
||||
audio = 0;
|
||||
for (i = 0; i < 31; ++i) assert(left[i] == in[i]*.5f && right[i] == left[i]);
|
||||
xtc_plugin_idle();
|
||||
}
|
||||
static void check(const char *path, xtc_plugin_format format)
|
||||
{
|
||||
xtc_plugin_spec spec, actual, bad;
|
||||
xtc_plugin_details details;
|
||||
xtc_plugin *plugin = NULL, *other = NULL;
|
||||
xtc_project *p = NULL, *loaded = NULL;
|
||||
xtc_graph *graph = NULL;
|
||||
xtc_realtime *rt = NULL;
|
||||
size_t node, output, i;
|
||||
char document[] = "/tmp/xtc-modern-XXXXXX";
|
||||
int fd = mkstemp(document); assert(fd >= 0); close(fd);
|
||||
assert(xtc_plugin_probe(path,0,48000,&spec) == XTC_OK && spec.format == format);
|
||||
assert(xtc_plugin_probe_format(format,path,0,48000,&actual) == XTC_OK);
|
||||
assert(!memcmp(&spec,&actual,sizeof(spec)));
|
||||
assert(xtc_plugin_describe(&spec,48000,&details) == XTC_OK && details.name[0]);
|
||||
assert(xtc_plugin_create(&spec,48000,31,&plugin) == XTC_OK);
|
||||
assert(xtc_plugin_create(&spec,48000,31,&other) == XTC_OK);
|
||||
{ float data[31]; for (i = 0; i < 31; ++i) data[i] = 1;
|
||||
audio = 1; assert(xtc_plugin_process(plugin,data,data,31) == XTC_OK); audio = 0;
|
||||
for (i = 0; i < 31; ++i) assert(data[i] == .5f);
|
||||
audio = 1; assert(xtc_plugin_process(other,NULL,data,31) == XTC_OK); audio = 0;
|
||||
for (i = 0; i < 31; ++i) assert(data[i] == 0);
|
||||
assert(xtc_plugin_process(plugin,data,data,32) == XTC_ERR_INVALID_ARGUMENT); }
|
||||
xtc_plugin_idle(); xtc_plugin_destroy(plugin); xtc_plugin_destroy(other); plugin = NULL;
|
||||
assert(xtc_project_create(&p) == XTC_OK && xtc_project_create(&loaded) == XTC_OK);
|
||||
assert(xtc_graph_create(2,&graph) == XTC_OK);
|
||||
assert(xtc_graph_add_plugin(graph,&spec,&node) == XTC_OK && xtc_graph_add_output(graph,&output) == XTC_OK);
|
||||
assert(xtc_graph_connect(graph,node,output) == XTC_OK);
|
||||
assert(xtc_project_set_graph(p,graph) == XTC_OK);
|
||||
assert(xtc_project_save(p,document) == XTC_OK && xtc_project_load(loaded,document) == XTC_OK);
|
||||
assert(xtc_graph_get_plugin(xtc_project_graph(loaded),node,&actual) == XTC_OK);
|
||||
assert(!memcmp(&actual,&spec,sizeof(spec)));
|
||||
assert(xtc_realtime_create(48000,31,&rt) == XTC_OK);
|
||||
assert(xtc_realtime_submit(rt,xtc_project_graph(loaded)) == XTC_OK); render(rt);
|
||||
for (i = 0; i < 50; ++i) {
|
||||
xtc_realtime_collect(rt);
|
||||
assert(xtc_realtime_submit(rt,graph) == XTC_OK); render(rt);
|
||||
}
|
||||
if (format == XTC_PLUGIN_VST3) {
|
||||
bad = spec; strcpy(bad.identifier,"not-a-class-id");
|
||||
assert(xtc_plugin_spec_validate(&bad) == XTC_ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
bad = spec; bad.control_count = 1;
|
||||
assert(xtc_plugin_spec_validate(&bad) == XTC_ERR_UNSUPPORTED);
|
||||
bad = spec; ++bad.unique_id;
|
||||
assert(xtc_graph_replace_plugin(graph,node,&bad) == XTC_OK);
|
||||
xtc_realtime_collect(rt);
|
||||
assert(xtc_realtime_submit(rt,graph) == XTC_ERR_UNSUPPORTED); render(rt);
|
||||
bad = spec; strcpy(bad.path,"/missing/xtc-modern-plugin.so");
|
||||
assert(xtc_graph_replace_plugin(graph,node,&bad) == XTC_OK && xtc_project_set_graph(p,graph) == XTC_OK);
|
||||
assert(xtc_project_save(p,document) == XTC_OK && xtc_project_load(loaded,document) == XTC_OK);
|
||||
assert(xtc_graph_get_plugin(xtc_project_graph(loaded),node,&actual) == XTC_OK && !strcmp(actual.path,bad.path));
|
||||
assert(xtc_plugin_create(&actual,48000,31,&plugin) == XTC_ERR_NOT_FOUND && !plugin);
|
||||
xtc_realtime_destroy(rt); xtc_graph_destroy(graph); xtc_project_destroy(p); xtc_project_destroy(loaded); unlink(document);
|
||||
printf("%s identity, buffers, stereo graph, retirement, reload and missing dependency passed.\n",xtc_plugin_format_name(format));
|
||||
}
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
unsigned int i; xtc_plugin_spec spec; xtc_plugin *p = NULL; float data[1] = {1};
|
||||
assert(argc == 4);
|
||||
check(argv[1],XTC_PLUGIN_CLAP); check(argv[2],XTC_PLUGIN_VST2); check(argv[3],XTC_PLUGIN_VST3);
|
||||
for (i = 1; i < 4; ++i) assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],i,48000,&spec) != XTC_OK);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],4,48000,&spec) == XTC_OK);
|
||||
assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK);
|
||||
assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p); p = NULL;
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],5,48000,&spec) == XTC_OK);
|
||||
assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK);
|
||||
assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],6,48000,&spec) == XTC_OK);
|
||||
p = NULL; data[0] = 1;
|
||||
assert(xtc_plugin_create(&spec,48000,1,&p) == XTC_OK);
|
||||
assert(xtc_plugin_process(p,data,data,1) == XTC_OK && data[0] == .5f);
|
||||
xtc_plugin_idle();
|
||||
assert(xtc_plugin_process(p,data,data,1) == XTC_ERR_INVALID_STATE && data[0] == 0); xtc_plugin_destroy(p);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_CLAP,argv[1],7,48000,&spec) == XTC_ERR_NOT_FOUND);
|
||||
assert(setenv("XTC_VST2_FIXTURE_LAYOUT","1",1) == 0);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_VST2,argv[2],0,48000,&spec) == XTC_ERR_UNSUPPORTED);
|
||||
unsetenv("XTC_VST2_FIXTURE_LAYOUT");
|
||||
assert(setenv("XTC_VST3_FIXTURE_INIT","1",1) == 0);
|
||||
assert(xtc_plugin_probe_format(XTC_PLUGIN_VST3,argv[3],0,48000,&spec) == XTC_ERR_INVALID_STATE);
|
||||
unsetenv("XTC_VST3_FIXTURE_INIT");
|
||||
puts("Modern plugin partial initialization/start/process failures passed."); return 0;
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ int main(void)
|
|||
assert(mkdtemp(root));
|
||||
assert(xtc_project_create(&p) == XTC_OK);
|
||||
snprintf(file,sizeof(file),"%s/migration.xtc",root);
|
||||
for (version = 1; version <= 10; ++version) {
|
||||
for (version = 1; version <= 11; ++version) {
|
||||
xtc_track_info t; xtc_clip_info c; size_t notes, points;
|
||||
snprintf(old,sizeof(old),"tests/fixtures/project-v%u.xtc",version);
|
||||
assert(xtc_project_load(p,old) == XTC_OK);
|
||||
|
|
@ -89,6 +89,6 @@ int main(void)
|
|||
assert(xtc_project_load(p,file) == XTC_ERR_FORMAT);
|
||||
{ xtc_clip_info c; assert(xtc_project_find_clip(p,clip,&c) == XTC_OK && c.asset_path[0]); } }
|
||||
xtc_project_destroy(p); unlink(file); rmdir(moved);
|
||||
puts("v1-v10 migration, current folder relocation, cwd independence and missing-media preservation passed.");
|
||||
puts("v1-v11 migration, current folder relocation, cwd independence and missing-media preservation passed.");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,37 @@ with tempfile.TemporaryDirectory(prefix="xtc-inspect-") as directory:
|
|||
# Inspection succeeds for readable files without trying dlopen or decoding.
|
||||
module.write_text("Deliberately not an executable module")
|
||||
check("--inspect", project, 0, "no plugin code executed")
|
||||
# Current metadata-only inspection must not execute any modern plugin ABI.
|
||||
maps = base[base.index("CONTROL_MAPS"):]
|
||||
for number, name, identity in ((1, "CLAP", "org.xtc.fixture"), (2, "VST2", ""),
|
||||
(3, "VST3", "0123456789abcdef0123456789abcdef")):
|
||||
lines = []
|
||||
for line in plugin.splitlines():
|
||||
if line.startswith(("CONTROL ", "PARAM ")):
|
||||
continue
|
||||
if line.startswith("XTC_PROJECT "):
|
||||
line = "XTC_PROJECT 11"
|
||||
elif line.startswith("PLUGIN "):
|
||||
fields = line.split()
|
||||
fields[4] = "0"
|
||||
line = " ".join(fields)
|
||||
elif line.startswith("PLUGIN_AUTOMATION "):
|
||||
line = "PLUGIN_AUTOMATION 0"
|
||||
elif line == "END":
|
||||
line = maps.rstrip()
|
||||
lines.append(line)
|
||||
if line.startswith("MODULE "):
|
||||
lines.append(f"FORMAT {number} {identity.encode().hex() if identity else '-'}")
|
||||
modern = "\n".join(lines) + "\n"
|
||||
project.write_text(modern)
|
||||
check("--inspect", project, 0, name + " node 0", "Project format 11")
|
||||
project.write_text(modern.replace(f"FORMAT {number} ", "FORMAT 99 "))
|
||||
check("--validate", project, 1, "Unsupported")
|
||||
if number == 3:
|
||||
project.write_text(modern.replace(identity.encode().hex(), b"bad-class-id".hex()))
|
||||
check("--validate", project, 1)
|
||||
for text, messages in [
|
||||
(base.replace("XTC_PROJECT 10", "XTC_PROJECT 999"), ("line 1", "999", "1..10")),
|
||||
(base.replace("XTC_PROJECT 10", "XTC_PROJECT 999"), ("line 1", "999", "1..11")),
|
||||
("XTC_PROJECT 10\n", ("line 2", "APP")),
|
||||
(base.replace("TEMPO 120000", "TEMPO 0"), ("line 3", "TEMPO")),
|
||||
(base + "OPTIONAL_FUTURE 1\n", ("Unknown fields",)),
|
||||
|
|
|
|||
78
tests/plugins/clap_fixture.c
Normal file
78
tests/plugins/clap_fixture.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#include <clap/clap.h>
|
||||
#include <clap/ext/thread-check.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static int loaded, count;
|
||||
static const char *features[] = {CLAP_PLUGIN_FEATURE_AUDIO_EFFECT,NULL};
|
||||
static const clap_plugin_descriptor_t descriptors[] = {
|
||||
{CLAP_VERSION,"xtc.fixture.gain","CLAP gain","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.stereo","Stereo","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.init","Init failure","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.activate","Activate failure","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.start","Start failure","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.process","Process failure","xtc","","","","1","",features},
|
||||
{CLAP_VERSION,"xtc.fixture.restart","Restart request","xtc","","","","1","",features}
|
||||
};
|
||||
typedef struct { clap_plugin_t plugin; const clap_host_t *host; unsigned int index; int active, started; } instance;
|
||||
static bool init(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; assert(loaded); return p->index != 2; }
|
||||
static void destroy(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; assert(!p->active && !p->started); --count; free(p); }
|
||||
static bool activate(const clap_plugin_t *plugin, double rate, uint32_t min, uint32_t max)
|
||||
{ instance *p = plugin->plugin_data; assert(rate > 0 && min && max >= min && !p->active); if (p->index == 3) return false; p->active = 1; return true; }
|
||||
static void deactivate(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; assert(p->active && !p->started); p->active = 0; }
|
||||
static bool start(const clap_plugin_t *plugin)
|
||||
{
|
||||
instance *p = plugin->plugin_data;
|
||||
const clap_host_thread_check_t *check = p->host->get_extension(p->host,CLAP_EXT_THREAD_CHECK);
|
||||
assert(p->active && !p->started && check->is_audio_thread(p->host));
|
||||
if (p->index == 4) return false;
|
||||
p->started = 1; return true;
|
||||
}
|
||||
static void stop(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; assert(p->started); p->started = 0; }
|
||||
static void reset(const clap_plugin_t *plugin) { (void)plugin; }
|
||||
static clap_process_status process(const clap_plugin_t *plugin, const clap_process_t *block)
|
||||
{
|
||||
instance *p = plugin->plugin_data; uint32_t i;
|
||||
assert(p->started && block->audio_inputs_count == 1 && block->audio_outputs_count == 1 && block->in_events->size(block->in_events) == 0);
|
||||
if (p->index == 5) return CLAP_PROCESS_ERROR;
|
||||
for (i = 0; i < block->frames_count; ++i) block->audio_outputs[0].data32[0][i] = block->audio_inputs[0].data32[0][i]*.5f;
|
||||
p->host->request_callback(p->host);
|
||||
if (p->index == 6) p->host->request_restart(p->host);
|
||||
return CLAP_PROCESS_CONTINUE;
|
||||
}
|
||||
static uint32_t port_count(const clap_plugin_t *plugin, bool input) { (void)plugin; (void)input; return 1; }
|
||||
static bool port_get(const clap_plugin_t *plugin, uint32_t index, bool input, clap_audio_port_info_t *info)
|
||||
{ instance *p = plugin->plugin_data; (void)input; if (index) return false; memset(info,0,sizeof(*info)); info->channel_count = p->index == 1 ? 2 : 1; return true; }
|
||||
static uint32_t latency(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; assert(p->active); return 0; }
|
||||
static const void *extension(const clap_plugin_t *plugin, const char *id)
|
||||
{
|
||||
static const clap_plugin_audio_ports_t ports = {port_count,port_get};
|
||||
static const clap_plugin_latency_t delay = {latency}; (void)plugin;
|
||||
if (!strcmp(id,CLAP_EXT_AUDIO_PORTS)) return &ports;
|
||||
return !strcmp(id,CLAP_EXT_LATENCY) ? &delay : NULL;
|
||||
}
|
||||
static void on_main(const clap_plugin_t *plugin)
|
||||
{ instance *p = plugin->plugin_data; const clap_host_thread_check_t *check = p->host->get_extension(p->host,CLAP_EXT_THREAD_CHECK); assert(check->is_main_thread(p->host)); }
|
||||
static uint32_t plugin_count(const clap_plugin_factory_t *factory) { (void)factory; return 7; }
|
||||
static const clap_plugin_descriptor_t *descriptor(const clap_plugin_factory_t *factory, uint32_t index)
|
||||
{ (void)factory; return index < 7 ? descriptors+index : NULL; }
|
||||
static const clap_plugin_t *create(const clap_plugin_factory_t *factory, const clap_host_t *host, const char *id)
|
||||
{
|
||||
unsigned int i; instance *p; (void)factory;
|
||||
for (i = 0; i < 7 && strcmp(id,descriptors[i].id); ++i) {}
|
||||
if (i == 7) return NULL;
|
||||
p = calloc(1,sizeof(*p)); if (!p) return NULL;
|
||||
p->host = host; p->index = i;
|
||||
p->plugin = (clap_plugin_t){descriptors+i,p,init,destroy,activate,deactivate,start,stop,reset,process,extension,on_main};
|
||||
++count; return &p->plugin;
|
||||
}
|
||||
static bool entry_init(const char *path) { (void)path; assert(!loaded); loaded = 1; return true; }
|
||||
static void entry_exit(void) { assert(loaded && !count); loaded = 0; }
|
||||
static const void *factory(const char *id)
|
||||
{ static const clap_plugin_factory_t f = {plugin_count,descriptor,create}; return !strcmp(id,CLAP_PLUGIN_FACTORY_ID) ? &f : NULL; }
|
||||
CLAP_EXPORT const clap_plugin_entry_t clap_entry = {CLAP_VERSION,entry_init,entry_exit,factory};
|
||||
34
tests/plugins/vst2_fixture.c
Normal file
34
tests/plugins/vst2_fixture.c
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* Original MIT ABI fixture; not built from or linked to a proprietary SDK. */
|
||||
#include "../../src/plugin/vst2_abi.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
typedef struct { xtc_v2_effect effect; int open, active, started; } instance;
|
||||
static intptr_t dispatch(xtc_v2_effect *e, int32_t op, int32_t index, intptr_t value, void *ptr, float option)
|
||||
{
|
||||
instance *p = (instance *)e; (void)index; (void)option;
|
||||
switch (op) {
|
||||
case 0: assert(!p->open); p->open = 1; break;
|
||||
case 1: assert(p->open && !p->active && !p->started); free(p); break;
|
||||
case 12: p->active = value != 0; break;
|
||||
case 45: strcpy(ptr,"VST2 gain"); return 1;
|
||||
case 71: assert(p->active); p->started = 1; break;
|
||||
case 72: p->started = 0; break;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void process(xtc_v2_effect *e, float **input, float **output, int32_t frames)
|
||||
{ instance *p = (instance *)e; int32_t i; assert(p->started); for (i = 0; i < frames; ++i) output[0][i] = input[0][i]*.5f; }
|
||||
xtc_v2_effect *VSTPluginMain(xtc_v2_host host);
|
||||
xtc_v2_effect *VSTPluginMain(xtc_v2_host host)
|
||||
{
|
||||
instance *p; assert(host(NULL,1,0,0,NULL,0) == 2400);
|
||||
p = calloc(1,sizeof(*p)); if (!p) return NULL;
|
||||
p->effect.magic = XTC_V2_MAGIC; p->effect.dispatch = dispatch;
|
||||
p->effect.inputs = p->effect.outputs = 1;
|
||||
if (getenv("XTC_VST2_FIXTURE_LAYOUT")) p->effect.inputs = 2;
|
||||
p->effect.flags = 16;
|
||||
p->effect.unique_id = 0x58544332; p->effect.replace = process;
|
||||
return &p->effect;
|
||||
}
|
||||
72
tests/plugins/vst3_fixture.c
Normal file
72
tests/plugins/vst3_fixture.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include <stdbool.h>
|
||||
#include <vst3_c_api.h>
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static int loaded, instances;
|
||||
static const Steinberg_TUID cid = SMTG_INLINE_UID(0x58544333,0x12345678,0x12345678,0x12345678);
|
||||
typedef struct { Steinberg_Vst_IComponent component; Steinberg_Vst_IAudioProcessor processor; unsigned int refs; int initialized, active, started; } instance;
|
||||
static instance *from_processor(void *p) { return (instance *)((char *)p - offsetof(instance,processor)); }
|
||||
static Steinberg_tresult cq(void *self, const Steinberg_TUID iid, void **out)
|
||||
{
|
||||
instance *p = self; *out = NULL;
|
||||
if (!memcmp(iid,Steinberg_Vst_IAudioProcessor_iid,16)) *out = &p->processor;
|
||||
else if (!memcmp(iid,Steinberg_Vst_IComponent_iid,16) || !memcmp(iid,Steinberg_FUnknown_iid,16)) *out = &p->component;
|
||||
if (!*out) return -1;
|
||||
++p->refs; return 0;
|
||||
}
|
||||
static Steinberg_uint32 add(void *self) { return ++((instance *)self)->refs; }
|
||||
static Steinberg_uint32 release(void *self)
|
||||
{ instance *p = self; unsigned int refs = --p->refs; if (!refs) { assert(!p->initialized); --instances; free(p); } return refs; }
|
||||
static Steinberg_tresult pq(void *self, const Steinberg_TUID iid, void **out) { return cq(from_processor(self),iid,out); }
|
||||
static Steinberg_uint32 pa(void *self) { return add(from_processor(self)); }
|
||||
static Steinberg_uint32 pr(void *self) { return release(from_processor(self)); }
|
||||
static Steinberg_tresult init(void *self, Steinberg_FUnknown *host)
|
||||
{ instance *p = self; assert(loaded && host && !p->initialized); if (getenv("XTC_VST3_FIXTURE_INIT")) return -1; p->initialized = 1; return 0; }
|
||||
static Steinberg_tresult terminate(void *self) { instance *p = self; assert(p->initialized && !p->active); p->initialized = 0; return 0; }
|
||||
static Steinberg_tresult controller(void *self, Steinberg_TUID id) { (void)self; (void)id; return -1; }
|
||||
static Steinberg_tresult mode(void *self, Steinberg_Vst_IoMode m) { (void)self; (void)m; return 0; }
|
||||
static Steinberg_int32 buses(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir) { (void)self; (void)dir; return type == 0 ? 1 : 0; }
|
||||
static Steinberg_tresult bus_info(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, struct Steinberg_Vst_BusInfo *info)
|
||||
{ (void)self; (void)dir; assert(type == 0 && index == 0); memset(info,0,sizeof(*info)); info->channelCount = 1; return 0; }
|
||||
static Steinberg_tresult routing(void *self, struct Steinberg_Vst_RoutingInfo *in, struct Steinberg_Vst_RoutingInfo *out)
|
||||
{ (void)self; (void)in; (void)out; return -1; }
|
||||
static Steinberg_tresult activate_bus(void *self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_TBool state)
|
||||
{ (void)self; (void)type; (void)dir; (void)index; (void)state; return 0; }
|
||||
static Steinberg_tresult active(void *self, Steinberg_TBool state) { instance *p = self; assert(!p->started); p->active = state; return 0; }
|
||||
static Steinberg_tresult state(void *self, Steinberg_IBStream *stream) { (void)self; (void)stream; return -1; }
|
||||
static Steinberg_tresult arrangements(void *self, Steinberg_Vst_SpeakerArrangement *in, Steinberg_int32 ni, Steinberg_Vst_SpeakerArrangement *out, Steinberg_int32 no)
|
||||
{ (void)self; return ni == 1 && no == 1 && in[0] == Steinberg_Vst_SpeakerArr_kMono && out[0] == in[0] ? 0 : -1; }
|
||||
static Steinberg_tresult arrangement(void *self, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_Vst_SpeakerArrangement *out)
|
||||
{ (void)self; (void)dir; (void)index; *out = Steinberg_Vst_SpeakerArr_kMono; return 0; }
|
||||
static Steinberg_tresult sample_size(void *self, Steinberg_int32 size) { (void)self; return size == 0 ? 0 : -1; }
|
||||
static Steinberg_uint32 latency(void *self) { (void)self; return 0; }
|
||||
static Steinberg_tresult setup(void *self, struct Steinberg_Vst_ProcessSetup *data) { (void)self; return data->maxSamplesPerBlock > 0 && data->sampleRate > 0 ? 0 : -1; }
|
||||
static Steinberg_tresult processing(void *self, Steinberg_TBool value) { instance *p = from_processor(self); assert(p->active); p->started = value; return 0; }
|
||||
static Steinberg_tresult process(void *self, struct Steinberg_Vst_ProcessData *data)
|
||||
{ instance *p = from_processor(self); int32_t i; assert(p->started); for (i = 0; i < data->numSamples; ++i) data->outputs[0].Steinberg_Vst_AudioBusBuffers_channelBuffers32[0][i] = data->inputs[0].Steinberg_Vst_AudioBusBuffers_channelBuffers32[0][i]*.5f; return 0; }
|
||||
static Steinberg_Vst_IComponentVtbl component_vtable = {cq,add,release,init,terminate,controller,mode,buses,bus_info,routing,activate_bus,active,state,state};
|
||||
static Steinberg_Vst_IAudioProcessorVtbl processor_vtable = {pq,pa,pr,arrangements,arrangement,sample_size,latency,setup,processing,process,latency};
|
||||
static Steinberg_tresult fq(void *self, const Steinberg_TUID iid, void **out) { (void)iid; *out = self; return 0; }
|
||||
static Steinberg_uint32 fr(void *self) { (void)self; return 1; }
|
||||
static Steinberg_tresult factory_info(void *self, struct Steinberg_PFactoryInfo *info) { (void)self; memset(info,0,sizeof(*info)); return 0; }
|
||||
static Steinberg_int32 classes(void *self) { (void)self; return 1; }
|
||||
static Steinberg_tresult class_info(void *self, Steinberg_int32 index, struct Steinberg_PClassInfo *info)
|
||||
{ (void)self; if (index) return -1; memset(info,0,sizeof(*info)); memcpy(info->cid,cid,16); strcpy(info->category,"Audio Module Class"); strcpy(info->name,"VST3 gain"); return 0; }
|
||||
static Steinberg_tresult create(void *self, Steinberg_FIDString id, Steinberg_FIDString iid, void **out)
|
||||
{
|
||||
instance *p; (void)self; *out = NULL;
|
||||
if (memcmp(id,cid,16) || memcmp(iid,Steinberg_Vst_IComponent_iid,16)) return -1;
|
||||
p = calloc(1,sizeof(*p)); if (!p) return -1;
|
||||
p->component.lpVtbl = &component_vtable; p->processor.lpVtbl = &processor_vtable; p->refs = 1;
|
||||
++instances; *out = p; return 0;
|
||||
}
|
||||
static Steinberg_IPluginFactoryVtbl factory_vtable = {fq,fr,fr,factory_info,classes,class_info,create};
|
||||
static Steinberg_IPluginFactory factory = {&factory_vtable};
|
||||
bool ModuleEntry(void *handle);
|
||||
bool ModuleExit(void);
|
||||
Steinberg_IPluginFactory *GetPluginFactory(void);
|
||||
bool ModuleEntry(void *handle) { assert(handle && !loaded); loaded = 1; return true; }
|
||||
bool ModuleExit(void) { assert(loaded && !instances); loaded = 0; return true; }
|
||||
Steinberg_IPluginFactory *GetPluginFactory(void) { assert(loaded); return &factory; }
|
||||
|
|
@ -68,7 +68,7 @@ int main(void)
|
|||
assert(xtc_project_add_track(old,"Old",&id) == XTC_OK && xtc_project_add_track(next,"New",&id) == XTC_OK);
|
||||
assert(xtc_project_save(old,song) == XTC_OK); size = bytes(song,before);
|
||||
assert(xtc_project_load_diagnostic(loaded,song,&diagnostic) == XTC_OK && diagnostic.result == XTC_OK &&
|
||||
diagnostic.format_version == 10 && !diagnostic.line);
|
||||
diagnostic.format_version == 11 && !diagnostic.line);
|
||||
for (mode = 1; mode <= 5; ++mode) {
|
||||
fault = mode;
|
||||
assert(xtc_project_save(next,song) == XTC_ERR_IO);
|
||||
|
|
@ -81,7 +81,7 @@ int main(void)
|
|||
}
|
||||
write_text(bad,"XTC_PROJECT 999\n");
|
||||
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_UNSUPPORTED && diagnostic.line == 1 &&
|
||||
diagnostic.format_version == 999 && !strcmp(diagnostic.record,"XTC_PROJECT") && strstr(diagnostic.message,"1..10"));
|
||||
diagnostic.format_version == 999 && !strcmp(diagnostic.record,"XTC_PROJECT") && strstr(diagnostic.message,"1..11"));
|
||||
write_text(bad,"XTC_PROJECT 10\nAPP 0 1 0\nTEMPO nope\n");
|
||||
assert(xtc_project_load_diagnostic(loaded,bad,&diagnostic) == XTC_ERR_FORMAT && diagnostic.line == 3 &&
|
||||
!strcmp(diagnostic.record,"TEMPO"));
|
||||
|
|
|
|||
20
third_party/README.md
vendored
Normal file
20
third_party/README.md
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Pinned plugin ABI headers
|
||||
|
||||
No plugin binaries or SDK runtime library are bundled. Updates are explicit,
|
||||
reviewed source changes; ordinary builds never fetch from the network.
|
||||
|
||||
| Headers | Upstream revision | License | Maintenance/build impact |
|
||||
| --- | --- | --- | --- |
|
||||
| `clap/include` | [free-audio/clap](https://github.com/free-audio/clap), `a47f6badb49d948fd009998f28309cdab78979c9` | MIT, `clap/LICENSE` | Active CLAP header specification, pinned snapshot; C99 compile-time dependency only |
|
||||
| `vst3/vst3_c_api.h` | [steinbergmedia/vst3_c_api](https://github.com/steinbergmedia/vst3_c_api), `93a116f7c6c52a317ec3aaee9b13789068b5234e` | BSD-3-Clause, `vst3/LICENSE.txt` | Official generated C ABI; review compatibility when updating the SDK snapshot; no C++ runtime adapter |
|
||||
|
||||
Files are unmodified upstream snapshots. The VST3 header's opening comment refers
|
||||
to its accompanying license; that upstream license is retained verbatim. Install
|
||||
and binary packages include both notices under the xtc license directory. These
|
||||
headers define interoperability ABIs, not a grant to redistribute user plugins.
|
||||
|
||||
`src/plugin/vst2_abi.h` is original minimal Linux compatibility declarations; no
|
||||
Steinberg VST2 SDK, implementation or VST2-wrapping SDK is copied or distributed.
|
||||
Legacy VST2 support does not grant SDK/trademark/plugin distribution rights. There
|
||||
is no VST2 plugin-building target for third-party SDKs. The original test fixture
|
||||
implements only the ABI subset needed to test this host.
|
||||
21
third_party/clap/LICENSE
vendored
Normal file
21
third_party/clap/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Alexandre BIQUE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
25
third_party/clap/include/clap/all.h
vendored
Normal file
25
third_party/clap/include/clap/all.h
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "clap.h"
|
||||
|
||||
#include "factory/draft/plugin-invalidation.h"
|
||||
#include "factory/draft/plugin-state-converter.h"
|
||||
|
||||
#include "ext/draft/background-activation.h"
|
||||
#include "ext/draft/background-progress.h"
|
||||
#include "ext/draft/background-state-context.h"
|
||||
#include "ext/draft/extensible-audio-ports.h"
|
||||
#include "ext/draft/flush-events.h"
|
||||
#include "ext/draft/gain-adjustment-metering.h"
|
||||
#include "ext/draft/mini-curve-display.h"
|
||||
#include "ext/draft/octave-number.h"
|
||||
#include "ext/draft/params-origin.h"
|
||||
#include "ext/draft/param-hovered.h"
|
||||
#include "ext/draft/project-location.h"
|
||||
#include "ext/draft/resource-directory.h"
|
||||
#include "ext/draft/scratch-memory.h"
|
||||
#include "ext/draft/transport-control.h"
|
||||
#include "ext/draft/triggers.h"
|
||||
#include "ext/draft/tuning.h"
|
||||
#include "ext/draft/undo.h"
|
||||
#include "ext/draft/webview.h"
|
||||
37
third_party/clap/include/clap/audio-buffer.h
vendored
Normal file
37
third_party/clap/include/clap/audio-buffer.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "private/std.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Sample code for reading a stereo buffer:
|
||||
//
|
||||
// bool isLeftConstant = (buffer->constant_mask & (1 << 0)) != 0;
|
||||
// bool isRightConstant = (buffer->constant_mask & (1 << 1)) != 0;
|
||||
//
|
||||
// for (int i = 0; i < N; ++i) {
|
||||
// float l = data32[0][isLeftConstant ? 0 : i];
|
||||
// float r = data32[1][isRightConstant ? 0 : i];
|
||||
// }
|
||||
//
|
||||
// Note: checking the constant mask is optional, and this implies that
|
||||
// the buffer must be filled with the constant value.
|
||||
// Rationale: if a buffer reader doesn't check the constant mask, then it may
|
||||
// process garbage samples and in result, garbage samples may be transmitted
|
||||
// to the audio interface with all the bad consequences it can have.
|
||||
//
|
||||
// The constant mask is a hint.
|
||||
typedef struct clap_audio_buffer {
|
||||
// Either data32 or data64 pointer will be set.
|
||||
float **data32;
|
||||
double **data64;
|
||||
uint32_t channel_count;
|
||||
uint32_t latency; // latency from/to the audio interface
|
||||
uint64_t constant_mask;
|
||||
} clap_audio_buffer_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
64
third_party/clap/include/clap/clap.h
vendored
Normal file
64
third_party/clap/include/clap/clap.h
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* CLAP - CLever Audio Plugin
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Copyright (c) 2014...2022 Alexandre BIQUE <bique.alexandre@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "entry.h"
|
||||
|
||||
#include "factory/plugin-factory.h"
|
||||
#include "factory/preset-discovery.h"
|
||||
|
||||
#include "plugin.h"
|
||||
#include "plugin-features.h"
|
||||
#include "host.h"
|
||||
#include "universal-plugin-id.h"
|
||||
|
||||
#include "ext/ambisonic.h"
|
||||
#include "ext/audio-ports-activation.h"
|
||||
#include "ext/audio-ports-config.h"
|
||||
#include "ext/audio-ports.h"
|
||||
#include "ext/configurable-audio-ports.h"
|
||||
#include "ext/context-menu.h"
|
||||
#include "ext/event-registry.h"
|
||||
#include "ext/gui.h"
|
||||
#include "ext/latency.h"
|
||||
#include "ext/log.h"
|
||||
#include "ext/note-name.h"
|
||||
#include "ext/note-ports.h"
|
||||
#include "ext/param-indication.h"
|
||||
#include "ext/params.h"
|
||||
#include "ext/posix-fd-support.h"
|
||||
#include "ext/preset-load.h"
|
||||
#include "ext/remote-controls.h"
|
||||
#include "ext/render.h"
|
||||
#include "ext/state-context.h"
|
||||
#include "ext/state.h"
|
||||
#include "ext/surround.h"
|
||||
#include "ext/tail.h"
|
||||
#include "ext/thread-check.h"
|
||||
#include "ext/thread-pool.h"
|
||||
#include "ext/timer-support.h"
|
||||
#include "ext/track-info.h"
|
||||
#include "ext/voice-info.h"
|
||||
20
third_party/clap/include/clap/color.h
vendored
Normal file
20
third_party/clap/include/clap/color.h
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "private/std.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_color {
|
||||
uint8_t alpha;
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
} clap_color_t;
|
||||
|
||||
static const CLAP_CONSTEXPR clap_color_t CLAP_COLOR_TRANSPARENT = { 0, 0, 0, 0 };
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
136
third_party/clap/include/clap/entry.h
vendored
Normal file
136
third_party/clap/include/clap/entry.h
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#pragma once
|
||||
|
||||
#include "version.h"
|
||||
#include "private/macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This interface is the entry point of the dynamic library.
|
||||
//
|
||||
// CLAP plugins standard search path:
|
||||
//
|
||||
// Linux
|
||||
// - ~/.clap
|
||||
// - /usr/lib/clap
|
||||
//
|
||||
// Windows
|
||||
// - %COMMONPROGRAMFILES%\CLAP
|
||||
// - %LOCALAPPDATA%\Programs\Common\CLAP
|
||||
//
|
||||
// MacOS
|
||||
// - /Library/Audio/Plug-Ins/CLAP
|
||||
// - ~/Library/Audio/Plug-Ins/CLAP
|
||||
//
|
||||
// In addition to the OS-specific default locations above, a CLAP host must query the environment
|
||||
// for a CLAP_PATH variable, which is a list of directories formatted in the same manner as the host
|
||||
// OS binary search path (PATH on Unix, separated by `:` and Path on Windows, separated by ';', as
|
||||
// of this writing).
|
||||
//
|
||||
// Each directory should be recursively searched for files and/or bundles as appropriate in your OS
|
||||
// ending with the extension `.clap`.
|
||||
//
|
||||
// init and deinit in most cases are called once, in a matched pair, when the dso is loaded / unloaded.
|
||||
// In some rare situations it may be called multiple times in a process, so the functions must be defensive,
|
||||
// mutex locking and counting calls if undertaking non trivial non idempotent actions.
|
||||
//
|
||||
// Rationale:
|
||||
//
|
||||
// The intent of the init() and deinit() functions is to provide a "normal" initialization pattern
|
||||
// which occurs when the shared object is loaded or unloaded. As such, hosts will call each once and
|
||||
// in matched pairs. In CLAP specifications prior to 1.2.0, this single-call was documented as a
|
||||
// requirement.
|
||||
//
|
||||
// We realized, though, that this is not a requirement hosts can meet. If hosts load a plugin
|
||||
// which itself wraps another CLAP for instance, while also loading that same clap in its memory
|
||||
// space, both the host and the wrapper will call init() and deinit() and have no means to communicate
|
||||
// the state.
|
||||
//
|
||||
// With CLAP 1.2.0 and beyond we are changing the spec to indicate that a host should make an
|
||||
// absolute best effort to call init() and deinit() once, and always in matched pairs (for every
|
||||
// init() which returns true, one deinit() should be called).
|
||||
//
|
||||
// This takes the de-facto burden on plugin writers to deal with multiple calls into a hard requirement.
|
||||
//
|
||||
// Most init() / deinit() pairs we have seen are the relatively trivial {return true;} and {}. But
|
||||
// if your init() function does non-trivial one time work, the plugin author must maintain a counter
|
||||
// and must manage a mutex lock. The most obvious implementation will maintain a static counter and a
|
||||
// global mutex, increment the counter on each init, decrement it on each deinit, and only undertake
|
||||
// the init or deinit action when the counter is zero.
|
||||
typedef struct clap_plugin_entry {
|
||||
clap_version_t clap_version; // initialized to CLAP_VERSION
|
||||
|
||||
// Initializes the DSO.
|
||||
//
|
||||
// This function must be called first, before any-other CLAP-related function or symbol from this
|
||||
// DSO.
|
||||
//
|
||||
// It also must only be called once, until a later call to deinit() is made, after which init()
|
||||
// can be called once more to re-initialize the DSO.
|
||||
// This enables hosts to e.g. quickly load and unload a DSO for scanning its plugins, and then
|
||||
// load it again later to actually use the plugins if needed.
|
||||
//
|
||||
// As stated above, even though hosts are forbidden to do so directly, multiple calls before any
|
||||
// deinit() call may still happen. Implementations *should* take this into account, and *must*
|
||||
// do so as of CLAP 1.2.0.
|
||||
//
|
||||
// It should be as fast as possible, in order to perform a very quick scan of the plugin
|
||||
// descriptors.
|
||||
//
|
||||
// It is forbidden to display graphical user interfaces in this call.
|
||||
// It is forbidden to perform any user interaction in this call.
|
||||
//
|
||||
// If the initialization depends upon expensive computation, maybe try to do them ahead of time
|
||||
// and cache the result.
|
||||
//
|
||||
// Returns true on success. If init() returns false, then the DSO must be considered
|
||||
// uninitialized, and the host must not call deinit() nor any other CLAP-related symbols from the
|
||||
// DSO.
|
||||
// This function also returns true in the case where the DSO is already initialized, and no
|
||||
// actual initialization work is done in this call, as explain above.
|
||||
//
|
||||
// plugin_path is the path to the DSO (Linux, Windows), or the bundle (macOS).
|
||||
//
|
||||
// This function may be called on any thread, including a different one from the one a later call
|
||||
// to deinit() (or a later init()) can be made.
|
||||
// However, it is forbidden to call this function simultaneously from multiple threads.
|
||||
// It is also forbidden to call it simultaneously with *any* other CLAP-related symbols from the
|
||||
// DSO, including (but not limited to) deinit().
|
||||
bool(CLAP_ABI *init)(const char *plugin_path);
|
||||
|
||||
// De-initializes the DSO, freeing any resources allocated or initialized by init().
|
||||
//
|
||||
// After this function is called, no more calls into the DSO must be made, except calling init()
|
||||
// again to re-initialize the DSO.
|
||||
// This means that after deinit() is called, the DSO can be considered to be in the same state
|
||||
// as if init() was never called at all yet, enabling it to be re-initialized as needed.
|
||||
//
|
||||
// As stated above, even though hosts are forbidden to do so directly, multiple calls before any
|
||||
// new init() call may still happen. Implementations *should* take this into account, and *must*
|
||||
// do so as of CLAP 1.2.0.
|
||||
//
|
||||
// Just like init(), this function may be called on any thread, including a different one from
|
||||
// the one init() was called from, or from the one a later init() call can be made.
|
||||
// However, it is forbidden to call this function simultaneously from multiple threads.
|
||||
// It is also forbidden to call it simultaneously with *any* other CLAP-related symbols from the
|
||||
// DSO, including (but not limited to) deinit().
|
||||
void(CLAP_ABI *deinit)(void);
|
||||
|
||||
// Get the pointer to a factory. See factory/plugin-factory.h for an example.
|
||||
//
|
||||
// Returns null if the factory is not provided.
|
||||
// The returned pointer must *not* be freed by the caller.
|
||||
//
|
||||
// Unlike init() and deinit(), this function can be called simultaneously by multiple threads.
|
||||
//
|
||||
// [thread-safe]
|
||||
const void *(CLAP_ABI *get_factory)(const char *factory_id);
|
||||
} clap_plugin_entry_t;
|
||||
|
||||
/* Entry point */
|
||||
CLAP_EXPORT extern const clap_plugin_entry_t clap_entry;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
367
third_party/clap/include/clap/events.h
vendored
Normal file
367
third_party/clap/include/clap/events.h
vendored
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
#pragma once
|
||||
|
||||
#include "private/std.h"
|
||||
#include "fixedpoint.h"
|
||||
#include "id.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// event header
|
||||
// All clap events start with an event header to determine the overall
|
||||
// size of the event and its type and space (a namespacing for types).
|
||||
// clap_event objects are contiguous regions of memory which can be copied
|
||||
// with a memcpy of `size` bytes starting at the top of the header. As
|
||||
// such, be very careful when designing clap events with internal pointers
|
||||
// and other non-value-types to consider the lifetime of those members.
|
||||
typedef struct clap_event_header {
|
||||
uint32_t size; // event size including this header, eg: sizeof (clap_event_note)
|
||||
uint32_t time; // sample offset within the buffer for this event
|
||||
uint16_t space_id; // event space, see clap_host_event_registry
|
||||
uint16_t type; // event type
|
||||
uint32_t flags; // see clap_event_flags
|
||||
} clap_event_header_t;
|
||||
|
||||
// The clap core event space
|
||||
static const CLAP_CONSTEXPR uint16_t CLAP_CORE_EVENT_SPACE_ID = 0;
|
||||
|
||||
enum clap_event_flags {
|
||||
// Indicate a live user event, for example a user turning a physical knob
|
||||
// or playing a physical key.
|
||||
CLAP_EVENT_IS_LIVE = 1 << 0,
|
||||
|
||||
// Indicate that the event should not be recorded.
|
||||
// For example this is useful when a parameter changes because of a MIDI CC,
|
||||
// because if the host records both the MIDI CC automation and the parameter
|
||||
// automation there will be a conflict.
|
||||
CLAP_EVENT_DONT_RECORD = 1 << 1,
|
||||
};
|
||||
|
||||
// Some of the following events overlap, a note on can be expressed with:
|
||||
// - CLAP_EVENT_NOTE_ON
|
||||
// - CLAP_EVENT_MIDI
|
||||
// - CLAP_EVENT_MIDI2
|
||||
//
|
||||
// The preferred way of sending a note event is to use CLAP_EVENT_NOTE_*.
|
||||
//
|
||||
// The same event must not be sent twice: it is forbidden to send a the same note on
|
||||
// encoded with both CLAP_EVENT_NOTE_ON and CLAP_EVENT_MIDI.
|
||||
//
|
||||
// The plugins are encouraged to be able to handle note events encoded as raw midi or midi2,
|
||||
// or implement clap_plugin_event_filter and reject raw midi and midi2 events.
|
||||
enum {
|
||||
// NOTE_ON and NOTE_OFF represent a key pressed and key released event, respectively.
|
||||
// A NOTE_ON with a velocity of 0 is valid and should not be interpreted as a NOTE_OFF.
|
||||
//
|
||||
// NOTE_CHOKE is meant to choke the voice(s), like in a drum machine when a closed hihat
|
||||
// chokes an open hihat. This event can be sent by the host to the plugin. Here are two use
|
||||
// cases:
|
||||
// - a plugin is inside a drum pad in Bitwig Studio's drum machine, and this pad is choked by
|
||||
// another one
|
||||
// - the user double-clicks the DAW's stop button in the transport which then stops the sound on
|
||||
// every track
|
||||
//
|
||||
// NOTE_END is sent by the plugin to the host. The port, channel, key and note_id are those given
|
||||
// by the host in the NOTE_ON event. In other words, this event is matched against the
|
||||
// plugin's note input port.
|
||||
// NOTE_END is useful to help the host to match the plugin's voice life time.
|
||||
//
|
||||
// When using polyphonic modulations, the host has to allocate and release voices for its
|
||||
// polyphonic modulator. Yet only the plugin effectively knows when the host should terminate
|
||||
// a voice. NOTE_END solves that issue in a non-intrusive and cooperative way.
|
||||
//
|
||||
// CLAP assumes that the host will allocate a unique voice on NOTE_ON event for a given port,
|
||||
// channel and key. This voice will run until the plugin will instruct the host to terminate
|
||||
// it by sending a NOTE_END event.
|
||||
//
|
||||
// Consider the following sequence:
|
||||
// - process()
|
||||
// Host->Plugin NoteOn(port:0, channel:0, key:16, time:t0)
|
||||
// Host->Plugin NoteOn(port:0, channel:0, key:64, time:t0)
|
||||
// Host->Plugin NoteOff(port:0, channel:0, key:16, t1)
|
||||
// Host->Plugin NoteOff(port:0, channel:0, key:64, t1)
|
||||
// # on t2, both notes did terminate
|
||||
// Host->Plugin NoteOn(port:0, channel:0, key:64, t3)
|
||||
// # Here the plugin finished processing all the frames and will tell the host
|
||||
// # to terminate the voice on key 16 but not 64, because a note has been started at t3
|
||||
// Plugin->Host NoteEnd(port:0, channel:0, key:16, time:ignored)
|
||||
//
|
||||
// These four events use clap_event_note.
|
||||
CLAP_EVENT_NOTE_ON = 0,
|
||||
CLAP_EVENT_NOTE_OFF = 1,
|
||||
CLAP_EVENT_NOTE_CHOKE = 2,
|
||||
CLAP_EVENT_NOTE_END = 3,
|
||||
|
||||
// Represents a note expression.
|
||||
// Uses clap_event_note_expression.
|
||||
CLAP_EVENT_NOTE_EXPRESSION = 4,
|
||||
|
||||
// PARAM_VALUE sets the parameter's value; uses clap_event_param_value.
|
||||
// PARAM_MOD sets the parameter's modulation amount; uses clap_event_param_mod.
|
||||
//
|
||||
// The value heard is: param_value + param_mod.
|
||||
//
|
||||
// In case of a concurrent global value/modulation versus a polyphonic one,
|
||||
// the voice should only use the polyphonic one and the polyphonic modulation
|
||||
// amount will already include the monophonic signal.
|
||||
CLAP_EVENT_PARAM_VALUE = 5,
|
||||
CLAP_EVENT_PARAM_MOD = 6,
|
||||
|
||||
// Indicates that the user started or finished adjusting a knob.
|
||||
// This is not mandatory to wrap parameter changes with gesture events, but this improves
|
||||
// the user experience a lot when recording automation or overriding automation playback.
|
||||
// Uses clap_event_param_gesture.
|
||||
CLAP_EVENT_PARAM_GESTURE_BEGIN = 7,
|
||||
CLAP_EVENT_PARAM_GESTURE_END = 8,
|
||||
|
||||
CLAP_EVENT_TRANSPORT = 9, // update the transport info; clap_event_transport
|
||||
CLAP_EVENT_MIDI = 10, // raw midi event; clap_event_midi
|
||||
CLAP_EVENT_MIDI_SYSEX = 11, // raw midi sysex event; clap_event_midi_sysex
|
||||
CLAP_EVENT_MIDI2 = 12, // raw midi 2 event; clap_event_midi2
|
||||
};
|
||||
|
||||
// Note on, off, end and choke events.
|
||||
//
|
||||
// Clap addresses notes and voices using the 4-value tuple
|
||||
// (port, channel, key, note_id). Note on/off/end/choke
|
||||
// events and parameter modulation messages are delivered with
|
||||
// these values populated.
|
||||
//
|
||||
// Values in a note and voice address are either >= 0 if they
|
||||
// are specified, or -1 to indicate a wildcard. A wildcard
|
||||
// means a voice with any value in that part of the tuple
|
||||
// matches the message.
|
||||
//
|
||||
// For instance, a (PCKN) of (0, 3, -1, -1) will match all voices
|
||||
// on channel 3 of port 0. And a PCKN of (-1, 0, 60, -1) will match
|
||||
// all channel 0 key 60 voices, independent of port or note id.
|
||||
//
|
||||
// Especially in the case of note-on note-off pairs, and in the
|
||||
// absence of voice stacking or polyphonic modulation, a host may
|
||||
// choose to issue a note id only at note on. So you may see a
|
||||
// message stream like
|
||||
//
|
||||
// CLAP_EVENT_NOTE_ON [0,0,60,184]
|
||||
// CLAP_EVENT_NOTE_OFF [0,0,60,-1]
|
||||
//
|
||||
// and the host will expect the first voice to be released.
|
||||
// Well constructed plugins will search for voices and notes using
|
||||
// the entire tuple.
|
||||
//
|
||||
// In the case of note on events:
|
||||
// - The port, channel and key must be specified with a value >= 0
|
||||
// - A note-on event with a '-1' for port, channel or key is invalid and
|
||||
// can be rejected or ignored by a plugin or host.
|
||||
// - A host which does not support note ids should set the note id to -1.
|
||||
//
|
||||
// In the case of note choke or end events:
|
||||
// - the velocity is ignored.
|
||||
// - key and channel are used to match active notes
|
||||
// - note_id is optionally provided by the host
|
||||
typedef struct clap_event_note {
|
||||
clap_event_header_t header;
|
||||
|
||||
int32_t note_id; // host provided note id >= 0, or -1 if unspecified or wildcard
|
||||
int16_t port_index; // port index from ext/note-ports; -1 for wildcard
|
||||
int16_t channel; // 0..15, same as MIDI1 Channel Number, -1 for wildcard
|
||||
int16_t key; // 0..127, same as MIDI1 Key Number (60==Middle C), -1 for wildcard
|
||||
double velocity; // 0..1
|
||||
} clap_event_note_t;
|
||||
|
||||
// Note Expressions are well named modifications of a voice targeted to
|
||||
// voices using the same wildcard rules described above. Note Expressions are delivered
|
||||
// as sample accurate events and should be applied at the sample when received.
|
||||
//
|
||||
// Note expressions are a statement of value, not cumulative. A PAN event of 0 followed by 1
|
||||
// followed by 0.5 would pan hard left, hard right, and center. They are intended as
|
||||
// an offset from the non-note-expression voice default. A voice which had a volume of
|
||||
// -20db absent note expressions which received a +4db note expression would move the
|
||||
// voice to -16db.
|
||||
//
|
||||
// A plugin which receives a note expression at the same sample as a NOTE_ON event
|
||||
// should apply that expression to all generated samples. A plugin which receives
|
||||
// a note expression after a NOTE_ON event should initiate the voice with default
|
||||
// values and then apply the note expression when received. A plugin may make a choice
|
||||
// to smooth note expression streams.
|
||||
enum {
|
||||
// with 0 < x <= 4, plain = 20 * log(x)
|
||||
CLAP_NOTE_EXPRESSION_VOLUME = 0,
|
||||
|
||||
// pan, 0 left, 0.5 center, 1 right
|
||||
CLAP_NOTE_EXPRESSION_PAN = 1,
|
||||
|
||||
// Relative tuning in semitones, from -120 to +120. Semitones are in
|
||||
// equal temperament and are doubles; the resulting note would be
|
||||
// retuned by `100 * evt->value` cents.
|
||||
CLAP_NOTE_EXPRESSION_TUNING = 2,
|
||||
|
||||
// 0..1
|
||||
CLAP_NOTE_EXPRESSION_VIBRATO = 3,
|
||||
CLAP_NOTE_EXPRESSION_EXPRESSION = 4,
|
||||
CLAP_NOTE_EXPRESSION_BRIGHTNESS = 5,
|
||||
CLAP_NOTE_EXPRESSION_PRESSURE = 6,
|
||||
};
|
||||
typedef int32_t clap_note_expression;
|
||||
|
||||
typedef struct clap_event_note_expression {
|
||||
clap_event_header_t header;
|
||||
|
||||
clap_note_expression expression_id;
|
||||
|
||||
// target a specific note_id, port, key and channel, with
|
||||
// -1 meaning wildcard, per the wildcard discussion above
|
||||
int32_t note_id;
|
||||
int16_t port_index;
|
||||
int16_t channel;
|
||||
int16_t key;
|
||||
|
||||
double value; // see expression for the range
|
||||
} clap_event_note_expression_t;
|
||||
|
||||
typedef struct clap_event_param_value {
|
||||
clap_event_header_t header;
|
||||
|
||||
// target parameter
|
||||
clap_id param_id; // @ref clap_param_info.id
|
||||
void *cookie; // @ref clap_param_info.cookie
|
||||
|
||||
// target a specific note_id, port, key and channel, with
|
||||
// -1 meaning wildcard, per the wildcard discussion above
|
||||
int32_t note_id;
|
||||
int16_t port_index;
|
||||
int16_t channel;
|
||||
int16_t key;
|
||||
|
||||
double value;
|
||||
} clap_event_param_value_t;
|
||||
|
||||
typedef struct clap_event_param_mod {
|
||||
clap_event_header_t header;
|
||||
|
||||
// target parameter
|
||||
clap_id param_id; // @ref clap_param_info.id
|
||||
void *cookie; // @ref clap_param_info.cookie
|
||||
|
||||
// target a specific note_id, port, key and channel, with
|
||||
// -1 meaning wildcard, per the wildcard discussion above
|
||||
int32_t note_id;
|
||||
int16_t port_index;
|
||||
int16_t channel;
|
||||
int16_t key;
|
||||
|
||||
double amount; // modulation amount
|
||||
} clap_event_param_mod_t;
|
||||
|
||||
typedef struct clap_event_param_gesture {
|
||||
clap_event_header_t header;
|
||||
|
||||
// target parameter
|
||||
clap_id param_id; // @ref clap_param_info.id
|
||||
} clap_event_param_gesture_t;
|
||||
|
||||
enum clap_transport_flags {
|
||||
CLAP_TRANSPORT_HAS_TEMPO = 1 << 0,
|
||||
CLAP_TRANSPORT_HAS_BEATS_TIMELINE = 1 << 1,
|
||||
CLAP_TRANSPORT_HAS_SECONDS_TIMELINE = 1 << 2,
|
||||
CLAP_TRANSPORT_HAS_TIME_SIGNATURE = 1 << 3,
|
||||
CLAP_TRANSPORT_IS_PLAYING = 1 << 4,
|
||||
CLAP_TRANSPORT_IS_RECORDING = 1 << 5,
|
||||
CLAP_TRANSPORT_IS_LOOP_ACTIVE = 1 << 6,
|
||||
CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL = 1 << 7,
|
||||
};
|
||||
|
||||
// clap_event_transport provides song position, tempo, and similar information
|
||||
// from the host to the plugin. There are two ways a host communicates these values.
|
||||
// In the `clap_process` structure sent to each processing block, the host may
|
||||
// provide a transport structure which indicates the available information at the
|
||||
// start of the block. If the host provides sample-accurate tempo or transport changes,
|
||||
// it can also provide subsequent inter-block transport updates by delivering a new event.
|
||||
typedef struct clap_event_transport {
|
||||
clap_event_header_t header;
|
||||
|
||||
uint32_t flags; // see clap_transport_flags
|
||||
|
||||
clap_beattime song_pos_beats; // position in beats
|
||||
clap_sectime song_pos_seconds; // position in seconds
|
||||
|
||||
double tempo; // in bpm
|
||||
double tempo_inc; // tempo increment for each sample and until the next
|
||||
// time info event
|
||||
|
||||
clap_beattime loop_start_beats;
|
||||
clap_beattime loop_end_beats;
|
||||
clap_sectime loop_start_seconds;
|
||||
clap_sectime loop_end_seconds;
|
||||
|
||||
clap_beattime bar_start; // start pos of the current bar
|
||||
int32_t bar_number; // bar at song pos 0 has the number 0
|
||||
|
||||
uint16_t tsig_num; // time signature numerator
|
||||
uint16_t tsig_denom; // time signature denominator
|
||||
} clap_event_transport_t;
|
||||
|
||||
typedef struct clap_event_midi {
|
||||
clap_event_header_t header;
|
||||
|
||||
uint16_t port_index;
|
||||
uint8_t data[3];
|
||||
} clap_event_midi_t;
|
||||
|
||||
// clap_event_midi_sysex contains a pointer to a sysex contents buffer.
|
||||
// The lifetime of this buffer is (from host->plugin) only the process
|
||||
// call in which the event is delivered or (from plugin->host) only the
|
||||
// duration of a try_push call.
|
||||
//
|
||||
// Since `clap_output_events.try_push` requires hosts to make a copy of
|
||||
// an event, host implementers receiving sysex messages from plugins need
|
||||
// to take care to both copy the event (so header, size, etc...) but
|
||||
// also memcpy the contents of the sysex pointer to host-owned memory, and
|
||||
// not just copy the data pointer.
|
||||
//
|
||||
// Similarly plugins retaining the sysex outside the lifetime of a single
|
||||
// process call must copy the sysex buffer to plugin-owned memory.
|
||||
//
|
||||
// As a consequence, the data structure pointed to by the sysex buffer
|
||||
// must be contiguous and copyable with `memcpy` of `size` bytes.
|
||||
typedef struct clap_event_midi_sysex {
|
||||
clap_event_header_t header;
|
||||
|
||||
uint16_t port_index;
|
||||
const uint8_t *buffer; // midi buffer. See lifetime comment above.
|
||||
uint32_t size;
|
||||
} clap_event_midi_sysex_t;
|
||||
|
||||
// While it is possible to use a series of midi2 event to send a sysex,
|
||||
// prefer clap_event_midi_sysex if possible for efficiency.
|
||||
typedef struct clap_event_midi2 {
|
||||
clap_event_header_t header;
|
||||
|
||||
uint16_t port_index;
|
||||
uint32_t data[4];
|
||||
} clap_event_midi2_t;
|
||||
|
||||
// Input event list. The host will deliver these sorted in sample order.
|
||||
typedef struct clap_input_events {
|
||||
void *ctx; // reserved pointer for the list
|
||||
|
||||
// returns the number of events in the list
|
||||
uint32_t(CLAP_ABI *size)(const struct clap_input_events *list);
|
||||
|
||||
// Don't free the returned event, it belongs to the list
|
||||
const clap_event_header_t *(CLAP_ABI *get)(const struct clap_input_events *list, uint32_t index);
|
||||
} clap_input_events_t;
|
||||
|
||||
// Output event list. The plugin must insert events in sample sorted order when inserting events
|
||||
typedef struct clap_output_events {
|
||||
void *ctx; // reserved pointer for the list
|
||||
|
||||
// Pushes a copy of the event
|
||||
// returns false if the event could not be pushed to the queue (out of memory?)
|
||||
bool(CLAP_ABI *try_push)(const struct clap_output_events *list,
|
||||
const clap_event_header_t *event);
|
||||
} clap_output_events_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
63
third_party/clap/include/clap/ext/ambisonic.h
vendored
Normal file
63
third_party/clap/include/clap/ext/ambisonic.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// This extension can be used to specify the channel mapping used by the plugin.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AMBISONIC[] = "clap.ambisonic/3";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AMBISONIC_COMPAT[] = "clap.ambisonic.draft/3";
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_PORT_AMBISONIC[] = "ambisonic";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clap_ambisonic_ordering {
|
||||
// FuMa channel ordering
|
||||
CLAP_AMBISONIC_ORDERING_FUMA = 0,
|
||||
|
||||
// ACN channel ordering
|
||||
CLAP_AMBISONIC_ORDERING_ACN = 1,
|
||||
};
|
||||
|
||||
enum clap_ambisonic_normalization {
|
||||
CLAP_AMBISONIC_NORMALIZATION_MAXN = 0,
|
||||
CLAP_AMBISONIC_NORMALIZATION_SN3D = 1,
|
||||
CLAP_AMBISONIC_NORMALIZATION_N3D = 2,
|
||||
CLAP_AMBISONIC_NORMALIZATION_SN2D = 3,
|
||||
CLAP_AMBISONIC_NORMALIZATION_N2D = 4,
|
||||
};
|
||||
|
||||
typedef struct clap_ambisonic_config {
|
||||
uint32_t ordering; // see clap_ambisonic_ordering
|
||||
uint32_t normalization; // see clap_ambisonic_normalization
|
||||
} clap_ambisonic_config_t;
|
||||
|
||||
typedef struct clap_plugin_ambisonic {
|
||||
// Returns true if the given configuration is supported.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *is_config_supported)(const clap_plugin_t *plugin,
|
||||
const clap_ambisonic_config_t *config);
|
||||
|
||||
// Returns true on success
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_config)(const clap_plugin_t *plugin,
|
||||
bool is_input,
|
||||
uint32_t port_index,
|
||||
clap_ambisonic_config_t *config);
|
||||
|
||||
} clap_plugin_ambisonic_t;
|
||||
|
||||
typedef struct clap_host_ambisonic {
|
||||
// Informs the host that the info has changed.
|
||||
// The info can only change when the plugin is de-activated.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_ambisonic_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
64
third_party/clap/include/clap/ext/audio-ports-activation.h
vendored
Normal file
64
third_party/clap/include/clap/ext/audio-ports-activation.h
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
/// @page Audio Ports Activation
|
||||
///
|
||||
/// This extension provides a way for the host to activate and de-activate audio ports.
|
||||
/// Deactivating a port provides the following benefits:
|
||||
/// - the plugin knows ahead of time that a given input is not present and can choose
|
||||
/// an optimized computation path,
|
||||
/// - the plugin knows that an output is not consumed by the host, and doesn't need to
|
||||
/// compute it.
|
||||
///
|
||||
/// Audio ports can only be activated or deactivated when the plugin is deactivated, unless
|
||||
/// can_activate_while_processing() returns true.
|
||||
///
|
||||
/// Audio buffers must still be provided if the audio port is deactivated.
|
||||
/// In such case, they shall be filled with 0 (or whatever is the neutral value in your context)
|
||||
/// and the constant_mask shall be set.
|
||||
///
|
||||
/// Audio ports are initially in the active state after creating the plugin instance.
|
||||
/// Audio ports state are not saved in the plugin state, so the host must restore the
|
||||
/// audio ports state after creating the plugin instance.
|
||||
///
|
||||
/// Audio ports state is invalidated by clap_plugin_audio_ports_config.select() and
|
||||
/// clap_host_audio_ports.rescan(CLAP_AUDIO_PORTS_RESCAN_LIST).
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_ACTIVATION[] =
|
||||
"clap.audio-ports-activation/2";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_ACTIVATION_COMPAT[] =
|
||||
"clap.audio-ports-activation/draft-2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_audio_ports_activation {
|
||||
// Returns true if the plugin supports activation/deactivation while processing.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *can_activate_while_processing)(const clap_plugin_t *plugin);
|
||||
|
||||
// Activate the given port.
|
||||
//
|
||||
// It is only possible to activate and de-activate on the audio-thread if
|
||||
// can_activate_while_processing() returns true.
|
||||
//
|
||||
// sample_size indicate if the host will provide 32 bit audio buffers or 64 bits one.
|
||||
// Possible values are: 32, 64 or 0 if unspecified.
|
||||
//
|
||||
// returns false if failed, or invalid parameters
|
||||
// [active ? audio-thread : main-thread]
|
||||
bool(CLAP_ABI *set_active)(const clap_plugin_t *plugin,
|
||||
bool is_input,
|
||||
uint32_t port_index,
|
||||
bool is_active,
|
||||
uint32_t sample_size);
|
||||
} clap_plugin_audio_ports_activation_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
109
third_party/clap/include/clap/ext/audio-ports-config.h
vendored
Normal file
109
third_party/clap/include/clap/ext/audio-ports-config.h
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
|
||||
#include "../string-sizes.h"
|
||||
#include "../plugin.h"
|
||||
#include "audio-ports.h"
|
||||
|
||||
/// @page Audio Ports Config
|
||||
///
|
||||
/// This extension let the plugin provide port configurations presets.
|
||||
/// For example mono, stereo, surround, ambisonic, ...
|
||||
///
|
||||
/// After the plugin initialization, the host may scan the list of configurations and eventually
|
||||
/// select one that fits the plugin context. The host can only select a configuration if the plugin
|
||||
/// is deactivated.
|
||||
///
|
||||
/// A configuration is a very simple description of the audio ports:
|
||||
/// - it describes the main input and output ports
|
||||
/// - it has a name that can be displayed to the user
|
||||
///
|
||||
/// The idea behind the configurations, is to let the user choose one via a menu.
|
||||
///
|
||||
/// Plugins with very complex configuration possibilities should let the user configure the ports
|
||||
/// from the plugin GUI, and call @ref clap_host_audio_ports.rescan(CLAP_AUDIO_PORTS_RESCAN_ALL).
|
||||
///
|
||||
/// To inquire the exact bus layout, the plugin implements the clap_plugin_audio_ports_config_info_t
|
||||
/// extension where all busses can be retrieved in the same way as in the audio-port extension.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_CONFIG[] = "clap.audio-ports-config";
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_CONFIG_INFO[] =
|
||||
"clap.audio-ports-config-info/1";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_CONFIG_INFO_COMPAT[] =
|
||||
"clap.audio-ports-config-info/draft-0";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Minimalistic description of ports configuration
|
||||
typedef struct clap_audio_ports_config {
|
||||
clap_id id;
|
||||
char name[CLAP_NAME_SIZE];
|
||||
|
||||
uint32_t input_port_count;
|
||||
uint32_t output_port_count;
|
||||
|
||||
// main input info
|
||||
bool has_main_input;
|
||||
uint32_t main_input_channel_count;
|
||||
const char *main_input_port_type;
|
||||
|
||||
// main output info
|
||||
bool has_main_output;
|
||||
uint32_t main_output_channel_count;
|
||||
const char *main_output_port_type;
|
||||
} clap_audio_ports_config_t;
|
||||
|
||||
// The audio ports config scan has to be done while the plugin is deactivated.
|
||||
typedef struct clap_plugin_audio_ports_config {
|
||||
// Gets the number of available configurations
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Gets information about a configuration
|
||||
// Returns true on success and stores the result into config.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
|
||||
uint32_t index,
|
||||
clap_audio_ports_config_t *config);
|
||||
|
||||
// Selects the configuration designated by id
|
||||
// Returns true if the configuration could be applied.
|
||||
// Once applied the host should scan again the audio ports.
|
||||
// [main-thread & plugin-deactivated]
|
||||
bool(CLAP_ABI *select)(const clap_plugin_t *plugin, clap_id config_id);
|
||||
} clap_plugin_audio_ports_config_t;
|
||||
|
||||
// Extended config info
|
||||
typedef struct clap_plugin_audio_ports_config_info {
|
||||
|
||||
// Gets the id of the currently selected config, or CLAP_INVALID_ID if the current port
|
||||
// layout isn't part of the config list.
|
||||
//
|
||||
// [main-thread]
|
||||
clap_id(CLAP_ABI *current_config)(const clap_plugin_t *plugin);
|
||||
|
||||
// Get info about an audio port, for a given config_id.
|
||||
// This is analogous to clap_plugin_audio_ports.get().
|
||||
// Returns true on success and stores the result into info.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
|
||||
clap_id config_id,
|
||||
uint32_t port_index,
|
||||
bool is_input,
|
||||
clap_audio_port_info_t *info);
|
||||
} clap_plugin_audio_ports_config_info_t;
|
||||
|
||||
typedef struct clap_host_audio_ports_config {
|
||||
// Rescan the full list of configs.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *rescan)(const clap_host_t *host);
|
||||
} clap_host_audio_ports_config_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
116
third_party/clap/include/clap/ext/audio-ports.h
vendored
Normal file
116
third_party/clap/include/clap/ext/audio-ports.h
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
/// @page Audio Ports
|
||||
///
|
||||
/// This extension provides a way for the plugin to describe its current audio ports.
|
||||
///
|
||||
/// If the plugin does not implement this extension, it won't have audio ports.
|
||||
///
|
||||
/// 32 bits support is required for both host and plugins. 64 bits audio is optional.
|
||||
///
|
||||
/// The plugin is only allowed to change its ports configuration while it is deactivated.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS[] = "clap.audio-ports";
|
||||
static CLAP_CONSTEXPR const char CLAP_PORT_MONO[] = "mono";
|
||||
static CLAP_CONSTEXPR const char CLAP_PORT_STEREO[] = "stereo";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// This port is the main audio input or output.
|
||||
// There can be only one main input and main output.
|
||||
// Main port must be at index 0.
|
||||
CLAP_AUDIO_PORT_IS_MAIN = 1 << 0,
|
||||
|
||||
// This port can be used with 64 bits audio
|
||||
CLAP_AUDIO_PORT_SUPPORTS_64BITS = 1 << 1,
|
||||
|
||||
// 64 bits audio is preferred with this port
|
||||
CLAP_AUDIO_PORT_PREFERS_64BITS = 1 << 2,
|
||||
|
||||
// This port must be used with the same sample size as all the other ports which have this flag.
|
||||
// In other words if all ports have this flag then the plugin may either be used entirely with
|
||||
// 64 bits audio or 32 bits audio, but it can't be mixed.
|
||||
CLAP_AUDIO_PORT_REQUIRES_COMMON_SAMPLE_SIZE = 1 << 3,
|
||||
};
|
||||
|
||||
typedef struct clap_audio_port_info {
|
||||
// id identifies a port and must be stable.
|
||||
// id may overlap between input and output ports.
|
||||
clap_id id;
|
||||
char name[CLAP_NAME_SIZE]; // displayable name
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t channel_count;
|
||||
|
||||
// If null or empty then it is unspecified (arbitrary audio).
|
||||
// This field can be compared against:
|
||||
// - CLAP_PORT_MONO
|
||||
// - CLAP_PORT_STEREO
|
||||
// - CLAP_PORT_SURROUND (defined in the surround extension)
|
||||
// - CLAP_PORT_AMBISONIC (defined in the ambisonic extension)
|
||||
//
|
||||
// An extension can provide its own port type and way to inspect the channels.
|
||||
const char *port_type;
|
||||
|
||||
// in-place processing: allow the host to use the same buffer for input and output
|
||||
// if supported set the pair port id.
|
||||
// if not supported set to CLAP_INVALID_ID
|
||||
clap_id in_place_pair;
|
||||
} clap_audio_port_info_t;
|
||||
|
||||
// The audio ports scan has to be done while the plugin is deactivated.
|
||||
typedef struct clap_plugin_audio_ports {
|
||||
// Number of ports, for either input or output
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin, bool is_input);
|
||||
|
||||
// Get info about an audio port.
|
||||
// Returns true on success and stores the result into info.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
|
||||
uint32_t index,
|
||||
bool is_input,
|
||||
clap_audio_port_info_t *info);
|
||||
} clap_plugin_audio_ports_t;
|
||||
|
||||
enum {
|
||||
// The ports name did change, the host can scan them right away.
|
||||
CLAP_AUDIO_PORTS_RESCAN_NAMES = 1 << 0,
|
||||
|
||||
// [!active] The flags did change
|
||||
CLAP_AUDIO_PORTS_RESCAN_FLAGS = 1 << 1,
|
||||
|
||||
// [!active] The channel_count did change
|
||||
CLAP_AUDIO_PORTS_RESCAN_CHANNEL_COUNT = 1 << 2,
|
||||
|
||||
// [!active] The port type did change
|
||||
CLAP_AUDIO_PORTS_RESCAN_PORT_TYPE = 1 << 3,
|
||||
|
||||
// [!active] The in-place pair did change, this requires.
|
||||
CLAP_AUDIO_PORTS_RESCAN_IN_PLACE_PAIR = 1 << 4,
|
||||
|
||||
// [!active] The list of ports have changed: entries have been removed/added.
|
||||
CLAP_AUDIO_PORTS_RESCAN_LIST = 1 << 5,
|
||||
};
|
||||
|
||||
typedef struct clap_host_audio_ports {
|
||||
// Checks if the host allows a plugin to change a given aspect of the audio ports definition.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *is_rescan_flag_supported)(const clap_host_t *host, uint32_t flag);
|
||||
|
||||
// Rescan the full list of audio ports according to the flags.
|
||||
// It is illegal to ask the host to rescan with a flag that is not supported.
|
||||
// Certain flags require the plugin to be de-activated.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *rescan)(const clap_host_t *host, uint32_t flags);
|
||||
} clap_host_audio_ports_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
63
third_party/clap/include/clap/ext/configurable-audio-ports.h
vendored
Normal file
63
third_party/clap/include/clap/ext/configurable-audio-ports.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
|
||||
#include "audio-ports.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This extension lets the host configure the plugin's input and output audio ports.
|
||||
// This is a "push" approach to audio ports configuration.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_CONFIGURABLE_AUDIO_PORTS[] =
|
||||
"clap.configurable-audio-ports/1";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_CONFIGURABLE_AUDIO_PORTS_COMPAT[] =
|
||||
"clap.configurable-audio-ports.draft1";
|
||||
|
||||
typedef struct clap_audio_port_configuration_request {
|
||||
// Identifies the port by is_input and port_index
|
||||
bool is_input;
|
||||
uint32_t port_index;
|
||||
|
||||
// The requested number of channels.
|
||||
uint32_t channel_count;
|
||||
|
||||
// The port type, see audio-ports.h, clap_audio_port_info.port_type for interpretation.
|
||||
const char *port_type;
|
||||
|
||||
// cast port_details according to port_type:
|
||||
// - CLAP_PORT_MONO: (discard)
|
||||
// - CLAP_PORT_STEREO: (discard)
|
||||
// - CLAP_PORT_SURROUND: const uint8_t *channel_map
|
||||
// - CLAP_PORT_AMBISONIC: const clap_ambisonic_config_t *info
|
||||
const void *port_details;
|
||||
} clap_audio_port_configuration_request_t;
|
||||
|
||||
typedef struct clap_plugin_configurable_audio_ports {
|
||||
// Returns true if the given configurations can be applied using apply_configuration().
|
||||
// [main-thread & !active]
|
||||
bool(CLAP_ABI *can_apply_configuration)(
|
||||
const clap_plugin_t *plugin,
|
||||
const struct clap_audio_port_configuration_request *requests,
|
||||
uint32_t request_count);
|
||||
|
||||
// Submit a bunch of configuration requests which will atomically be applied together,
|
||||
// or discarded together.
|
||||
//
|
||||
// Once the configuration is successfully applied, it isn't necessary for the plugin to call
|
||||
// clap_host_audio_ports->changed(); and it isn't necessary for the host to scan the
|
||||
// audio ports.
|
||||
//
|
||||
// Returns true if applied.
|
||||
// [main-thread & !active]
|
||||
bool(CLAP_ABI *apply_configuration)(const clap_plugin_t *plugin,
|
||||
const struct clap_audio_port_configuration_request *requests,
|
||||
uint32_t request_count);
|
||||
} clap_plugin_configurable_audio_ports_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
167
third_party/clap/include/clap/ext/context-menu.h
vendored
Normal file
167
third_party/clap/include/clap/ext/context-menu.h
vendored
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// This extension lets the host and plugin exchange menu items and let the plugin ask the host to
|
||||
// show its context menu.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_CONTEXT_MENU[] = "clap.context-menu/1";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_CONTEXT_MENU_COMPAT[] = "clap.context-menu.draft/0";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// There can be different target kind for a context menu
|
||||
enum {
|
||||
CLAP_CONTEXT_MENU_TARGET_KIND_GLOBAL = 0,
|
||||
CLAP_CONTEXT_MENU_TARGET_KIND_PARAM = 1,
|
||||
};
|
||||
|
||||
// Describes the context menu target
|
||||
typedef struct clap_context_menu_target {
|
||||
uint32_t kind;
|
||||
clap_id id;
|
||||
} clap_context_menu_target_t;
|
||||
|
||||
enum {
|
||||
// Adds a clickable menu entry.
|
||||
// data: const clap_context_menu_item_entry_t*
|
||||
CLAP_CONTEXT_MENU_ITEM_ENTRY,
|
||||
|
||||
// Adds a clickable menu entry which will feature both a checkmark and a label.
|
||||
// data: const clap_context_menu_item_check_entry_t*
|
||||
CLAP_CONTEXT_MENU_ITEM_CHECK_ENTRY,
|
||||
|
||||
// Adds a separator line.
|
||||
// data: NULL
|
||||
CLAP_CONTEXT_MENU_ITEM_SEPARATOR,
|
||||
|
||||
// Starts a sub menu with the given label.
|
||||
// data: const clap_context_menu_item_begin_submenu_t*
|
||||
CLAP_CONTEXT_MENU_ITEM_BEGIN_SUBMENU,
|
||||
|
||||
// Ends the current sub menu.
|
||||
// data: NULL
|
||||
CLAP_CONTEXT_MENU_ITEM_END_SUBMENU,
|
||||
|
||||
// Adds a title entry
|
||||
// data: const clap_context_menu_item_title_t *
|
||||
CLAP_CONTEXT_MENU_ITEM_TITLE,
|
||||
};
|
||||
typedef uint32_t clap_context_menu_item_kind_t;
|
||||
|
||||
typedef struct clap_context_menu_entry {
|
||||
// text to be displayed
|
||||
const char *label;
|
||||
|
||||
// if false, then the menu entry is greyed out and not clickable
|
||||
bool is_enabled;
|
||||
clap_id action_id;
|
||||
} clap_context_menu_entry_t;
|
||||
|
||||
typedef struct clap_context_menu_check_entry {
|
||||
// text to be displayed
|
||||
const char *label;
|
||||
|
||||
// if false, then the menu entry is greyed out and not clickable
|
||||
bool is_enabled;
|
||||
|
||||
// if true, then the menu entry will be displayed as checked
|
||||
bool is_checked;
|
||||
clap_id action_id;
|
||||
} clap_context_menu_check_entry_t;
|
||||
|
||||
typedef struct clap_context_menu_item_title {
|
||||
// text to be displayed
|
||||
const char *title;
|
||||
|
||||
// if false, then the menu entry is greyed out
|
||||
bool is_enabled;
|
||||
} clap_context_menu_item_title_t;
|
||||
|
||||
typedef struct clap_context_menu_submenu {
|
||||
// text to be displayed
|
||||
const char *label;
|
||||
|
||||
// if false, then the menu entry is greyed out and won't show submenu
|
||||
bool is_enabled;
|
||||
} clap_context_menu_submenu_t;
|
||||
|
||||
// Context menu builder.
|
||||
// This object isn't thread-safe and must be used on the same thread as it was provided.
|
||||
typedef struct clap_context_menu_builder {
|
||||
void *ctx;
|
||||
|
||||
// Adds an entry to the menu.
|
||||
// item_data type is determined by item_kind.
|
||||
// Returns true on success.
|
||||
bool(CLAP_ABI *add_item)(const struct clap_context_menu_builder *builder,
|
||||
clap_context_menu_item_kind_t item_kind,
|
||||
const void *item_data);
|
||||
|
||||
// Returns true if the menu builder supports the given item kind
|
||||
bool(CLAP_ABI *supports)(const struct clap_context_menu_builder *builder,
|
||||
clap_context_menu_item_kind_t item_kind);
|
||||
} clap_context_menu_builder_t;
|
||||
|
||||
typedef struct clap_plugin_context_menu {
|
||||
// Insert plugin's menu items into the menu builder.
|
||||
// If target is null, assume global context.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *populate)(const clap_plugin_t *plugin,
|
||||
const clap_context_menu_target_t *target,
|
||||
const clap_context_menu_builder_t *builder);
|
||||
|
||||
// Performs the given action, which was previously provided to the host via populate().
|
||||
// If target is null, assume global context.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *perform)(const clap_plugin_t *plugin,
|
||||
const clap_context_menu_target_t *target,
|
||||
clap_id action_id);
|
||||
} clap_plugin_context_menu_t;
|
||||
|
||||
typedef struct clap_host_context_menu {
|
||||
// Insert host's menu items into the menu builder.
|
||||
// If target is null, assume global context.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *populate)(const clap_host_t *host,
|
||||
const clap_context_menu_target_t *target,
|
||||
const clap_context_menu_builder_t *builder);
|
||||
|
||||
// Performs the given action, which was previously provided to the plugin via populate().
|
||||
// If target is null, assume global context.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *perform)(const clap_host_t *host,
|
||||
const clap_context_menu_target_t *target,
|
||||
clap_id action_id);
|
||||
|
||||
// Returns true if the host can display a popup menu for the plugin.
|
||||
// This may depend upon the current windowing system used to display the plugin, so the
|
||||
// return value is invalidated after creating the plugin window.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *can_popup)(const clap_host_t *host);
|
||||
|
||||
// Shows the host popup menu for a given parameter.
|
||||
// If the plugin is using embedded GUI, then x and y are relative to the plugin's window,
|
||||
// otherwise they're absolute coordinate, and screen index might be set accordingly.
|
||||
// If target is null, assume global context.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *popup)(const clap_host_t *host,
|
||||
const clap_context_menu_target_t *target,
|
||||
int32_t screen_index,
|
||||
int32_t x,
|
||||
int32_t y);
|
||||
} clap_host_context_menu_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
45
third_party/clap/include/clap/ext/draft/background-activation.h
vendored
Normal file
45
third_party/clap/include/clap/ext/draft/background-activation.h
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page background activation
|
||||
/// @brief Activate and Deactivate from a background thread.
|
||||
///
|
||||
/// Some plugin needs to perform complex computation or even I/O during activation
|
||||
/// and this blocks the main thread.
|
||||
///
|
||||
/// This extension is here to offer an alternative way to activate the plugin from a background
|
||||
/// thread, to keep the main-thread running.
|
||||
///
|
||||
/// Background activation must not be concurrent to a plugin activation/deactivation on the
|
||||
/// main-thread.
|
||||
///
|
||||
/// Implementing this extension implies that background activation and deactivation
|
||||
/// are beneficial and preferred for this plugin.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_BACKGROUND_ACTIVATION[] = "clap.background-activation/1";
|
||||
|
||||
typedef struct clap_plugin_background_activation {
|
||||
// Same as clap_plugin.activate() but it is called from a background thread.
|
||||
// See clap_host_background_progress for progress feedback and cancelation.
|
||||
//
|
||||
// [background-thread]
|
||||
bool(CLAP_ABI *activate_from_background_thread)(clap_plugin_t *plugin,
|
||||
double sample_rate,
|
||||
uint32_t min_frames_count,
|
||||
uint32_t max_frames_count);
|
||||
|
||||
// Same as clap_plugin.deactivate() but it is called from a background thread.
|
||||
// See clap_host_background_progress for progress feedback and cancelation.
|
||||
//
|
||||
// [background-thread]
|
||||
void(CLAP_ABI *deactivate_from_background_thread)(const struct clap_plugin *plugin);
|
||||
} clap_plugin_background_activation_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
51
third_party/clap/include/clap/ext/draft/background-progress.h
vendored
Normal file
51
third_party/clap/include/clap/ext/draft/background-progress.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "../state.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page background-progress
|
||||
///
|
||||
/// @brief Let the plugin report progress to the host for the current background task, and check for
|
||||
/// cancelation as well.
|
||||
///
|
||||
/// This interface reports progress and checks for cancelation for the task currently active on this
|
||||
/// background thread.
|
||||
///
|
||||
/// This interface is used by CLAP_EXT_BACKGROUND_ACTIVATION and CLAP_EXT_BACKGROUND_STATE_CONTEXT.
|
||||
///
|
||||
/// Typical execution:
|
||||
/// plugin->do_something_from_background_thread() {
|
||||
/// while (!host->is_canceled()) {
|
||||
/// // do some work
|
||||
/// host->progress(x, "doing something");
|
||||
/// }
|
||||
/// }
|
||||
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_BACKGROUND_PROGRESS[] = "clap.background-progress/1";
|
||||
|
||||
typedef struct clap_host_background_progress {
|
||||
// Returns true if the host wants to cancel this task.
|
||||
// [background-thread]
|
||||
bool(CLAP_ABI *is_canceled)(const clap_host_t *host);
|
||||
|
||||
// Reports progress to the host.
|
||||
// The progress value is from 0 to 1.
|
||||
// 0 at the begining and 1 at the end.
|
||||
//
|
||||
// Be aware that the progress may go backward if a sub-task fails and the plugin decides to retry
|
||||
// it.
|
||||
//
|
||||
// msg: an optional null terminated message (maybe nullptr) explaining what the plugin is currently
|
||||
// doing. For example: "Downloading xxx...", "Analyzing...", "Connecting to HW...", and so on.
|
||||
//
|
||||
// [background-thread]
|
||||
void(CLAP_ABI *progress)(const clap_host_t *host, double progress, const char *msg);
|
||||
} clap_host_background_progress_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
44
third_party/clap/include/clap/ext/draft/background-state-context.h
vendored
Normal file
44
third_party/clap/include/clap/ext/draft/background-state-context.h
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "../state-context.h"
|
||||
|
||||
/// @page background state context
|
||||
/// @brief Save and Load state from a background thread.
|
||||
///
|
||||
/// Some plugin needs to perform complex computation or even I/O during state loading or saving and
|
||||
/// this blocks the main thread.
|
||||
///
|
||||
/// This extension is here to offer an alternative way to load or save the plugin from a
|
||||
/// background thread, to keep the main-thread running.
|
||||
///
|
||||
/// Background save and load must not be concurrent to main-thread save and load.
|
||||
///
|
||||
/// Implementing this extension implies that background state saving and loading
|
||||
/// are beneficial and preferred for this plugin.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_BACKGROUND_STATE_CONTEXT[] =
|
||||
"clap.background-state-context/1";
|
||||
|
||||
typedef struct clap_plugin_background_state_context {
|
||||
// Same as clap_plugin_state_context.save() but it is called from a background thread.
|
||||
// See clap_host_background_progress for progress feedback and cancelation.
|
||||
// [background-thread]
|
||||
bool(CLAP_ABI *save_from_background_thread)(const clap_plugin_t *plugin,
|
||||
const clap_ostream_t *stream,
|
||||
uint32_t context_type);
|
||||
|
||||
// Same as clap_plugin_state_context.load() but it is called from a background thread.
|
||||
// See clap_host_background_progress for progress feedback and cancelation.
|
||||
// [background-thread]
|
||||
bool(CLAP_ABI *load_from_background_thread)(const clap_plugin_t *plugin,
|
||||
const clap_istream_t *stream,
|
||||
uint32_t context_type);
|
||||
} clap_plugin_background_state_context_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
33
third_party/clap/include/clap/ext/draft/extensible-audio-ports.h
vendored
Normal file
33
third_party/clap/include/clap/ext/draft/extensible-audio-ports.h
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "../audio-ports.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This extension lets the host add and remove audio ports to the plugin.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_EXTENSIBLE_AUDIO_PORTS[] =
|
||||
"clap.extensible-audio-ports/1";
|
||||
|
||||
typedef struct clap_plugin_extensible_audio_ports {
|
||||
// Asks the plugin to add a new port (at the end of the list), with the following settings.
|
||||
// port_type: see clap_audio_port_info.port_type for interpretation.
|
||||
// port_details: see clap_audio_port_configuration_request.port_details for interpretation.
|
||||
// Returns true on success.
|
||||
// [main-thread & !active]
|
||||
bool(CLAP_ABI *add_port)(const clap_plugin_t *plugin,
|
||||
bool is_input,
|
||||
uint32_t channel_count,
|
||||
const char *port_type,
|
||||
const void *port_details);
|
||||
|
||||
// Asks the plugin to remove a port.
|
||||
// Returns true on success.
|
||||
// [main-thread & !active]
|
||||
bool(CLAP_ABI *remove_port)(const clap_plugin_t *plugin, bool is_input, uint32_t index);
|
||||
} clap_plugin_extensible_audio_ports_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
48
third_party/clap/include/clap/ext/draft/flush-events.h
vendored
Normal file
48
third_party/clap/include/clap/ext/draft/flush-events.h
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page flush events
|
||||
///
|
||||
/// This interface is useful to exchange events with the plugin while not processing.
|
||||
///
|
||||
/// This is useful to perform MIDI 2.0 non realtime communication on the main-thread
|
||||
/// before activating the plugin.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_FLUSH_EVENTS[] = "clap.flush-events/1";
|
||||
|
||||
typedef struct clap_plugin_flush_events {
|
||||
// Flushes a set of events.
|
||||
// This method must not be called concurrently to clap_plugin->process().
|
||||
//
|
||||
// Note: if the plugin is processing, then the process() call will already perform events I/O, so
|
||||
// a call to flush isn't required, also be aware that the plugin may use the sample offset in
|
||||
// process(), while this information would be lost within flush().
|
||||
//
|
||||
// [active ? audio-thread : main-thread]
|
||||
void(CLAP_ABI *flush)(const clap_plugin_t *plugin,
|
||||
const clap_input_events_t *in,
|
||||
const clap_output_events_t *out);
|
||||
} clap_plugin_flush_events_t;
|
||||
|
||||
typedef struct clap_host_flush_events {
|
||||
// Request an event flush.
|
||||
//
|
||||
// The host will then schedule a call to either:
|
||||
// - clap_plugin.process()
|
||||
// - clap_plugin_flush_events.flush()
|
||||
//
|
||||
// This function is always safe to use and should not be called from an [audio-thread] as the
|
||||
// plugin would already be within process() or flush().
|
||||
//
|
||||
// [thread-safe,!audio-thread]
|
||||
void(CLAP_ABI *request_flush)(const clap_host_t *host);
|
||||
} clap_host_flush_events_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
34
third_party/clap/include/clap/ext/draft/gain-adjustment-metering.h
vendored
Normal file
34
third_party/clap/include/clap/ext/draft/gain-adjustment-metering.h
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension lets the plugin report the current gain adjustment
|
||||
// (typically, gain reduction) to the host.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_GAIN_ADJUSTMENT_METERING[] = "clap.gain-adjustment-metering/0";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_gain_adjustment_metering {
|
||||
// Returns the current gain adjustment in dB. The value is intended
|
||||
// for informational display, for example in a host meter or tooltip.
|
||||
// The returned value represents the gain adjustment that the plugin
|
||||
// applied to the last sample in the most recently processed block.
|
||||
//
|
||||
// The returned value is in dB. Zero means the plugin is applying no gain
|
||||
// reduction, or is not processing. A negative value means the plugin is
|
||||
// applying gain reduction, as with a compressor or limiter. A positive
|
||||
// value means the plugin is adding gain, as with an expander. The value
|
||||
// represents the dynamic gain reduction or expansion applied by the
|
||||
// plugin, before any make-up gain or other adjustment. A single value is
|
||||
// returned for all audio channels.
|
||||
//
|
||||
// [audio-thread]
|
||||
double(CLAP_ABI *get)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_gain_adjustment_metering_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
153
third_party/clap/include/clap/ext/draft/mini-curve-display.h
vendored
Normal file
153
third_party/clap/include/clap/ext/draft/mini-curve-display.h
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension allows a host to render a small curve provided by the plugin.
|
||||
// A useful application is to render an EQ frequency response in the DAW mixer view.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_MINI_CURVE_DISPLAY[] = "clap.mini-curve-display/3";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clap_mini_curve_display_curve_kind {
|
||||
// If the curve's kind doesn't fit in any proposed kind, use this one
|
||||
// and perhaps, make a pull request to extend the list.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_UNSPECIFIED = 0,
|
||||
|
||||
// The mini curve is intended to draw the total gain response of the plugin.
|
||||
// In this case the y values are in dB and the x values are in Hz (logarithmic).
|
||||
// This would be useful in for example an equalizer.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_GAIN_RESPONSE = 1,
|
||||
|
||||
// The mini curve is intended to draw the total phase response of the plugin.
|
||||
// In this case the y values are in radians and the x values are in Hz (logarithmic).
|
||||
// This would be useful in for example an equalizer.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_PHASE_RESPONSE = 2,
|
||||
|
||||
// The mini curve is intended to draw the transfer curve of the plugin.
|
||||
// In this case the both x and y values are in dB.
|
||||
// This would be useful in for example a compressor or distortion plugin.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_TRANSFER_CURVE = 3,
|
||||
|
||||
// This mini curve is intended to draw gain reduction over time. In this case
|
||||
// x refers to the window in seconds and y refers to level in dB, x_min is
|
||||
// always 0, and x_max would be the duration of the window.
|
||||
// This would be useful in for example a compressor or limiter.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_GAIN_REDUCTION = 4,
|
||||
|
||||
// This curve is intended as a generic time series plot. In this case
|
||||
// x refers to the window in seconds. x_min is always 0, and x_max would be the duration of the
|
||||
// window.
|
||||
// Y is not specified and up to the plugin.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_KIND_TIME_SERIES = 5,
|
||||
|
||||
// Note: more entries could be added here in the future
|
||||
};
|
||||
|
||||
typedef struct clap_mini_curve_display_curve_hints {
|
||||
|
||||
// Range for the x axis.
|
||||
double x_min;
|
||||
double x_max;
|
||||
|
||||
// Range for the y axis.
|
||||
double y_min;
|
||||
double y_max;
|
||||
|
||||
} clap_mini_curve_display_curve_hints_t;
|
||||
|
||||
// A set of points representing the curve to be painted.
|
||||
typedef struct clap_mini_curve_display_curve_data {
|
||||
// Indicates the kind of curve those values represent, the host can use this
|
||||
// information to paint the curve using a meaningful color.
|
||||
int32_t curve_kind;
|
||||
|
||||
// values[0] will be the leftmost value and values[data_size -1] will be the rightmost
|
||||
// value.
|
||||
//
|
||||
// The value 0 and UINT16_MAX won't be painted.
|
||||
// The value 1 will be at the bottom of the curve and UINT16_MAX - 1 will be at the top.
|
||||
uint16_t *values;
|
||||
uint32_t values_count;
|
||||
} clap_mini_curve_display_curve_data_t;
|
||||
|
||||
typedef struct clap_plugin_mini_curve_display {
|
||||
// Returns the number of curves the plugin wants to paint.
|
||||
// Be aware that the space to display those curves will be small, and too much data will make
|
||||
// the output hard to read.
|
||||
uint32_t(CLAP_ABI *get_curve_count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Renders the curve into each the curves buffer.
|
||||
//
|
||||
// curves is an array, and each entries (up to curves_size) contains pre-allocated
|
||||
// values buffer that must be filled by the plugin.
|
||||
//
|
||||
// The host will "stack" the curves, from the first one to the last one.
|
||||
// curves[0] is the first curve to be painted.
|
||||
// curves[n + 1] will be painted over curves[n].
|
||||
//
|
||||
// Returns the number of curves rendered.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *render)(const clap_plugin_t *plugin,
|
||||
clap_mini_curve_display_curve_data_t *curves,
|
||||
uint32_t curves_size);
|
||||
|
||||
// Tells the plugin if the curve is currently observed or not.
|
||||
// When it isn't observed render() can't be called.
|
||||
//
|
||||
// When is_obseverd becomes true, the curve content and axis name are implicitly invalidated. So
|
||||
// the plugin don't need to call host->changed.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_observed)(const clap_plugin_t *plugin, bool is_observed);
|
||||
|
||||
// Retrives the axis name.
|
||||
// x_name and y_name must not to be null.
|
||||
// Returns true on success, if the name capacity was sufficient.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_axis_name)(const clap_plugin_t *plugin,
|
||||
uint32_t curve_index,
|
||||
char *x_name,
|
||||
char *y_name,
|
||||
uint32_t name_capacity);
|
||||
} clap_plugin_mini_curve_display_t;
|
||||
|
||||
enum clap_mini_curve_display_change_flags {
|
||||
// Informs the host that the curve content changed.
|
||||
// Can only be called if the curve is observed and is static.
|
||||
CLAP_MINI_CURVE_DISPLAY_CURVE_CHANGED = 1 << 0,
|
||||
|
||||
// Informs the host that the curve axis name changed.
|
||||
// Can only be called if the curve is observed.
|
||||
CLAP_MINI_CURVE_DISPLAY_AXIS_NAME_CHANGED = 1 << 1,
|
||||
};
|
||||
|
||||
typedef struct clap_host_mini_curve_display {
|
||||
// Fills in the given clap_mini_display_curve_hints_t structure and returns
|
||||
// true if successful. If not, return false.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_hints)(const clap_host_t *host,
|
||||
uint32_t kind,
|
||||
clap_mini_curve_display_curve_hints_t *hints);
|
||||
|
||||
// Mark the curve as being static or dynamic.
|
||||
// The curve is initially considered as static, though the plugin should explicitely
|
||||
// initialize this state.
|
||||
//
|
||||
// When static, the curve changes will be notified by calling host->changed().
|
||||
// When dynamic, the curve is constantly changing and the host is expected to
|
||||
// periodically re-render.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_dynamic)(const clap_host_t *host, bool is_dynamic);
|
||||
|
||||
// See clap_mini_curve_display_change_flags
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host, uint32_t flags);
|
||||
} clap_host_mini_curve_display_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
30
third_party/clap/include/clap/ext/draft/octave-number.h
vendored
Normal file
30
third_party/clap/include/clap/ext/draft/octave-number.h
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension allows a host to communicate to a plugin the
|
||||
// octave number associated with MIDI Note 60 (aka "Middle C").
|
||||
// Since various hosts and standards call note 60 either C3, C4 or C5,
|
||||
// host displays and plugin displays often mismatch absent this information
|
||||
// being shared.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_OCTAVE_NUMBER[] = "clap.octave-number/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_octave_number {
|
||||
// If displaying the name of a note, and using standard CDEFGAB scale note names
|
||||
// on a piano-roll-like display, this api will tell the plugin which octave number is
|
||||
// associated with note 60. For instance, calling this with '3' would indicate to
|
||||
// the plugin that the consistent name for note 60 is "C3", for 72 is "C4" etc...
|
||||
// if using CDEFGAB note names across a 12 note display.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_note60_octave)(const clap_plugin_t *plugin,
|
||||
int8_t octave_number);
|
||||
} clap_plugin_octave_number_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
29
third_party/clap/include/clap/ext/draft/param-hovered.h
vendored
Normal file
29
third_party/clap/include/clap/ext/draft/param-hovered.h
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension lets a plugin report to the host the parameter's clap_id of its last hovered UI
|
||||
// control and whether it is currently hovered (usually hovered by pointer device).
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PARAM_HOVERED[] = "clap.param-hovered/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_host_param_hovered {
|
||||
// Plugin informs the host about a new hover state.
|
||||
//
|
||||
// Should be called whenever the hovered UI control's parameter ID changes or when it changes
|
||||
// from hovered to not being hovered.
|
||||
//
|
||||
// Only one parameter can be hovered at a time. Use CLAP_INVALID_ID as param_id if no parameter
|
||||
// is hovered.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *update)(const clap_host_t *host, clap_id hovered_param_id);
|
||||
} clap_host_param_hovered_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
61
third_party/clap/include/clap/ext/draft/params-origin.h
vendored
Normal file
61
third_party/clap/include/clap/ext/draft/params-origin.h
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PARAMS_ORIGIN[] = "clap.params-origin/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// This extension provides an optional value per parameter that lets the host draw a visual
|
||||
/// indication for the parameter's origin.
|
||||
///
|
||||
/// examples:
|
||||
/// - lowpass filter cutoff parameter with an origin equal to param_info.min_value
|
||||
/// [--------------> ]
|
||||
/// 60Hz 20kHz
|
||||
/// min=origin max
|
||||
/// - highpass filter cutoff parameter with an origin equal to param_info.max_value
|
||||
/// [ <--------------]
|
||||
/// 60Hz 20kHz
|
||||
/// min max=origin
|
||||
/// - (bipolar) parameter with a range from -1.0 to +1.0 with an origin of 0.0
|
||||
/// [ <------| ]
|
||||
/// -1.0 0.0 +1.0
|
||||
/// min origin max
|
||||
/// - crossfade parameter without an origin
|
||||
/// [ o ]
|
||||
/// A B
|
||||
/// min max
|
||||
|
||||
typedef struct clap_plugin_params_origin {
|
||||
// Get the origin value for a parameter.
|
||||
// Returns false if the parameter has no origin, true otherwise.
|
||||
// The host must not call this for params with CLAP_PARAM_IS_ENUM flag set.
|
||||
//
|
||||
// out_value constraints:
|
||||
// - has to be in the range from param_info.min_value to param_info.max_value
|
||||
// - has to be an integer value if CLAP_PARAM_IS_STEPPED flag is set
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin, clap_id param_id, double *out_value);
|
||||
} clap_plugin_params_origin_t;
|
||||
|
||||
typedef struct clap_host_params_origin {
|
||||
// Informs the host that param origins have changed.
|
||||
//
|
||||
// Note: If the plugin calls params.rescan with CLAP_PARAM_RESCAN_ALL, all previously scanned
|
||||
// parameter origins must be considered invalid. It is thus not necessary for the plugin to call
|
||||
// param_origin.changed in this case.
|
||||
//
|
||||
// Note: This is useful if a parameter origin changes on-the-fly. For example a plugin might want
|
||||
// to change the origin of a filter cutoff frequency parameter when the corresponding filter type
|
||||
// (LP/BP/HP) has changed.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_params_origin_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
108
third_party/clap/include/clap/ext/draft/project-location.h
vendored
Normal file
108
third_party/clap/include/clap/ext/draft/project-location.h
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../color.h"
|
||||
#include "../../plugin.h"
|
||||
#include "../../string-sizes.h"
|
||||
|
||||
// This extension allows a host to tell the plugin more about its position
|
||||
// within a project or session.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PROJECT_LOCATION[] = "clap.project-location/2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clap_project_location_kind {
|
||||
// Represents a document/project/session.
|
||||
CLAP_PROJECT_LOCATION_PROJECT = 1,
|
||||
|
||||
// Represents a group of tracks.
|
||||
// It can contain track groups, tracks, and devices (post processing).
|
||||
// The first device within a track group has the index of
|
||||
// the last track or track group within this group + 1.
|
||||
CLAP_PROJECT_LOCATION_TRACK_GROUP = 2,
|
||||
|
||||
// Represents a single track.
|
||||
// It contains devices (serial).
|
||||
CLAP_PROJECT_LOCATION_TRACK = 3,
|
||||
|
||||
// Represents a single device.
|
||||
// It can contain other nested device chains.
|
||||
CLAP_PROJECT_LOCATION_DEVICE = 4,
|
||||
|
||||
// Represents a nested device chain (serial).
|
||||
// Its parent must be a device.
|
||||
// It contains other devices.
|
||||
CLAP_PROJECT_LOCATION_NESTED_DEVICE_CHAIN = 5,
|
||||
};
|
||||
|
||||
enum clap_project_location_track_kind {
|
||||
// This track is an instrument track.
|
||||
CLAP_PROJECT_LOCATION_INSTUMENT_TRACK = 1,
|
||||
|
||||
// This track is an audio track.
|
||||
CLAP_PROJECT_LOCATION_AUDIO_TRACK = 2,
|
||||
|
||||
// This track is both an instrument and audio track.
|
||||
CLAP_PROJECT_LOCATION_HYBRID_TRACK = 3,
|
||||
|
||||
// This track is a return track.
|
||||
CLAP_PROJECT_LOCATION_RETURN_TRACK = 4,
|
||||
|
||||
// This track is a master track.
|
||||
// Each group have a master track for processing the sum of all its children tracks.
|
||||
CLAP_PROJECT_LOCATION_MASTER_TRACK = 5,
|
||||
};
|
||||
|
||||
enum clap_project_location_flags {
|
||||
CLAP_PROJECT_LOCATION_HAS_INDEX = 1 << 0,
|
||||
CLAP_PROJECT_LOCATION_HAS_COLOR = 1 << 1,
|
||||
};
|
||||
|
||||
typedef struct clap_project_location_element {
|
||||
// A bit-mask, see clap_project_location_flags.
|
||||
uint64_t flags;
|
||||
|
||||
// Kind of the element, must be one of the CLAP_PROJECT_LOCATION_* values.
|
||||
uint32_t kind;
|
||||
|
||||
// Only relevant if kind is CLAP_PLUGIN_LOCATION_TRACK.
|
||||
// see enum CLAP_PROJECT_LOCATION_track_kind.
|
||||
uint32_t track_kind;
|
||||
|
||||
// Index within the parent element.
|
||||
// Only usable if CLAP_PROJECT_LOCATION_HAS_INDEX is set in flags.
|
||||
uint32_t index;
|
||||
|
||||
// Internal ID of the element.
|
||||
// This is not intended for display to the user,
|
||||
// but rather to give the host a potential quick way for lookups.
|
||||
char id[CLAP_PATH_SIZE];
|
||||
|
||||
// User friendly name of the element.
|
||||
char name[CLAP_NAME_SIZE];
|
||||
|
||||
// Color for this element.
|
||||
// Only usable if CLAP_PROJECT_LOCATION_HAS_COLOR is set in flags.
|
||||
clap_color_t color;
|
||||
} clap_project_location_element_t;
|
||||
|
||||
typedef struct clap_plugin_project_location {
|
||||
// Called by the host when the location of the plugin instance changes.
|
||||
//
|
||||
// The last item in this array always refers to the device itself, and as
|
||||
// such is expected to be of kind CLAP_PLUGIN_LOCATION_DEVICE.
|
||||
// The first item in this array always refers to the project this device is in and must be of
|
||||
// kind CLAP_PROJECT_LOCATION_PROJECT. The path is expected to be something like: PROJECT >
|
||||
// TRACK_GROUP+ > TRACK > (DEVICE > NESTED_DEVICE_CHAIN)* > DEVICE
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set)(const clap_plugin_t *plugin,
|
||||
const clap_project_location_element_t *path,
|
||||
uint32_t num_elements);
|
||||
} clap_plugin_project_location_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
88
third_party/clap/include/clap/ext/draft/resource-directory.h
vendored
Normal file
88
third_party/clap/include/clap/ext/draft/resource-directory.h
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_RESOURCE_DIRECTORY[] = "clap.resource-directory/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page Resource Directory
|
||||
///
|
||||
/// This extension provides a way for the plugin to store its resources as file in a directory
|
||||
/// provided by the host and recover them later on.
|
||||
///
|
||||
/// The plugin **must** store relative path in its state toward resource directories.
|
||||
///
|
||||
/// Resource sharing:
|
||||
/// - shared directory is shared among all plugin instances, hence mostly appropriate for read-only
|
||||
/// content
|
||||
/// -> suitable for read-only content
|
||||
/// - exclusive directory is exclusive to the plugin instance
|
||||
/// -> if the plugin, then its exclusive directory must be duplicated too
|
||||
/// -> suitable for read-write content
|
||||
///
|
||||
/// Keeping the shared directory clean:
|
||||
/// - to avoid clashes in the shared directory, plugins are encouraged to organize their files in
|
||||
/// sub-folders, for example create one subdirectory using the vendor name
|
||||
/// - don't use symbolic links or hard links which points outside of the directory
|
||||
///
|
||||
/// Resource life-time:
|
||||
/// - exclusive folder content is managed by the plugin instance
|
||||
/// - exclusive folder content is deleted when the plugin instance is removed from the project
|
||||
/// - shared folder content isn't managed by the host, until all plugins using the shared directory
|
||||
/// are removed from the project
|
||||
///
|
||||
/// Note for the host
|
||||
/// - try to use the filesystem's copy-on-write feature when possible for reducing exclusive folder
|
||||
/// space usage on duplication
|
||||
/// - host can "garbage collect" the files in the shared folder using:
|
||||
/// clap_plugin_resource_directory.get_files_count()
|
||||
/// clap_plugin_resource_directory.get_file_path()
|
||||
/// but be **very** careful before deleting any resources
|
||||
|
||||
typedef struct clap_plugin_resource_directory {
|
||||
// Sets the directory in which the plugin can save its resources.
|
||||
// The directory remains valid until it is overridden or the plugin is destroyed.
|
||||
// If path is null or blank, it clears the directory location.
|
||||
// path must be absolute.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_directory)(const clap_plugin_t *plugin, const char *path, bool is_shared);
|
||||
|
||||
// Asks the plugin to put its resources into the resource directory.
|
||||
// It is not necessary to collect files which belongs to the plugin's
|
||||
// factory content unless the param all is true.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *collect)(const clap_plugin_t *plugin, bool all);
|
||||
|
||||
// Returns the number of files used by the plugin in the shared resource folder.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *get_files_count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Retrieves relative file path to the resource directory.
|
||||
// @param path writable memory to store the path
|
||||
// @param path_size number of available bytes in path
|
||||
// Returns the number of bytes in the path, or -1 on error
|
||||
// [main-thread]
|
||||
int32_t(CLAP_ABI *get_file_path)(const clap_plugin_t *plugin,
|
||||
uint32_t index,
|
||||
char *path,
|
||||
uint32_t path_size);
|
||||
} clap_plugin_resource_directory_t;
|
||||
|
||||
typedef struct clap_host_resource_directory {
|
||||
// Request the host to setup a resource directory with the specified sharing.
|
||||
// Returns true if the host will perform the request.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *request_directory)(const clap_host_t *host, bool is_shared);
|
||||
|
||||
// Tell the host that the resource directory of the specified sharing is no longer required.
|
||||
// If is_shared = false, then the host may delete the directory content.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *release_directory)(const clap_host_t *host, bool is_shared);
|
||||
} clap_host_resource_directory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
90
third_party/clap/include/clap/ext/draft/scratch-memory.h
vendored
Normal file
90
third_party/clap/include/clap/ext/draft/scratch-memory.h
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension lets the plugin request "scratch" memory from the host.
|
||||
//
|
||||
// The scratch memory is thread-local, and can be accessed during
|
||||
// `clap_plugin->process()` and `clap_plugin_thread_pool->exec()`;
|
||||
// its content is not persistent between callbacks.
|
||||
//
|
||||
// The motivation for this extension is to allow the plugin host
|
||||
// to "share" a single scratch buffer across multiple plugin
|
||||
// instances.
|
||||
//
|
||||
// For example, imagine the host needs to process N plugins
|
||||
// in sequence, and each plugin requires 10K of scratch memory.
|
||||
// If each plugin pre-allocates its own scratch memory, then N * 10K
|
||||
// of memory is being allocated in total. However, if each plugin
|
||||
// requests 10K of scratch memory from the host, then the host can
|
||||
// allocate a single 10K scratch buffer, and make it available to all
|
||||
// plugins.
|
||||
//
|
||||
// This optimization may allow for reduced memory usage and improved
|
||||
// CPU cache usage.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_SCRATCH_MEMORY[] = "clap.scratch-memory/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_host_scratch_memory {
|
||||
// Asks the host to reserve scratch memory.
|
||||
//
|
||||
// The plugin may call this method multiple times (for
|
||||
// example, gradually decreasing the amount of scratch
|
||||
// being asked for until the host returns true), however,
|
||||
// the plugin should avoid calling this method un-neccesarily
|
||||
// since the host implementation may be relatively expensive.
|
||||
// If the plugin calls `reserve()` multiple times, then the
|
||||
// last call invalidates all previous calls.
|
||||
//
|
||||
// De-activating the plugin releases the scratch memory.
|
||||
//
|
||||
// `max_concurrency_hint` is an optional hint which indicates
|
||||
// the maximum number of threads concurrently accessing the scratch memory.
|
||||
// Set to 0 if unspecified.
|
||||
//
|
||||
// Returns true on success.
|
||||
//
|
||||
// [main-thread & being-activated]
|
||||
bool(CLAP_ABI *reserve)(const clap_host_t *host,
|
||||
uint32_t scratch_size_bytes,
|
||||
uint32_t max_concurrency_hint);
|
||||
|
||||
// Returns a pointer to the "thread-local" scratch memory.
|
||||
//
|
||||
// If the scratch memory wasn't successfully reserved, returns NULL.
|
||||
//
|
||||
// If the plugin crosses `max_concurrency_hint`, then the return value
|
||||
// is either NULL or a valid scratch memory pointer.
|
||||
//
|
||||
// This method may only be called by the plugin from the audio thread,
|
||||
// (i.e. during the process() or thread_pool.exec() callback), and
|
||||
// the provided memory is only valid until the plugin returns from
|
||||
// that callback. The plugin must not hold any references to data
|
||||
// that lives in the scratch memory after returning from the callback,
|
||||
// as that data will likely be over-written by another plugin using
|
||||
// the same scratch memory.
|
||||
//
|
||||
// The provided memory is not initialized, and may have been used
|
||||
// by other plugin instances, so the plugin must correctly initialize
|
||||
// the memory when using it.
|
||||
//
|
||||
// The provided memory is owned by the host, so the plugin must not
|
||||
// free the memory.
|
||||
//
|
||||
// If the plugin wants to share the same scratch memory pointer with
|
||||
// many threads, it must access the the scratch at the beginning of the
|
||||
// `process()` callback, cache the returned pointer before calling
|
||||
// `clap_host_thread_pool->request_exec()` and clear the cached pointer
|
||||
// before returning from `process()`.
|
||||
//
|
||||
// [audio-thread]
|
||||
void *(CLAP_ABI *access)(const clap_host_t *host);
|
||||
} clap_host_scratch_memory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
75
third_party/clap/include/clap/ext/draft/transport-control.h
vendored
Normal file
75
third_party/clap/include/clap/ext/draft/transport-control.h
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
|
||||
// This extension lets the plugin submit transport requests to the host.
|
||||
// The host has no obligation to execute these requests, so the interface may be
|
||||
// partially working.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TRANSPORT_CONTROL[] = "clap.transport-control/2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_host_transport_control {
|
||||
// Jumps back to the start point and starts the transport
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_start)(const clap_host_t *host);
|
||||
|
||||
// Stops the transport, and jumps to the start point
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_stop)(const clap_host_t *host);
|
||||
|
||||
// If not playing, starts the transport from its current position
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_continue)(const clap_host_t *host);
|
||||
|
||||
// If playing, stops the transport at the current position
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_pause)(const clap_host_t *host);
|
||||
|
||||
// Equivalent to what "space bar" does with most DAWs
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_toggle_play)(const clap_host_t *host);
|
||||
|
||||
// Jumps the transport to the given position.
|
||||
// Does not start the transport.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_jump)(const clap_host_t *host, clap_beattime position);
|
||||
|
||||
// Sets the loop region
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_loop_region)(const clap_host_t *host,
|
||||
clap_beattime start,
|
||||
clap_beattime duration);
|
||||
|
||||
// Toggles looping
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_toggle_loop)(const clap_host_t *host);
|
||||
|
||||
// Enables/Disables looping
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_enable_loop)(const clap_host_t *host, bool is_enabled);
|
||||
|
||||
// Enables/Disables recording
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_record)(const clap_host_t *host, bool is_recording);
|
||||
|
||||
// Toggles recording
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_toggle_record)(const clap_host_t *host);
|
||||
|
||||
// Sets tempo
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_tempo)(const clap_host_t *host, double tempo);
|
||||
|
||||
// Sets time signature, same format as in clap_event_transport_t.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_time_signature)(const clap_host_t *host, uint16_t tsig_num, uint16_t tsig_denom);
|
||||
|
||||
} clap_host_transport_control_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
144
third_party/clap/include/clap/ext/draft/triggers.h
vendored
Normal file
144
third_party/clap/include/clap/ext/draft/triggers.h
vendored
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
#include "../../events.h"
|
||||
#include "../../string-sizes.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TRIGGERS[] = "clap.triggers/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page Trigger events
|
||||
///
|
||||
/// This extension enables the plugin to expose a set of triggers to the host.
|
||||
///
|
||||
/// Some examples for triggers:
|
||||
/// - trigger an envelope which is independent of the notes
|
||||
/// - trigger a sample-and-hold unit (maybe even per-voice)
|
||||
|
||||
enum {
|
||||
// Does this trigger support per note automations?
|
||||
CLAP_TRIGGER_IS_AUTOMATABLE_PER_NOTE_ID = 1 << 0,
|
||||
|
||||
// Does this trigger support per key automations?
|
||||
CLAP_TRIGGER_IS_AUTOMATABLE_PER_KEY = 1 << 1,
|
||||
|
||||
// Does this trigger support per channel automations?
|
||||
CLAP_TRIGGER_IS_AUTOMATABLE_PER_CHANNEL = 1 << 2,
|
||||
|
||||
// Does this trigger support per port automations?
|
||||
CLAP_TRIGGER_IS_AUTOMATABLE_PER_PORT = 1 << 3,
|
||||
};
|
||||
typedef uint32_t clap_trigger_info_flags;
|
||||
|
||||
// Given that this extension is still draft, it'll use the event-registry and its own event
|
||||
// namespace until we stabilize it.
|
||||
//
|
||||
// #include <clap/ext/event-registry.h>
|
||||
//
|
||||
// uint16_t CLAP_EXT_TRIGGER_EVENT_SPACE_ID = UINT16_MAX;
|
||||
// if (host_event_registry->query(host, CLAP_EXT_TRIGGERS, &CLAP_EXT_TRIGGER_EVENT_SPACE_ID)) {
|
||||
// /* we can use trigger events */
|
||||
// }
|
||||
//
|
||||
// /* later on */
|
||||
// clap_event_trigger ev;
|
||||
// ev.header.space_id = CLAP_EXT_TRIGGER_EVENT_SPACE_ID;
|
||||
// ev.header.type = CLAP_EVENT_TRIGGER;
|
||||
|
||||
enum { CLAP_EVENT_TRIGGER = 0 };
|
||||
|
||||
typedef struct clap_event_trigger {
|
||||
clap_event_header_t header;
|
||||
|
||||
// target trigger
|
||||
clap_id trigger_id; // @ref clap_trigger_info.id
|
||||
void *cookie; // @ref clap_trigger_info.cookie
|
||||
|
||||
// target a specific note_id, port, key and channel, -1 for global
|
||||
int32_t note_id;
|
||||
int16_t port_index;
|
||||
int16_t channel;
|
||||
int16_t key;
|
||||
} clap_event_trigger_t;
|
||||
|
||||
/* This describes a trigger */
|
||||
typedef struct clap_trigger_info {
|
||||
// stable trigger identifier, it must never change.
|
||||
clap_id id;
|
||||
|
||||
clap_trigger_info_flags flags;
|
||||
|
||||
// in analogy to clap_param_info.cookie
|
||||
void *cookie;
|
||||
|
||||
// displayable name
|
||||
char name[CLAP_NAME_SIZE];
|
||||
|
||||
// the module path containing the trigger, eg:"sequencers/seq1"
|
||||
// '/' will be used as a separator to show a tree like structure.
|
||||
char module[CLAP_PATH_SIZE];
|
||||
} clap_trigger_info_t;
|
||||
|
||||
typedef struct clap_plugin_triggers {
|
||||
// Returns the number of triggers.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Copies the trigger's info to trigger_info and returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_info)(const clap_plugin_t *plugin,
|
||||
uint32_t index,
|
||||
clap_trigger_info_t *trigger_info);
|
||||
} clap_plugin_triggers_t;
|
||||
|
||||
enum {
|
||||
// The trigger info did change, use this flag for:
|
||||
// - name change
|
||||
// - module change
|
||||
// New info takes effect immediately.
|
||||
CLAP_TRIGGER_RESCAN_INFO = 1 << 0,
|
||||
|
||||
// Invalidates everything the host knows about triggers.
|
||||
// It can only be used while the plugin is deactivated.
|
||||
// If the plugin is activated use clap_host->restart() and delay any change until the host calls
|
||||
// clap_plugin->deactivate().
|
||||
//
|
||||
// You must use this flag if:
|
||||
// - some triggers were added or removed.
|
||||
// - some triggers had critical changes:
|
||||
// - is_per_note (flag)
|
||||
// - is_per_key (flag)
|
||||
// - is_per_channel (flag)
|
||||
// - is_per_port (flag)
|
||||
// - cookie
|
||||
CLAP_TRIGGER_RESCAN_ALL = 1 << 1,
|
||||
};
|
||||
typedef uint32_t clap_trigger_rescan_flags;
|
||||
|
||||
enum {
|
||||
// Clears all possible references to a trigger
|
||||
CLAP_TRIGGER_CLEAR_ALL = 1 << 0,
|
||||
|
||||
// Clears all automations to a trigger
|
||||
CLAP_TRIGGER_CLEAR_AUTOMATIONS = 1 << 1,
|
||||
};
|
||||
typedef uint32_t clap_trigger_clear_flags;
|
||||
|
||||
typedef struct clap_host_triggers {
|
||||
// Rescan the full list of triggers according to the flags.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *rescan)(const clap_host_t *host, clap_trigger_rescan_flags flags);
|
||||
|
||||
// Clears references to a trigger.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *clear)(const clap_host_t *host,
|
||||
clap_id trigger_id,
|
||||
clap_trigger_clear_flags flags);
|
||||
} clap_host_triggers_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
76
third_party/clap/include/clap/ext/draft/tuning.h
vendored
Normal file
76
third_party/clap/include/clap/ext/draft/tuning.h
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
#include "../../events.h"
|
||||
#include "../../string-sizes.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TUNING[] = "clap.tuning/2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Use clap_host_event_registry->query(host, CLAP_EXT_TUNING, &space_id) to know the event space.
|
||||
//
|
||||
// This event defines the tuning to be used on the given port/channel.
|
||||
typedef struct clap_event_tuning {
|
||||
clap_event_header_t header;
|
||||
|
||||
int16_t port_index; // -1 global
|
||||
int16_t channel; // 0..15, -1 global
|
||||
clap_id tunning_id;
|
||||
} clap_event_tuning_t;
|
||||
|
||||
typedef struct clap_tuning_info {
|
||||
clap_id tuning_id;
|
||||
char name[CLAP_NAME_SIZE];
|
||||
bool is_dynamic; // true if the values may vary with time
|
||||
} clap_tuning_info_t;
|
||||
|
||||
typedef struct clap_plugin_tuning {
|
||||
// Called when a tuning is added or removed from the pool.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_tuning_t;
|
||||
|
||||
// This extension provides a dynamic tuning table to the plugin.
|
||||
typedef struct clap_host_tuning {
|
||||
// Gets the relative tuning in semitones against equal temperament with A4=440Hz.
|
||||
// The plugin may query the tuning at a rate that makes sense for *low* frequency modulations.
|
||||
//
|
||||
// If the tuning_id is not found or equals to CLAP_INVALID_ID,
|
||||
// then the function shall gracefully return a sensible value.
|
||||
//
|
||||
// sample_offset is the sample offset from the beginning of the current process block.
|
||||
//
|
||||
// should_play(...) should be checked before calling this function.
|
||||
//
|
||||
// [audio-thread & in-process]
|
||||
double(CLAP_ABI *get_relative)(const clap_host_t *host,
|
||||
clap_id tuning_id,
|
||||
int32_t channel,
|
||||
int32_t key,
|
||||
uint32_t sample_offset);
|
||||
|
||||
// Returns true if the note should be played.
|
||||
// [audio-thread & in-process]
|
||||
bool(CLAP_ABI *should_play)(const clap_host_t *host,
|
||||
clap_id tuning_id,
|
||||
int32_t channel,
|
||||
int32_t key);
|
||||
|
||||
// Returns the number of tunings in the pool.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *get_tuning_count)(const clap_host_t *host);
|
||||
|
||||
// Gets info about a tuning
|
||||
// Returns true on success and stores the result into info.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_info)(const clap_host_t *host,
|
||||
uint32_t tuning_index,
|
||||
clap_tuning_info_t *info);
|
||||
} clap_host_tuning_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
201
third_party/clap/include/clap/ext/draft/undo.h
vendored
Normal file
201
third_party/clap/include/clap/ext/draft/undo.h
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
#include "../../stream.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO[] = "clap.undo/4";
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO_CONTEXT[] = "clap.undo_context/4";
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_UNDO_DELTA[] = "clap.undo_delta/4";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page Undo
|
||||
///
|
||||
/// This extension enables the plugin to merge its undo history with the host.
|
||||
/// This leads to a single undo history shared by the host and many plugins.
|
||||
///
|
||||
/// Calling host->undo() or host->redo() is equivalent to clicking undo/redo within the host's GUI.
|
||||
///
|
||||
/// If the plugin uses this interface then its undo and redo should be entirely delegated to
|
||||
/// the host; clicking in the plugin's UI undo or redo is equivalent to clicking undo or redo in the
|
||||
/// host's UI.
|
||||
///
|
||||
/// Some changes are long running changes, for example a mouse interaction will begin editing some
|
||||
/// complex data and it may take multiple events and a long duration to complete the change.
|
||||
/// In such case the plugin will call host->begin_change() to indicate the beginning of a long
|
||||
/// running change and complete the change by calling host->change_made().
|
||||
///
|
||||
/// The host may group changes together:
|
||||
/// [---------------------------------]
|
||||
/// ^-T0 ^-T1 ^-T2 ^-T3
|
||||
/// Here a long running change C0 begin at T0.
|
||||
/// A instantaneous change C1 at T1, and another one C2 at T2.
|
||||
/// Then at T3 the long running change is completed.
|
||||
/// The host will then create a single undo step that will merge all the changes into C0.
|
||||
///
|
||||
/// This leads to another important consideration: starting a long running change without
|
||||
/// terminating is **VERY BAD**, because while a change is running it is impossible to call undo or
|
||||
/// redo.
|
||||
///
|
||||
/// Rationale: multiple designs were considered and this one has the benefit of having a single undo
|
||||
/// history. This simplifies the host implementation, leading to less bugs, a more robust design
|
||||
/// and maybe an easier experience for the user because there's a single undo context versus one
|
||||
/// for the host and one for each plugin instance.
|
||||
///
|
||||
/// This extension tries to make it as easy as possible for the plugin to hook into the host undo
|
||||
/// and make it efficient when possible by using deltas. The plugin interfaces are all optional, and
|
||||
/// the plugin can for a minimal implementation, just use the host interface and call
|
||||
/// host->change_made() without providing a delta. This is enough for the host to know that it can
|
||||
/// capture a plugin state for the undo step.
|
||||
|
||||
typedef struct clap_undo_delta_properties {
|
||||
// If true, then the plugin will provide deltas in host->change_made().
|
||||
// If false, then all clap_undo_delta_properties's attributes become irrelevant.
|
||||
bool has_delta;
|
||||
|
||||
// If true, then the deltas can be stored on disk and re-used in the future as long as the plugin
|
||||
// is compatible with the given format_version.
|
||||
//
|
||||
// If false, then format_version must be set to CLAP_INVALID_ID.
|
||||
bool are_deltas_persistent;
|
||||
|
||||
// This represents the delta format version that the plugin is currently using.
|
||||
// Use CLAP_INVALID_ID for invalid value.
|
||||
clap_id format_version;
|
||||
} clap_undo_delta_properties_t;
|
||||
|
||||
// Use CLAP_EXT_UNDO_DELTA.
|
||||
// This is an optional interface, using deltas is an optimization versus making a state snapshot.
|
||||
typedef struct clap_plugin_undo_delta {
|
||||
// Asks the plugin the delta properties.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *get_delta_properties)(const clap_plugin_t *plugin,
|
||||
clap_undo_delta_properties_t *properties);
|
||||
|
||||
// Asks the plugin if it can apply a delta using the given format version.
|
||||
// Returns true if it is possible.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *can_use_delta_format_version)(const clap_plugin_t *plugin,
|
||||
clap_id format_version);
|
||||
|
||||
// Undo using the delta.
|
||||
// Returns true on success.
|
||||
//
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *undo)(const clap_plugin_t *plugin,
|
||||
clap_id format_version,
|
||||
const void *delta,
|
||||
size_t delta_size);
|
||||
|
||||
// Redo using the delta.
|
||||
// Returns true on success.
|
||||
//
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *redo)(const clap_plugin_t *plugin,
|
||||
clap_id format_version,
|
||||
const void *delta,
|
||||
size_t delta_size);
|
||||
} clap_plugin_undo_delta_t;
|
||||
|
||||
// Use CLAP_EXT_UNDO_CONTEXT.
|
||||
// This is an optional interface, that the plugin can implement in order to know about
|
||||
// the current undo context.
|
||||
typedef struct clap_plugin_undo_context {
|
||||
// Indicate if it is currently possible to perform an undo or redo operation.
|
||||
// [main-thread & plugin-subscribed-to-undo-context]
|
||||
void(CLAP_ABI *set_can_undo)(const clap_plugin_t *plugin, bool can_undo);
|
||||
void(CLAP_ABI *set_can_redo)(const clap_plugin_t *plugin, bool can_redo);
|
||||
|
||||
// Sets the name of the next undo or redo step.
|
||||
// name: null terminated string.
|
||||
// [main-thread & plugin-subscribed-to-undo-context]
|
||||
void(CLAP_ABI *set_undo_name)(const clap_plugin_t *plugin, const char *name);
|
||||
void(CLAP_ABI *set_redo_name)(const clap_plugin_t *plugin, const char *name);
|
||||
} clap_plugin_undo_context_t;
|
||||
|
||||
// Use CLAP_EXT_UNDO.
|
||||
typedef struct clap_host_undo {
|
||||
// Begins a long running change.
|
||||
// The plugin must not call this twice: there must be either a call to cancel_change() or
|
||||
// change_made() before calling begin_change() again.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *begin_change)(const clap_host_t *host);
|
||||
|
||||
// Cancels a long running change.
|
||||
// cancel_change() must not be called without a preceding begin_change().
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *cancel_change)(const clap_host_t *host);
|
||||
|
||||
// Completes an undoable change.
|
||||
// At the moment of this function call, plugin_state->save() would include the current change.
|
||||
//
|
||||
// name: mandatory null terminated string describing the change, this is displayed to the user
|
||||
//
|
||||
// delta: optional, it is a binary blobs used to perform the undo and redo. When not available
|
||||
// the host will save the plugin state and use state->load() to perform undo and redo.
|
||||
// The plugin must be able to perform a redo operation using the delta, though the undo operation
|
||||
// is only possible if delta_can_undo is true.
|
||||
//
|
||||
// Note: the provided delta may be used for incremental state saving and crash recovery. The
|
||||
// plugin can indicate a format version id and the validity lifetime for the binary blobs.
|
||||
// The host can use these to verify the compatibility before applying the delta.
|
||||
// If the plugin is unable to use a delta, a notification should be provided to the user and
|
||||
// the crash recovery should perform a best effort job, at least restoring the latest saved
|
||||
// state.
|
||||
//
|
||||
// Special case: for objects with shared and synchronized state, changes shouldn't be reported
|
||||
// as the host already knows about it.
|
||||
// For example, plugin parameter changes shouldn't produce a call to change_made().
|
||||
//
|
||||
// Note: if the plugin asked for this interface, then host_state->mark_dirty() will not create an
|
||||
// implicit undo step.
|
||||
//
|
||||
// Note: if the plugin did load a preset or did something that leads to a large delta,
|
||||
// it may consider not producing a delta (pass null) and let the host make a state snapshot
|
||||
// instead.
|
||||
//
|
||||
// Note: if a plugin is producing a lot of changes within a small amount of time, the host
|
||||
// may merge them into a single undo step.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *change_made)(const clap_host_t *host,
|
||||
const char *name,
|
||||
const void *delta,
|
||||
size_t delta_size,
|
||||
bool delta_can_undo);
|
||||
|
||||
// Asks the host to perform the next undo or redo step.
|
||||
//
|
||||
// Note: this maybe a complex and asynchronous operation, which may complete after
|
||||
// this function returns.
|
||||
//
|
||||
// Note: the host may ignore this request if there is no undo/redo step to perform,
|
||||
// or if the host is unable to perform undo/redo at the time (eg: a long running
|
||||
// change is going on).
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *request_undo)(const clap_host_t *host);
|
||||
void(CLAP_ABI *request_redo)(const clap_host_t *host);
|
||||
|
||||
// Subscribes to or unsubscribes from undo context info.
|
||||
//
|
||||
// This method helps reducing the number of calls the host has to perform when updating
|
||||
// the undo context info. Consider a large project with 1000+ plugins, we don't want to
|
||||
// call 1000+ times update, while the plugin may only need the context info if its GUI
|
||||
// is shown and it wants to display undo/redo info.
|
||||
//
|
||||
// Initial state is unsubscribed.
|
||||
//
|
||||
// is_subscribed: set to true to receive context info
|
||||
//
|
||||
// It is mandatory for the plugin to implement CLAP_EXT_UNDO_CONTEXT when using this method.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_wants_context_updates)(const clap_host_t *host, bool is_subscribed);
|
||||
} clap_host_undo_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
77
third_party/clap/include/clap/ext/draft/webview.h
vendored
Normal file
77
third_party/clap/include/clap/ext/draft/webview.h
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../plugin.h"
|
||||
#include "../../stream.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_WEBVIEW[] = "clap.webview/3";
|
||||
|
||||
// clap.gui API constant. The pointer in clap_window must be NULL, but sizing methods are useful.
|
||||
// This uses logical size, don't call clap_plugin_gui->set_scale()
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WEBVIEW[] = "webview";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page Webview
|
||||
///
|
||||
/// This extension enables the plugin to provide the start-page for a webview UI, and exchange
|
||||
/// messages back and forth.
|
||||
///
|
||||
/// Messages are received in the webview using a standard MessageEvent, with the data in an
|
||||
/// ArrayBuffer. They are posted back to the plugin using window.parent.postMessage(), with the
|
||||
/// data in an ArrayBuffer or TypedArray.
|
||||
|
||||
typedef struct clap_plugin_webview {
|
||||
// Writes the URL for the webview's initial navigation to the provided `uri` buffer as a
|
||||
// null-terminated UTF-8 string.
|
||||
//
|
||||
// This must be called at least once before any messages are sent (or accepted) by the host.
|
||||
// Absolute URIs (including `data:`, and `file:` URIs on local systems) are always supported.
|
||||
// Relative URIs (with absolute paths) refer to resources provided by .get_resource(), which
|
||||
// may be provided to the webview with an arbitrary scheme or URI prefix. The host may also
|
||||
// translate `file:` URIs to some other scheme or path root, to limit access scope or handle
|
||||
// virtual filesystems. Therefore, when using either relative or `file:` URIs, pages must not
|
||||
// assume a particular absolute path, only relative paths between resources.
|
||||
//
|
||||
// Returns either the full length of the URI (including the null terminator), or <= 0 for an
|
||||
// error. If the value returned is greater than the capacity, then the result was truncated.
|
||||
// If the capacity is 0, `uri` may be a null pointer. In this case, the length of the URI is
|
||||
// returned without writing to `uri`, allowing the host to preallocate a buffer for a subsequent
|
||||
// call.
|
||||
// [main-thread]
|
||||
int32_t(CLAP_ABI *get_uri)(const clap_plugin_t *plugin, char *uri, uint32_t uri_capacity);
|
||||
|
||||
// Provides the media type and data for resources, starting with the URI from get_uri().
|
||||
// The path must be absolute (starting with `/`) with any host-defined path prefix removed.
|
||||
// Writes null-terminated media type (MIME type) to the `mime` output buffer if the capacity
|
||||
// is large enough, and streams resource data to `data_stream`.
|
||||
// Returns true if the media type and entire contents of the resource were provided.
|
||||
//
|
||||
// See https://www.rfc-editor.org/rfc/rfc6838#section-4.2
|
||||
//
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_resource)(const clap_plugin_t *plugin,
|
||||
const char *path,
|
||||
char *mime,
|
||||
uint32_t mime_capacity,
|
||||
const clap_ostream_t *data_stream);
|
||||
|
||||
// Receives a single message from the webview, which must be open and ready to receive replies.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *receive)(const clap_plugin_t *plugin, const void *buffer, uint32_t size);
|
||||
|
||||
} clap_plugin_webview_t;
|
||||
|
||||
typedef struct clap_host_webview {
|
||||
// Sends a single message to the webview.
|
||||
// Returns true on success. It must fail (false) if the webview is not open.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *send)(const clap_host_t *host, const void *buffer, uint32_t size);
|
||||
|
||||
} clap_host_webview_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
22
third_party/clap/include/clap/ext/event-registry.h
vendored
Normal file
22
third_party/clap/include/clap/ext/event-registry.h
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_EVENT_REGISTRY[] = "clap.event-registry";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_host_event_registry {
|
||||
// Queries an event space id.
|
||||
// The space id 0 is reserved for CLAP's core events. See CLAP_CORE_EVENT_SPACE.
|
||||
//
|
||||
// Return false and sets *space_id to UINT16_MAX if the space name is unknown to the host.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *query)(const clap_host_t *host, const char *space_name, uint16_t *space_id);
|
||||
} clap_host_event_registry_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
249
third_party/clap/include/clap/ext/gui.h
vendored
Normal file
249
third_party/clap/include/clap/ext/gui.h
vendored
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
/// @page GUI
|
||||
///
|
||||
/// This extension defines how the plugin will present its GUI.
|
||||
///
|
||||
/// There are two approaches:
|
||||
/// 1. the plugin creates a window and embeds it into the host's window
|
||||
/// 2. the plugin creates a floating window
|
||||
///
|
||||
/// Embedding the window gives more control to the host, and feels more integrated.
|
||||
/// Floating window are sometimes the only option due to technical limitations.
|
||||
///
|
||||
/// The Embedding protocol is by far the most common, supported by all hosts to date,
|
||||
/// and a plugin author should support at least that case.
|
||||
///
|
||||
/// Showing the GUI works as follow:
|
||||
/// 1. clap_plugin_gui->is_api_supported(), check what can work
|
||||
/// 2. clap_plugin_gui->create(), allocates gui resources
|
||||
/// 3. if the plugin window is floating
|
||||
/// 4. -> clap_plugin_gui->set_transient()
|
||||
/// 5. -> clap_plugin_gui->suggest_title()
|
||||
/// 6. else
|
||||
/// 7. -> clap_plugin_gui->set_scale()
|
||||
/// 8. -> clap_plugin_gui->can_resize()
|
||||
/// 9. -> if resizable and has known size from previous session, clap_plugin_gui->set_size()
|
||||
/// 10. -> else clap_plugin_gui->get_size(), gets initial size
|
||||
/// 11. -> clap_plugin_gui->set_parent()
|
||||
/// 12. clap_plugin_gui->show()
|
||||
/// 13. clap_plugin_gui->hide()/show() ...
|
||||
/// 14. clap_plugin_gui->destroy() when done with the gui
|
||||
///
|
||||
/// Resizing the window (initiated by the plugin, if embedded):
|
||||
/// 1. Plugins calls clap_host_gui->request_resize()
|
||||
/// 2. If the host returns true the new size is accepted,
|
||||
/// the host doesn't have to call clap_plugin_gui->set_size().
|
||||
/// If the host returns false, the new size is rejected.
|
||||
///
|
||||
/// Resizing the window (drag, if embedded)):
|
||||
/// 1. Only possible if clap_plugin_gui->can_resize() returns true
|
||||
/// 2. Mouse drag -> new_size
|
||||
/// 3. clap_plugin_gui->adjust_size(new_size) -> working_size
|
||||
/// 4. clap_plugin_gui->set_size(working_size)
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_GUI[] = "clap.gui";
|
||||
|
||||
// If your windowing API is not listed here, please open an issue and we'll figure it out.
|
||||
// https://github.com/free-audio/clap/issues/new
|
||||
|
||||
// uses physical size
|
||||
// embed using https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WIN32[] = "win32";
|
||||
|
||||
// uses logical size, don't call clap_plugin_gui->set_scale()
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_COCOA[] = "cocoa";
|
||||
|
||||
// uses logical size, don't call clap_plugin_gui->set_scale()
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_UIKIT[] = "uikit";
|
||||
|
||||
// uses physical size
|
||||
// embed using https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_X11[] = "x11";
|
||||
|
||||
// uses physical size
|
||||
// embed is currently not supported, use floating windows
|
||||
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WAYLAND[] = "wayland";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *clap_hwnd;
|
||||
typedef void *clap_nsview;
|
||||
typedef void *clap_uiview;
|
||||
typedef unsigned long clap_xwnd;
|
||||
|
||||
// Represent a window reference.
|
||||
typedef struct clap_window {
|
||||
const char *api; // one of CLAP_WINDOW_API_XXX
|
||||
union {
|
||||
clap_nsview cocoa;
|
||||
clap_uiview uikit;
|
||||
clap_xwnd x11;
|
||||
clap_hwnd win32;
|
||||
void *ptr; // for anything defined outside of clap
|
||||
};
|
||||
} clap_window_t;
|
||||
|
||||
// Information to improve window resizing when initiated by the host or window manager.
|
||||
typedef struct clap_gui_resize_hints {
|
||||
bool can_resize_horizontally;
|
||||
bool can_resize_vertically;
|
||||
|
||||
// if both horizontal and vertical resize are available, do we preserve the
|
||||
// aspect ratio, and if so, what is the width x height aspect ratio to preserve.
|
||||
// These flags are unused if can_resize_horizontally or vertically are false,
|
||||
// and ratios are unused if preserve is false.
|
||||
bool preserve_aspect_ratio;
|
||||
uint32_t aspect_ratio_width;
|
||||
uint32_t aspect_ratio_height;
|
||||
} clap_gui_resize_hints_t;
|
||||
|
||||
// Size (width, height) is in pixels; the corresponding windowing system extension is
|
||||
// responsible for defining if it is physical pixels or logical pixels.
|
||||
typedef struct clap_plugin_gui {
|
||||
// Returns true if the requested gui api is supported, either in floating (plugin-created)
|
||||
// or non-floating (embedded) mode.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *is_api_supported)(const clap_plugin_t *plugin, const char *api, bool is_floating);
|
||||
|
||||
// Returns true if the plugin has a preferred api.
|
||||
// The host has no obligation to honor the plugin preference, this is just a hint.
|
||||
// The const char **api variable should be explicitly assigned as a pointer to
|
||||
// one of the CLAP_WINDOW_API_ constants defined above, not strcopied.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_preferred_api)(const clap_plugin_t *plugin,
|
||||
const char **api,
|
||||
bool *is_floating);
|
||||
|
||||
// Create and allocate all resources necessary for the gui.
|
||||
//
|
||||
// If is_floating is true, then the window will not be managed by the host. The plugin
|
||||
// can set its window to stays above the parent window, see set_transient().
|
||||
// api may be null or blank for floating window.
|
||||
//
|
||||
// If is_floating is false, then the plugin has to embed its window into the parent window, see
|
||||
// set_parent().
|
||||
//
|
||||
// After this call, the GUI may not be visible yet; don't forget to call show().
|
||||
//
|
||||
// Returns true if the GUI is successfully created.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *create)(const clap_plugin_t *plugin, const char *api, bool is_floating);
|
||||
|
||||
// Free all resources associated with the gui.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *destroy)(const clap_plugin_t *plugin);
|
||||
|
||||
// Set the absolute GUI scaling factor, and override any OS info.
|
||||
// Should not be used if the windowing api relies upon logical pixels.
|
||||
//
|
||||
// If the plugin prefers to work out the scaling factor itself by querying the OS directly,
|
||||
// then ignore the call.
|
||||
//
|
||||
// scale = 2 means 200% scaling.
|
||||
//
|
||||
// Returns true if the scaling could be applied
|
||||
// Returns false if the call was ignored, or the scaling could not be applied.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *set_scale)(const clap_plugin_t *plugin, double scale);
|
||||
|
||||
// Get the current size of the plugin UI.
|
||||
// clap_plugin_gui->create() must have been called prior to asking the size.
|
||||
//
|
||||
// Returns true if the plugin could get the size.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height);
|
||||
|
||||
// Returns true if the window is resizeable (mouse drag).
|
||||
// [main-thread & !floating]
|
||||
bool(CLAP_ABI *can_resize)(const clap_plugin_t *plugin);
|
||||
|
||||
// Returns true if the plugin can provide hints on how to resize the window.
|
||||
// [main-thread & !floating]
|
||||
bool(CLAP_ABI *get_resize_hints)(const clap_plugin_t *plugin, clap_gui_resize_hints_t *hints);
|
||||
|
||||
// If the plugin gui is resizable, then the plugin will calculate the closest
|
||||
// usable size which fits in the given size.
|
||||
// This method does not change the size.
|
||||
//
|
||||
// Returns true if the plugin could adjust the given size.
|
||||
// [main-thread & !floating]
|
||||
bool(CLAP_ABI *adjust_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height);
|
||||
|
||||
// Sets the window size.
|
||||
//
|
||||
// Returns true if the plugin could resize its window to the given size.
|
||||
// [main-thread & !floating]
|
||||
bool(CLAP_ABI *set_size)(const clap_plugin_t *plugin, uint32_t width, uint32_t height);
|
||||
|
||||
// Embeds the plugin window into the given window.
|
||||
//
|
||||
// Returns true on success.
|
||||
// [main-thread & !floating]
|
||||
bool(CLAP_ABI *set_parent)(const clap_plugin_t *plugin, const clap_window_t *window);
|
||||
|
||||
// Set the plugin floating window to stay above the given window.
|
||||
//
|
||||
// Returns true on success.
|
||||
// [main-thread & floating]
|
||||
bool(CLAP_ABI *set_transient)(const clap_plugin_t *plugin, const clap_window_t *window);
|
||||
|
||||
// Suggests a window title. Only for floating windows.
|
||||
//
|
||||
// [main-thread & floating]
|
||||
void(CLAP_ABI *suggest_title)(const clap_plugin_t *plugin, const char *title);
|
||||
|
||||
// Show the window.
|
||||
//
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *show)(const clap_plugin_t *plugin);
|
||||
|
||||
// Hide the window, this method does not free the resources, it just hides
|
||||
// the window content. Yet it may be a good idea to stop painting timers.
|
||||
//
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *hide)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_gui_t;
|
||||
|
||||
typedef struct clap_host_gui {
|
||||
// The host should call get_resize_hints() again.
|
||||
// [thread-safe & !floating]
|
||||
void(CLAP_ABI *resize_hints_changed)(const clap_host_t *host);
|
||||
|
||||
// Request the host to resize the client area to width, height.
|
||||
// Return true if the new size is accepted, false otherwise.
|
||||
// The host doesn't have to call set_size().
|
||||
//
|
||||
// Note: if not called from the main thread, then a return value simply means that the host
|
||||
// acknowledged the request and will process it asynchronously. If the request then can't be
|
||||
// satisfied then the host will call set_size() to revert the operation.
|
||||
// [thread-safe & !floating]
|
||||
bool(CLAP_ABI *request_resize)(const clap_host_t *host, uint32_t width, uint32_t height);
|
||||
|
||||
// Request the host to show the plugin gui.
|
||||
// Return true on success, false otherwise.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *request_show)(const clap_host_t *host);
|
||||
|
||||
// Request the host to hide the plugin gui.
|
||||
// Return true on success, false otherwise.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *request_hide)(const clap_host_t *host);
|
||||
|
||||
// The floating window has been closed, or the connection to the gui has been lost.
|
||||
//
|
||||
// If was_destroyed is true, then the host must call clap_plugin_gui->destroy() to acknowledge
|
||||
// the gui destruction.
|
||||
// [thread-safe]
|
||||
void(CLAP_ABI *closed)(const clap_host_t *host, bool was_destroyed);
|
||||
} clap_host_gui_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
27
third_party/clap/include/clap/ext/latency.h
vendored
Normal file
27
third_party/clap/include/clap/ext/latency.h
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_LATENCY[] = "clap.latency";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_latency {
|
||||
// Returns the plugin latency in samples.
|
||||
// [main-thread & (being-activated | active)]
|
||||
uint32_t(CLAP_ABI *get)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_latency_t;
|
||||
|
||||
typedef struct clap_host_latency {
|
||||
// Tell the host that the latency changed.
|
||||
// The latency is only allowed to change during plugin->activate.
|
||||
// If the plugin is activated, call host->request_restart()
|
||||
// [main-thread & being-activated]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_latency_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
33
third_party/clap/include/clap/ext/log.h
vendored
Normal file
33
third_party/clap/include/clap/ext/log.h
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_LOG[] = "clap.log";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CLAP_LOG_DEBUG = 0,
|
||||
CLAP_LOG_INFO = 1,
|
||||
CLAP_LOG_WARNING = 2,
|
||||
CLAP_LOG_ERROR = 3,
|
||||
CLAP_LOG_FATAL = 4,
|
||||
|
||||
// These severities should be used to report misbehaviour.
|
||||
// The plugin one can be used by a layer between the plugin and the host.
|
||||
CLAP_LOG_HOST_MISBEHAVING = 5,
|
||||
CLAP_LOG_PLUGIN_MISBEHAVING = 6,
|
||||
};
|
||||
typedef int32_t clap_log_severity;
|
||||
|
||||
typedef struct clap_host_log {
|
||||
// Log a message through the host.
|
||||
// [thread-safe]
|
||||
void(CLAP_ABI *log)(const clap_host_t *host, clap_log_severity severity, const char *msg);
|
||||
} clap_host_log_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
37
third_party/clap/include/clap/ext/note-name.h
vendored
Normal file
37
third_party/clap/include/clap/ext/note-name.h
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_NOTE_NAME[] = "clap.note-name";
|
||||
|
||||
typedef struct clap_note_name {
|
||||
char name[CLAP_NAME_SIZE];
|
||||
int16_t port; // -1 for every port
|
||||
int16_t key; // -1 for every key
|
||||
int16_t channel; // -1 for every channel
|
||||
} clap_note_name_t;
|
||||
|
||||
typedef struct clap_plugin_note_name {
|
||||
// Return the number of note names
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Returns true on success and stores the result into note_name
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin, uint32_t index, clap_note_name_t *note_name);
|
||||
} clap_plugin_note_name_t;
|
||||
|
||||
typedef struct clap_host_note_name {
|
||||
// Informs the host that the note names have changed.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_note_name_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
79
third_party/clap/include/clap/ext/note-ports.h
vendored
Normal file
79
third_party/clap/include/clap/ext/note-ports.h
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
/// @page Note Ports
|
||||
///
|
||||
/// This extension provides a way for the plugin to describe its current note ports.
|
||||
/// If the plugin does not implement this extension, it won't have note input or output.
|
||||
/// The plugin is only allowed to change its note ports configuration while it is deactivated.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_NOTE_PORTS[] = "clap.note-ports";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clap_note_dialect {
|
||||
// Uses clap_event_note and clap_event_note_expression.
|
||||
CLAP_NOTE_DIALECT_CLAP = 1 << 0,
|
||||
|
||||
// Uses clap_event_midi, no polyphonic expression
|
||||
CLAP_NOTE_DIALECT_MIDI = 1 << 1,
|
||||
|
||||
// Uses clap_event_midi, with polyphonic expression (MPE)
|
||||
CLAP_NOTE_DIALECT_MIDI_MPE = 1 << 2,
|
||||
|
||||
// Uses clap_event_midi2
|
||||
CLAP_NOTE_DIALECT_MIDI2 = 1 << 3,
|
||||
};
|
||||
|
||||
typedef struct clap_note_port_info {
|
||||
// id identifies a port and must be stable.
|
||||
// id may overlap between input and output ports.
|
||||
clap_id id;
|
||||
uint32_t supported_dialects; // bitfield, see clap_note_dialect
|
||||
uint32_t preferred_dialect; // one value of clap_note_dialect
|
||||
char name[CLAP_NAME_SIZE]; // displayable name, i18n?
|
||||
} clap_note_port_info_t;
|
||||
|
||||
// The note ports scan has to be done while the plugin is deactivated.
|
||||
typedef struct clap_plugin_note_ports {
|
||||
// Number of ports, for either input or output.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin, bool is_input);
|
||||
|
||||
// Get info about a note port.
|
||||
// Returns true on success and stores the result into info.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
|
||||
uint32_t index,
|
||||
bool is_input,
|
||||
clap_note_port_info_t *info);
|
||||
} clap_plugin_note_ports_t;
|
||||
|
||||
enum {
|
||||
// The ports have changed, the host shall perform a full scan of the ports.
|
||||
// This flag can only be used if the plugin is not active.
|
||||
// If the plugin active, call host->request_restart() and then call rescan()
|
||||
// when the host calls deactivate()
|
||||
CLAP_NOTE_PORTS_RESCAN_ALL = 1 << 0,
|
||||
|
||||
// The ports name did change, the host can scan them right away.
|
||||
CLAP_NOTE_PORTS_RESCAN_NAMES = 1 << 1,
|
||||
};
|
||||
|
||||
typedef struct clap_host_note_ports {
|
||||
// Query which dialects the host supports
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *supported_dialects)(const clap_host_t *host);
|
||||
|
||||
// Rescan the full list of note ports according to the flags.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *rescan)(const clap_host_t *host, uint32_t flags);
|
||||
} clap_host_note_ports_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
77
third_party/clap/include/clap/ext/param-indication.h
vendored
Normal file
77
third_party/clap/include/clap/ext/param-indication.h
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include "params.h"
|
||||
#include "../color.h"
|
||||
|
||||
// This extension lets the host tell the plugin to display a little color based indication on the
|
||||
// parameter. This can be used to indicate:
|
||||
// - a physical controller is mapped to a parameter
|
||||
// - the parameter is current playing an automation
|
||||
// - the parameter is overriding the automation
|
||||
// - etc...
|
||||
//
|
||||
// The color semantic depends upon the host here and the goal is to have a consistent experience
|
||||
// across all plugins.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PARAM_INDICATION[] = "clap.param-indication/4";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PARAM_INDICATION_COMPAT[] = "clap.param-indication.draft/4";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// The host doesn't have an automation for this parameter
|
||||
CLAP_PARAM_INDICATION_AUTOMATION_NONE = 0,
|
||||
|
||||
// The host has an automation for this parameter, but it isn't playing it
|
||||
CLAP_PARAM_INDICATION_AUTOMATION_PRESENT = 1,
|
||||
|
||||
// The host is playing an automation for this parameter
|
||||
CLAP_PARAM_INDICATION_AUTOMATION_PLAYING = 2,
|
||||
|
||||
// The host is recording an automation on this parameter
|
||||
CLAP_PARAM_INDICATION_AUTOMATION_RECORDING = 3,
|
||||
|
||||
// The host should play an automation for this parameter, but the user has started to adjust this
|
||||
// parameter and is overriding the automation playback
|
||||
CLAP_PARAM_INDICATION_AUTOMATION_OVERRIDING = 4,
|
||||
};
|
||||
|
||||
typedef struct clap_plugin_param_indication {
|
||||
// Sets or clears a mapping indication.
|
||||
//
|
||||
// has_mapping: does the parameter currently has a mapping?
|
||||
// color: if set, the color to use to highlight the control in the plugin GUI
|
||||
// label: if set, a small string to display on top of the knob which identifies the hardware
|
||||
// controller description: if set, a string which can be used in a tooltip, which describes the
|
||||
// current mapping
|
||||
//
|
||||
// Parameter indications should not be saved in the plugin context, and are off by default.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_mapping)(const clap_plugin_t *plugin,
|
||||
clap_id param_id,
|
||||
bool has_mapping,
|
||||
const clap_color_t *color,
|
||||
const char *label,
|
||||
const char *description);
|
||||
|
||||
// Sets or clears an automation indication.
|
||||
//
|
||||
// automation_state: current automation state for the given parameter
|
||||
// color: if set, the color to use to display the automation indication in the plugin GUI
|
||||
//
|
||||
// Parameter indications should not be saved in the plugin context, and are off by default.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *set_automation)(const clap_plugin_t *plugin,
|
||||
clap_id param_id,
|
||||
uint32_t automation_state,
|
||||
const clap_color_t *color);
|
||||
} clap_plugin_param_indication_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
386
third_party/clap/include/clap/ext/params.h
vendored
Normal file
386
third_party/clap/include/clap/ext/params.h
vendored
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
/// @page Parameters
|
||||
/// @brief parameters management
|
||||
///
|
||||
/// Main idea:
|
||||
///
|
||||
/// The host sees the plugin as an atomic entity; and acts as a controller on top of its parameters.
|
||||
/// The plugin is responsible for keeping its audio processor and its GUI in sync.
|
||||
///
|
||||
/// The host can at any time read parameters' value on the [main-thread] using
|
||||
/// @ref clap_plugin_params.get_value().
|
||||
///
|
||||
/// There are two options to communicate parameter value changes, and they are not concurrent.
|
||||
/// - send automation points during clap_plugin.process()
|
||||
/// - send automation points during clap_plugin_params.flush(), for parameter changes
|
||||
/// without processing audio
|
||||
///
|
||||
/// When the plugin changes a parameter value, it must inform the host.
|
||||
/// It will send @ref CLAP_EVENT_PARAM_VALUE event during process() or flush().
|
||||
/// If the user is adjusting the value, don't forget to mark the beginning and end
|
||||
/// of the gesture by sending CLAP_EVENT_PARAM_GESTURE_BEGIN and CLAP_EVENT_PARAM_GESTURE_END
|
||||
/// events.
|
||||
///
|
||||
/// @note MIDI CCs are tricky because you may not know when the parameter adjustment ends.
|
||||
/// Also if the host records incoming MIDI CC and parameter change automation at the same time,
|
||||
/// there will be a conflict at playback: MIDI CC vs Automation.
|
||||
/// The parameter automation will always target the same parameter because the param_id is stable.
|
||||
/// The MIDI CC may have a different mapping in the future and may result in a different playback.
|
||||
///
|
||||
/// When a MIDI CC changes a parameter's value, set the flag CLAP_EVENT_DONT_RECORD in
|
||||
/// clap_event_param.header.flags. That way the host may record the MIDI CC automation, but not the
|
||||
/// parameter change and there won't be conflict at playback.
|
||||
///
|
||||
/// Scenarios:
|
||||
///
|
||||
/// I. Loading a preset
|
||||
/// - load the preset in a temporary state
|
||||
/// - call @ref clap_host_params.rescan() if anything changed
|
||||
/// - call @ref clap_host_latency.changed() if latency changed
|
||||
/// - invalidate any other info that may be cached by the host
|
||||
/// - if the plugin is activated and the preset will introduce breaking changes
|
||||
/// (latency, audio ports, new parameters, ...) be sure to wait for the host
|
||||
/// to deactivate the plugin to apply those changes.
|
||||
/// If there are no breaking changes, the plugin can apply them them right away.
|
||||
/// The plugin is responsible for updating both its audio processor and its gui.
|
||||
///
|
||||
/// II. Turning a knob on the DAW interface
|
||||
/// - the host will send an automation event to the plugin via a process() or flush()
|
||||
///
|
||||
/// III. Turning a knob on the Plugin interface
|
||||
/// - the plugin is responsible for sending the parameter value to its audio processor
|
||||
/// - call clap_host_params->request_flush() or clap_host->request_process().
|
||||
/// - when the host calls either clap_plugin->process() or clap_plugin_params->flush(),
|
||||
/// send an automation event and don't forget to wrap the parameter change(s)
|
||||
/// with CLAP_EVENT_PARAM_GESTURE_BEGIN and CLAP_EVENT_PARAM_GESTURE_END to define the
|
||||
/// beginning and end of the gesture.
|
||||
///
|
||||
/// IV. Turning a knob via automation
|
||||
/// - host sends an automation point during clap_plugin->process() or clap_plugin_params->flush().
|
||||
/// - the plugin is responsible for updating its GUI
|
||||
///
|
||||
/// V. Turning a knob via plugin's internal MIDI mapping
|
||||
/// - the plugin sends a CLAP_EVENT_PARAM_VALUE output event, set should_record to false
|
||||
/// - the plugin is responsible for updating its GUI
|
||||
///
|
||||
/// VI. Adding or removing parameters
|
||||
/// - if the plugin is activated call clap_host->restart()
|
||||
/// - once the plugin isn't active:
|
||||
/// - apply the new state
|
||||
/// - if a parameter is gone or is created with an id that may have been used before,
|
||||
/// call clap_host_params.clear(host, param_id, CLAP_PARAM_CLEAR_ALL)
|
||||
/// - call clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL)
|
||||
///
|
||||
/// CLAP allows the plugin to change the parameter range, yet the plugin developer
|
||||
/// should be aware that doing so isn't without risk, especially if you made the
|
||||
/// promise to never change the sound. If you want to be 100% certain that the
|
||||
/// sound will not change with all host, then simply never change the range.
|
||||
///
|
||||
/// There are two approaches to automations, either you automate the plain value,
|
||||
/// or you automate the knob position. The first option will be robust to a range
|
||||
/// increase, while the second won't be.
|
||||
///
|
||||
/// If the host goes with the second approach (automating the knob position), it means
|
||||
/// that the plugin is hosted in a relaxed environment regarding sound changes (they are
|
||||
/// accepted, and not a concern as long as they are reasonable). Though, stepped parameters
|
||||
/// should be stored as plain value in the document.
|
||||
///
|
||||
/// If the host goes with the first approach, there will still be situation where the
|
||||
/// sound may inevitably change. For example, if the plugin increase the range, there
|
||||
/// is an automation playing at the max value and on top of that an LFO is applied.
|
||||
/// See the following curve:
|
||||
/// .
|
||||
/// . .
|
||||
/// ..... . .
|
||||
/// before: . . and after: . .
|
||||
///
|
||||
/// Persisting parameter values:
|
||||
///
|
||||
/// Plugins are responsible for persisting their parameter's values between
|
||||
/// sessions by implementing the state extension. Otherwise parameter value will
|
||||
/// not be recalled when reloading a project. Hosts should _not_ try to save and
|
||||
/// restore parameter values for plugins that don't implement the state
|
||||
/// extension.
|
||||
///
|
||||
/// Advice for the host:
|
||||
///
|
||||
/// - store plain values in the document (automation)
|
||||
/// - store modulation amount in plain value delta, not in percentage
|
||||
/// - when you apply a CC mapping, remember the min/max plain values so you can adjust
|
||||
/// - do not implement a parameter saving fall back for plugins that don't
|
||||
/// implement the state extension
|
||||
///
|
||||
/// Advice for the plugin:
|
||||
///
|
||||
/// - think carefully about your parameter range when designing your DSP
|
||||
/// - avoid shrinking parameter ranges, they are very likely to change the sound
|
||||
/// - consider changing the parameter range as a tradeoff: what you improve vs what you break
|
||||
/// - make sure to implement saving and loading the parameter values using the
|
||||
/// state extension
|
||||
/// - if you plan to use adapters for other plugin formats, then you need to pay extra
|
||||
/// attention to the adapter requirements
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PARAMS[] = "clap.params";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// Is this param stepped? (integer values only)
|
||||
// if so the double value is converted to integer using a cast (equivalent to trunc).
|
||||
CLAP_PARAM_IS_STEPPED = 1 << 0,
|
||||
|
||||
// Useful for periodic parameters like a phase
|
||||
CLAP_PARAM_IS_PERIODIC = 1 << 1,
|
||||
|
||||
// The parameter should not be shown to the user, because it is currently not used.
|
||||
// It is not necessary to process automation for this parameter.
|
||||
CLAP_PARAM_IS_HIDDEN = 1 << 2,
|
||||
|
||||
// The parameter can't be changed by the host.
|
||||
CLAP_PARAM_IS_READONLY = 1 << 3,
|
||||
|
||||
// This parameter is used to merge the plugin and host bypass button.
|
||||
// It implies that the parameter is stepped.
|
||||
// Only zero or one bypass parameter is allowed per plugin.
|
||||
// min: 0 -> bypass off
|
||||
// max: 1 -> bypass on
|
||||
// The value of this parameter should not influence whether the host calls plugin->process() or
|
||||
// not. If a plugin wants to save CPU cycles during bypass, the plugin will implement that in its
|
||||
// process() routine, possibly returning CLAP_PROCESS_SLEEP at some point.
|
||||
CLAP_PARAM_IS_BYPASS = 1 << 4,
|
||||
|
||||
// When set:
|
||||
// - automation can be recorded
|
||||
// - automation can be played back
|
||||
//
|
||||
// The host can send live user changes for this parameter regardless of this flag.
|
||||
//
|
||||
// If this parameter affects the internal processing structure of the plugin, ie: max delay, fft
|
||||
// size, ... and the plugins needs to re-allocate its working buffers, then it should call
|
||||
// host->request_restart(), and perform the change once the plugin is re-activated.
|
||||
CLAP_PARAM_IS_AUTOMATABLE = 1 << 5,
|
||||
|
||||
// Does this parameter support per note automations?
|
||||
CLAP_PARAM_IS_AUTOMATABLE_PER_NOTE_ID = 1 << 6,
|
||||
|
||||
// Does this parameter support per key automations?
|
||||
CLAP_PARAM_IS_AUTOMATABLE_PER_KEY = 1 << 7,
|
||||
|
||||
// Does this parameter support per channel automations?
|
||||
CLAP_PARAM_IS_AUTOMATABLE_PER_CHANNEL = 1 << 8,
|
||||
|
||||
// Does this parameter support per port automations?
|
||||
CLAP_PARAM_IS_AUTOMATABLE_PER_PORT = 1 << 9,
|
||||
|
||||
// Does this parameter support the modulation signal?
|
||||
CLAP_PARAM_IS_MODULATABLE = 1 << 10,
|
||||
|
||||
// Does this parameter support per note modulations?
|
||||
CLAP_PARAM_IS_MODULATABLE_PER_NOTE_ID = 1 << 11,
|
||||
|
||||
// Does this parameter support per key modulations?
|
||||
CLAP_PARAM_IS_MODULATABLE_PER_KEY = 1 << 12,
|
||||
|
||||
// Does this parameter support per channel modulations?
|
||||
CLAP_PARAM_IS_MODULATABLE_PER_CHANNEL = 1 << 13,
|
||||
|
||||
// Does this parameter support per port modulations?
|
||||
CLAP_PARAM_IS_MODULATABLE_PER_PORT = 1 << 14,
|
||||
|
||||
// Any change to this parameter will affect the plugin output and requires to be done via
|
||||
// process() if the plugin is active.
|
||||
//
|
||||
// A simple example would be a DC Offset, changing it will change the output signal and must be
|
||||
// processed.
|
||||
CLAP_PARAM_REQUIRES_PROCESS = 1 << 15,
|
||||
|
||||
// This parameter represents an enumerated value.
|
||||
// If you set this flag, then you must set CLAP_PARAM_IS_STEPPED too.
|
||||
// All values from min to max must not have a blank value_to_text().
|
||||
CLAP_PARAM_IS_ENUM = 1 << 16,
|
||||
};
|
||||
typedef uint32_t clap_param_info_flags;
|
||||
|
||||
/* This describes a parameter */
|
||||
typedef struct clap_param_info {
|
||||
// Stable parameter identifier, it must never change.
|
||||
clap_id id;
|
||||
|
||||
clap_param_info_flags flags;
|
||||
|
||||
// This value is optional and set by the plugin.
|
||||
// Its purpose is to provide fast access to the plugin parameter object by caching its pointer.
|
||||
// For instance:
|
||||
//
|
||||
// in clap_plugin_params.get_info():
|
||||
// Parameter *p = findParameter(param_id);
|
||||
// param_info->cookie = p;
|
||||
//
|
||||
// later, in clap_plugin.process():
|
||||
//
|
||||
// Parameter *p = (Parameter *)event->cookie;
|
||||
// if (!p) [[unlikely]]
|
||||
// p = findParameter(event->param_id);
|
||||
//
|
||||
// where findParameter() is a function the plugin implements to map parameter ids to internal
|
||||
// objects.
|
||||
//
|
||||
// Important:
|
||||
// - The cookie is invalidated by a call to clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) or
|
||||
// when the plugin is destroyed.
|
||||
// - The host will either provide the cookie as issued or nullptr in events addressing
|
||||
// parameters.
|
||||
// - The plugin must gracefully handle the case of a cookie which is nullptr.
|
||||
// - Many plugins will process the parameter events more quickly if the host can provide the
|
||||
// cookie in a faster time than a hashmap lookup per param per event.
|
||||
void *cookie;
|
||||
|
||||
// The display name. eg: "Volume". This does not need to be unique. Do not include the module
|
||||
// text in this. The host should concatenate/format the module + name in the case where showing
|
||||
// the name alone would be too vague.
|
||||
char name[CLAP_NAME_SIZE];
|
||||
|
||||
// The module path containing the param, eg: "Oscillators/Wavetable 1".
|
||||
// '/' will be used as a separator to show a tree-like structure.
|
||||
char module[CLAP_PATH_SIZE];
|
||||
|
||||
double min_value; // Minimum plain value. Must be finite (`std::isfinite` true)
|
||||
double max_value; // Maximum plain value. Must be finite
|
||||
double default_value; // Default plain value. Must be in [min, max] range.
|
||||
} clap_param_info_t;
|
||||
|
||||
typedef struct clap_plugin_params {
|
||||
// Returns the number of parameters.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Copies the parameter's info to param_info.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_info)(const clap_plugin_t *plugin,
|
||||
uint32_t param_index,
|
||||
clap_param_info_t *param_info);
|
||||
|
||||
// Writes the parameter's current value to out_value.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get_value)(const clap_plugin_t *plugin, clap_id param_id, double *out_value);
|
||||
|
||||
// Fills out_buffer with a null-terminated UTF-8 string that represents the parameter at the
|
||||
// given 'value' argument. eg: "2.3 kHz". The host should always use this to format parameter
|
||||
// values before displaying it to the user.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *value_to_text)(const clap_plugin_t *plugin,
|
||||
clap_id param_id,
|
||||
double value,
|
||||
char *out_buffer,
|
||||
uint32_t out_buffer_capacity);
|
||||
|
||||
// Converts the null-terminated UTF-8 param_value_text into a double and writes it to out_value.
|
||||
// The host can use this to convert user input into a parameter value.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *text_to_value)(const clap_plugin_t *plugin,
|
||||
clap_id param_id,
|
||||
const char *param_value_text,
|
||||
double *out_value);
|
||||
|
||||
// Flushes a set of parameter changes.
|
||||
// This method must not be called concurrently to clap_plugin->process().
|
||||
//
|
||||
// Note: if the plugin is processing, then the process() call will already achieve the
|
||||
// parameter update (bi-directional), so a call to flush isn't required, also be aware
|
||||
// that the plugin may use the sample offset in process(), while this information would be
|
||||
// lost within flush().
|
||||
//
|
||||
// [active ? audio-thread : main-thread]
|
||||
void(CLAP_ABI *flush)(const clap_plugin_t *plugin,
|
||||
const clap_input_events_t *in,
|
||||
const clap_output_events_t *out);
|
||||
} clap_plugin_params_t;
|
||||
|
||||
enum {
|
||||
// The parameter values did change, eg. after loading a preset.
|
||||
// The host will scan all the parameters value.
|
||||
// The host will not record those changes as automation points.
|
||||
// New values takes effect immediately.
|
||||
CLAP_PARAM_RESCAN_VALUES = 1 << 0,
|
||||
|
||||
// The value to text conversion changed, and the text needs to be rendered again.
|
||||
CLAP_PARAM_RESCAN_TEXT = 1 << 1,
|
||||
|
||||
// The parameter info did change, use this flag for:
|
||||
// - name change
|
||||
// - module change
|
||||
// - is_periodic (flag)
|
||||
// - is_hidden (flag)
|
||||
// New info takes effect immediately.
|
||||
CLAP_PARAM_RESCAN_INFO = 1 << 2,
|
||||
|
||||
// Invalidates everything the host knows about parameters.
|
||||
// It can only be used while the plugin is deactivated.
|
||||
// If the plugin is activated use clap_host->restart() and delay any change until the host calls
|
||||
// clap_plugin->deactivate().
|
||||
//
|
||||
// You must use this flag if:
|
||||
// - some parameters were added or removed.
|
||||
// - some parameters had critical changes:
|
||||
// - is_per_note (flag)
|
||||
// - is_per_key (flag)
|
||||
// - is_per_channel (flag)
|
||||
// - is_per_port (flag)
|
||||
// - is_readonly (flag)
|
||||
// - is_bypass (flag)
|
||||
// - is_stepped (flag)
|
||||
// - is_modulatable (flag)
|
||||
// - min_value
|
||||
// - max_value
|
||||
// - cookie
|
||||
CLAP_PARAM_RESCAN_ALL = 1 << 3,
|
||||
};
|
||||
typedef uint32_t clap_param_rescan_flags;
|
||||
|
||||
enum {
|
||||
// Clears all possible references to a parameter
|
||||
CLAP_PARAM_CLEAR_ALL = 1 << 0,
|
||||
|
||||
// Clears all automations to a parameter
|
||||
CLAP_PARAM_CLEAR_AUTOMATIONS = 1 << 1,
|
||||
|
||||
// Clears all modulations to a parameter
|
||||
CLAP_PARAM_CLEAR_MODULATIONS = 1 << 2,
|
||||
};
|
||||
typedef uint32_t clap_param_clear_flags;
|
||||
|
||||
typedef struct clap_host_params {
|
||||
// Rescan the full list of parameters according to the flags.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *rescan)(const clap_host_t *host, clap_param_rescan_flags flags);
|
||||
|
||||
// Clears references to a parameter.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *clear)(const clap_host_t *host, clap_id param_id, clap_param_clear_flags flags);
|
||||
|
||||
// Request a parameter flush.
|
||||
//
|
||||
// The host will then schedule a call to either:
|
||||
// - clap_plugin.process()
|
||||
// - clap_plugin_params.flush()
|
||||
//
|
||||
// This function is always safe to use and should not be called from an [audio-thread] as the
|
||||
// plugin would already be within process() or flush().
|
||||
//
|
||||
// [thread-safe,!audio-thread]
|
||||
void(CLAP_ABI *request_flush)(const clap_host_t *host);
|
||||
} clap_host_params_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
49
third_party/clap/include/clap/ext/posix-fd-support.h
vendored
Normal file
49
third_party/clap/include/clap/ext/posix-fd-support.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// This extension let your plugin hook itself into the host select/poll/epoll/kqueue reactor.
|
||||
// This is useful to handle asynchronous I/O on the main thread.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_POSIX_FD_SUPPORT[] = "clap.posix-fd-support";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// IO events flags, they can be used to form a mask which describes:
|
||||
// - which events you are interested in (register_fd/modify_fd)
|
||||
// - which events happened (on_fd)
|
||||
CLAP_POSIX_FD_READ = 1 << 0,
|
||||
CLAP_POSIX_FD_WRITE = 1 << 1,
|
||||
CLAP_POSIX_FD_ERROR = 1 << 2,
|
||||
};
|
||||
typedef uint32_t clap_posix_fd_flags_t;
|
||||
|
||||
typedef struct clap_plugin_posix_fd_support {
|
||||
// This callback is "level-triggered".
|
||||
// It means that a writable fd will continuously produce "on_fd()" events;
|
||||
// don't forget using modify_fd() to remove the write notification once you're
|
||||
// done writing.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *on_fd)(const clap_plugin_t *plugin, int fd, clap_posix_fd_flags_t flags);
|
||||
} clap_plugin_posix_fd_support_t;
|
||||
|
||||
typedef struct clap_host_posix_fd_support {
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *register_fd)(const clap_host_t *host, int fd, clap_posix_fd_flags_t flags);
|
||||
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *modify_fd)(const clap_host_t *host, int fd, clap_posix_fd_flags_t flags);
|
||||
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *unregister_fd)(const clap_host_t *host, int fd);
|
||||
} clap_host_posix_fd_support_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
53
third_party/clap/include/clap/ext/preset-load.h
vendored
Normal file
53
third_party/clap/include/clap/ext/preset-load.h
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PRESET_LOAD[] = "clap.preset-load/2";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_PRESET_LOAD_COMPAT[] = "clap.preset-load.draft/2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_preset_load {
|
||||
// Loads a preset in the plugin native preset file format from a location.
|
||||
// The preset discovery provider defines the location and load_key to be passed to this function.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *from_location)(const clap_plugin_t *plugin,
|
||||
uint32_t location_kind,
|
||||
const char *location,
|
||||
const char *load_key);
|
||||
} clap_plugin_preset_load_t;
|
||||
|
||||
typedef struct clap_host_preset_load {
|
||||
// Called if clap_plugin_preset_load.from_location() failed.
|
||||
// os_error: the operating system error, if applicable. If not applicable set it to a non-error
|
||||
// value, eg: 0 on unix and Windows.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *on_error)(const clap_host_t *host,
|
||||
uint32_t location_kind,
|
||||
const char *location,
|
||||
const char *load_key,
|
||||
int32_t os_error,
|
||||
const char *msg);
|
||||
|
||||
// Informs the host that the following preset has been loaded.
|
||||
// This contributes to keep in sync the host preset browser and plugin preset browser.
|
||||
// If the preset was loaded from a container file, then the load_key must be set, otherwise it
|
||||
// must be null.
|
||||
//
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *loaded)(const clap_host_t *host,
|
||||
uint32_t location_kind,
|
||||
const char *location,
|
||||
const char *load_key);
|
||||
} clap_host_preset_load_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
83
third_party/clap/include/clap/ext/remote-controls.h
vendored
Normal file
83
third_party/clap/include/clap/ext/remote-controls.h
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
// This extension let the plugin provide a structured way of mapping parameters to an hardware
|
||||
// controller.
|
||||
//
|
||||
// This is done by providing a set of remote control pages organized by section.
|
||||
// A page contains up to 8 controls, which references parameters using param_id.
|
||||
//
|
||||
// |`- [section:main]
|
||||
// | `- [name:main] performance controls
|
||||
// |`- [section:osc]
|
||||
// | |`- [name:osc1] osc1 page
|
||||
// | |`- [name:osc2] osc2 page
|
||||
// | |`- [name:osc-sync] osc sync page
|
||||
// | `- [name:osc-noise] osc noise page
|
||||
// |`- [section:filter]
|
||||
// | |`- [name:flt1] filter 1 page
|
||||
// | `- [name:flt2] filter 2 page
|
||||
// |`- [section:env]
|
||||
// | |`- [name:env1] env1 page
|
||||
// | `- [name:env2] env2 page
|
||||
// |`- [section:lfo]
|
||||
// | |`- [name:lfo1] env1 page
|
||||
// | `- [name:lfo2] env2 page
|
||||
// `- etc...
|
||||
//
|
||||
// One possible workflow is to have a set of buttons, which correspond to a section.
|
||||
// Pressing that button once gets you to the first page of the section.
|
||||
// Press it again to cycle through the section's pages.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_REMOTE_CONTROLS[] = "clap.remote-controls/2";
|
||||
|
||||
// The latest draft is 100% compatible
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_REMOTE_CONTROLS_COMPAT[] = "clap.remote-controls.draft/2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum { CLAP_REMOTE_CONTROLS_COUNT = 8 };
|
||||
|
||||
typedef struct clap_remote_controls_page {
|
||||
char section_name[CLAP_NAME_SIZE];
|
||||
clap_id page_id;
|
||||
char page_name[CLAP_NAME_SIZE];
|
||||
clap_id param_ids[CLAP_REMOTE_CONTROLS_COUNT];
|
||||
|
||||
// This is used to separate device pages versus preset pages.
|
||||
// If true, then this page is specific to this preset.
|
||||
bool is_for_preset;
|
||||
} clap_remote_controls_page_t;
|
||||
|
||||
typedef struct clap_plugin_remote_controls {
|
||||
// Returns the number of pages.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
|
||||
|
||||
// Get a page by index.
|
||||
// Returns true on success and stores the result into page.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
|
||||
uint32_t page_index,
|
||||
clap_remote_controls_page_t *page);
|
||||
} clap_plugin_remote_controls_t;
|
||||
|
||||
typedef struct clap_host_remote_controls {
|
||||
// Informs the host that the remote controls have changed.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
|
||||
// Suggest a page to the host because it corresponds to what the user is currently editing in the
|
||||
// plugin's GUI.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *suggest_page)(const clap_host_t *host, clap_id page_id);
|
||||
} clap_host_remote_controls_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
39
third_party/clap/include/clap/ext/render.h
vendored
Normal file
39
third_party/clap/include/clap/ext/render.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_RENDER[] = "clap.render";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// Default setting, for "realtime" processing
|
||||
CLAP_RENDER_REALTIME = 0,
|
||||
|
||||
// For processing without realtime pressure
|
||||
// The plugin may use more expensive algorithms for higher sound quality.
|
||||
CLAP_RENDER_OFFLINE = 1,
|
||||
};
|
||||
typedef int32_t clap_plugin_render_mode;
|
||||
|
||||
// The render extension is used to let the plugin know if it has "realtime"
|
||||
// pressure to process.
|
||||
//
|
||||
// If this information does not influence your rendering code, then don't
|
||||
// implement this extension.
|
||||
typedef struct clap_plugin_render {
|
||||
// Returns true if the plugin has a hard requirement to process in real-time.
|
||||
// This is especially useful for plugin acting as a proxy to an hardware device.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *has_hard_realtime_requirement)(const clap_plugin_t *plugin);
|
||||
|
||||
// Returns true if the rendering mode could be applied.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *set)(const clap_plugin_t *plugin, clap_plugin_render_mode mode);
|
||||
} clap_plugin_render_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
72
third_party/clap/include/clap/ext/state-context.h
vendored
Normal file
72
third_party/clap/include/clap/ext/state-context.h
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../stream.h"
|
||||
|
||||
/// @page state-context extension
|
||||
/// @brief extended state handling
|
||||
///
|
||||
/// This extension lets the host save and load the plugin state with different semantics depending
|
||||
/// on the context.
|
||||
///
|
||||
/// Briefly, when loading a preset or duplicating a device, the plugin may want to partially load
|
||||
/// the state and initialize certain things differently, like handling limited resources or fixed
|
||||
/// connections to external hardware resources.
|
||||
///
|
||||
/// Save and Load operations may have a different context.
|
||||
/// All three operations should be equivalent:
|
||||
/// 1. clap_plugin_state_context.load(clap_plugin_state.save(), CLAP_STATE_CONTEXT_FOR_PRESET)
|
||||
/// 2. clap_plugin_state.load(clap_plugin_state_context.save(CLAP_STATE_CONTEXT_FOR_PRESET))
|
||||
/// 3. clap_plugin_state_context.load(
|
||||
/// clap_plugin_state_context.save(CLAP_STATE_CONTEXT_FOR_PRESET),
|
||||
/// CLAP_STATE_CONTEXT_FOR_PRESET)
|
||||
///
|
||||
/// If in doubt, fallback to clap_plugin_state.
|
||||
///
|
||||
/// If the plugin implements CLAP_EXT_STATE_CONTEXT then it is mandatory to also implement
|
||||
/// CLAP_EXT_STATE.
|
||||
///
|
||||
/// It is unspecified which context is equivalent to clap_plugin_state.{save,load}()
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_STATE_CONTEXT[] = "clap.state-context/2";
|
||||
|
||||
enum clap_plugin_state_context_type {
|
||||
// suitable for storing and loading a state as a preset
|
||||
CLAP_STATE_CONTEXT_FOR_PRESET = 1,
|
||||
|
||||
// suitable for duplicating a plugin instance
|
||||
CLAP_STATE_CONTEXT_FOR_DUPLICATE = 2,
|
||||
|
||||
// suitable for storing and loading a state within a project/song
|
||||
CLAP_STATE_CONTEXT_FOR_PROJECT = 3,
|
||||
};
|
||||
|
||||
typedef struct clap_plugin_state_context {
|
||||
// Saves the plugin state into stream, according to context_type.
|
||||
// Returns true if the state was correctly saved.
|
||||
//
|
||||
// Note that the result may be loaded by both clap_plugin_state.load() and
|
||||
// clap_plugin_state_context.load().
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *save)(const clap_plugin_t *plugin,
|
||||
const clap_ostream_t *stream,
|
||||
uint32_t context_type);
|
||||
|
||||
// Loads the plugin state from stream, according to context_type.
|
||||
// Returns true if the state was correctly restored.
|
||||
//
|
||||
// Note that the state may have been saved by clap_plugin_state.save() or
|
||||
// clap_plugin_state_context.save() with a different context_type.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *load)(const clap_plugin_t *plugin,
|
||||
const clap_istream_t *stream,
|
||||
uint32_t context_type);
|
||||
} clap_plugin_state_context_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
45
third_party/clap/include/clap/ext/state.h
vendored
Normal file
45
third_party/clap/include/clap/ext/state.h
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../stream.h"
|
||||
|
||||
/// @page State
|
||||
/// @brief state management
|
||||
///
|
||||
/// Plugins can implement this extension to save and restore both parameter
|
||||
/// values and non-parameter state. This is used to persist a plugin's state
|
||||
/// between project reloads, when duplicating and copying plugin instances, and
|
||||
/// for host-side preset management.
|
||||
///
|
||||
/// If you need to know if the save/load operation is meant for duplicating a plugin
|
||||
/// instance, for saving/loading a plugin preset or while saving/loading the project
|
||||
/// then consider implementing CLAP_EXT_STATE_CONTEXT in addition to CLAP_EXT_STATE.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_STATE[] = "clap.state";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_state {
|
||||
// Saves the plugin state into stream.
|
||||
// Returns true if the state was correctly saved.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *save)(const clap_plugin_t *plugin, const clap_ostream_t *stream);
|
||||
|
||||
// Loads the plugin state from stream.
|
||||
// Returns true if the state was correctly restored.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *load)(const clap_plugin_t *plugin, const clap_istream_t *stream);
|
||||
} clap_plugin_state_t;
|
||||
|
||||
typedef struct clap_host_state {
|
||||
// Tell the host that the plugin state has changed and should be saved again.
|
||||
// If a parameter value changes, then it is implicit that the state is dirty.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *mark_dirty)(const clap_host_t *host);
|
||||
} clap_host_state_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
86
third_party/clap/include/clap/ext/surround.h
vendored
Normal file
86
third_party/clap/include/clap/ext/surround.h
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// This extension can be used to specify the channel mapping used by the plugin.
|
||||
//
|
||||
// To have consistent surround features across all the plugin instances,
|
||||
// here is the proposed workflow:
|
||||
// 1. the plugin queries the host preferred channel mapping and
|
||||
// adjusts its configuration to match it.
|
||||
// 2. the host checks how the plugin is effectively configured and honors it.
|
||||
//
|
||||
// If the host decides to change the project's surround setup:
|
||||
// 1. deactivate the plugin
|
||||
// 2. host pushes a new configuration using clap_plugin_configurable_audio_ports
|
||||
// 3. host activates the plugin and can start processing audio
|
||||
//
|
||||
// If the plugin wants to change its surround setup:
|
||||
// 1. call host->request_restart() if the plugin is active
|
||||
// 2. once deactivated plugin calls clap_host_surround->changed()
|
||||
// 3. host calls clap_plugin_surround->get_channel_map()
|
||||
// 4. host activates the plugin and can start processing audio
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_SURROUND[] = "clap.surround/4";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_SURROUND_COMPAT[] = "clap.surround.draft/4";
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_PORT_SURROUND[] = "surround";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CLAP_SURROUND_FL = 0, // Front Left
|
||||
CLAP_SURROUND_FR = 1, // Front Right
|
||||
CLAP_SURROUND_FC = 2, // Front Center
|
||||
CLAP_SURROUND_LFE = 3, // Low Frequency
|
||||
CLAP_SURROUND_BL = 4, // Back (Rear) Left
|
||||
CLAP_SURROUND_BR = 5, // Back (Rear) Right
|
||||
CLAP_SURROUND_FLC = 6, // Front Left of Center
|
||||
CLAP_SURROUND_FRC = 7, // Front Right of Center
|
||||
CLAP_SURROUND_BC = 8, // Back (Rear) Center
|
||||
CLAP_SURROUND_SL = 9, // Side Left
|
||||
CLAP_SURROUND_SR = 10, // Side Right
|
||||
CLAP_SURROUND_TC = 11, // Top (Height) Center
|
||||
CLAP_SURROUND_TFL = 12, // Top (Height) Front Left
|
||||
CLAP_SURROUND_TFC = 13, // Top (Height) Front Center
|
||||
CLAP_SURROUND_TFR = 14, // Top (Height) Front Right
|
||||
CLAP_SURROUND_TBL = 15, // Top (Height) Back (Rear) Left
|
||||
CLAP_SURROUND_TBC = 16, // Top (Height) Back (Rear) Center
|
||||
CLAP_SURROUND_TBR = 17, // Top (Height) Back (Rear) Right
|
||||
CLAP_SURROUND_TSL = 18, // Top (Height) Side Left
|
||||
CLAP_SURROUND_TSR = 19, // Top (Height) Side Right
|
||||
};
|
||||
|
||||
typedef struct clap_plugin_surround {
|
||||
// Checks if a given channel mask is supported.
|
||||
// The channel mask is a bitmask, for example:
|
||||
// (1 << CLAP_SURROUND_FL) | (1 << CLAP_SURROUND_FR) | ...
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *is_channel_mask_supported)(const clap_plugin_t *plugin, uint64_t channel_mask);
|
||||
|
||||
// Stores the surround identifier of each channel into the channel_map array.
|
||||
// Returns the number of elements stored in channel_map.
|
||||
// channel_map_capacity must be greater or equal to the channel count of the given port.
|
||||
// [main-thread]
|
||||
uint32_t(CLAP_ABI *get_channel_map)(const clap_plugin_t *plugin,
|
||||
bool is_input,
|
||||
uint32_t port_index,
|
||||
uint8_t *channel_map,
|
||||
uint32_t channel_map_capacity);
|
||||
} clap_plugin_surround_t;
|
||||
|
||||
typedef struct clap_host_surround {
|
||||
// Informs the host that the channel map has changed.
|
||||
// The channel map can only change when the plugin is de-activated.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_surround_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
26
third_party/clap/include/clap/ext/tail.h
vendored
Normal file
26
third_party/clap/include/clap/ext/tail.h
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TAIL[] = "clap.tail";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_tail {
|
||||
// Returns tail length in samples.
|
||||
// Any value greater or equal to INT32_MAX implies infinite tail.
|
||||
// [main-thread,audio-thread]
|
||||
uint32_t(CLAP_ABI *get)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_tail_t;
|
||||
|
||||
typedef struct clap_host_tail {
|
||||
// Tell the host that the tail has changed.
|
||||
// [audio-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_tail_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
83
third_party/clap/include/clap/ext/thread-check.h
vendored
Normal file
83
third_party/clap/include/clap/ext/thread-check.h
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_THREAD_CHECK[] = "clap.thread-check";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// @page thread-check
|
||||
///
|
||||
/// CLAP defines two symbolic threads:
|
||||
///
|
||||
/// main-thread:
|
||||
/// This is the thread in which most of the interaction between the plugin and host happens.
|
||||
/// This will be the same OS thread throughout the lifetime of the plug-in.
|
||||
/// On macOS and Windows, this must be the thread on which gui and timer events are received
|
||||
/// (i.e., the main thread of the program).
|
||||
/// It isn't a realtime thread, yet this thread needs to respond fast enough to allow responsive
|
||||
/// user interaction, so it is strongly recommended plugins run long,and expensive or blocking
|
||||
/// tasks such as preset indexing or asset loading in dedicated background threads started by the
|
||||
/// plugin.
|
||||
///
|
||||
/// audio-thread:
|
||||
/// This thread can be used for realtime audio processing. Its execution should be as
|
||||
/// deterministic as possible to meet the audio interface's deadline (can be <1ms). There are a
|
||||
/// known set of operations that should be avoided: malloc() and free(), contended locks and
|
||||
/// mutexes, I/O, waiting, and so forth.
|
||||
///
|
||||
/// The audio-thread is symbolic, there isn't one OS thread that remains the
|
||||
/// audio-thread for the plugin lifetime. A host is may opt to have a
|
||||
/// thread pool and the plugin.process() call may be scheduled on different OS threads over time.
|
||||
/// However, the host must guarantee that single plugin instance will not be two audio-threads
|
||||
/// at the same time.
|
||||
///
|
||||
/// Functions marked with [audio-thread] **ARE NOT CONCURRENT**. The host may mark any OS thread,
|
||||
/// including the main-thread as the audio-thread, as long as it can guarantee that only one OS
|
||||
/// thread is the audio-thread at a time in a plugin instance. The audio-thread can be seen as a
|
||||
/// concurrency guard for all functions marked with [audio-thread].
|
||||
///
|
||||
/// The real-time constraint on the [audio-thread] interacts closely with the render extension.
|
||||
/// If a plugin doesn't implement render, then that plugin must have all [audio-thread] functions
|
||||
/// meet the real time standard. If the plugin does implement render, and returns true when
|
||||
/// render mode is set to real-time or if the plugin advertises a hard realtime requirement, it
|
||||
/// must implement realtime constraints. Hosts also provide functions marked [audio-thread].
|
||||
/// These can be safely called by a plugin in the audio thread. Therefore hosts must either (1)
|
||||
/// implement those functions meeting the real-time constraints or (2) not process plugins which
|
||||
/// advertise a hard realtime constraint or don't implement the render extension. Hosts which
|
||||
/// provide [audio-thread] functions outside these conditions may experience inconsistent or
|
||||
/// inaccurate rendering.
|
||||
///
|
||||
/// background-thread:
|
||||
/// This thread is created by the host to run some heavy operation without blocking the
|
||||
/// main-thread.
|
||||
///
|
||||
/// Only a few extensions use the background thread and in a very explicit way. If
|
||||
/// the plugin implement a background interfaces, it must take the necessary thread-safety
|
||||
/// precautions.
|
||||
///
|
||||
/// It is the host's responsiblity to execute background operations in a way that guarentee
|
||||
/// a race-free and deterministic execution.
|
||||
///
|
||||
/// Clap also tags some functions as [thread-safe]. Functions tagged as [thread-safe] can be called
|
||||
/// from any thread unless explicitly counter-indicated (for instance [thread-safe, !audio-thread])
|
||||
/// and may be called concurrently.
|
||||
|
||||
// This interface is useful to do runtime checks and make
|
||||
// sure that the functions are called on the correct threads.
|
||||
// It is highly recommended that hosts implement this extension.
|
||||
typedef struct clap_host_thread_check {
|
||||
// Returns true if "this" thread is the main thread.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *is_main_thread)(const clap_host_t *host);
|
||||
|
||||
// Returns true if "this" thread is one of the audio threads.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *is_audio_thread)(const clap_host_t *host);
|
||||
} clap_host_thread_check_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
66
third_party/clap/include/clap/ext/thread-pool.h
vendored
Normal file
66
third_party/clap/include/clap/ext/thread-pool.h
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
/// @page
|
||||
///
|
||||
/// This extension lets the plugin use the host's thread pool.
|
||||
///
|
||||
/// The plugin must provide @ref clap_plugin_thread_pool, and the host may provide @ref
|
||||
/// clap_host_thread_pool. If it doesn't, the plugin should process its data by its own means. In
|
||||
/// the worst case, a single threaded for-loop.
|
||||
///
|
||||
/// Simple example with N voices to process
|
||||
///
|
||||
/// @code
|
||||
/// void myplug_thread_pool_exec(const clap_plugin *plugin, uint32_t voice_index)
|
||||
/// {
|
||||
/// compute_voice(plugin, voice_index);
|
||||
/// }
|
||||
///
|
||||
/// void myplug_process(const clap_plugin *plugin, const clap_process *process)
|
||||
/// {
|
||||
/// ...
|
||||
/// bool didComputeVoices = false;
|
||||
/// if (host_thread_pool && host_thread_pool->request_exec)
|
||||
/// didComputeVoices = host_thread_pool->request_exec(host, N);
|
||||
///
|
||||
/// if (!didComputeVoices)
|
||||
/// for (uint32_t i = 0; i < N; ++i)
|
||||
/// myplug_thread_pool_exec(plugin, i);
|
||||
/// ...
|
||||
/// }
|
||||
/// @endcode
|
||||
///
|
||||
/// Be aware that using a thread pool may break hard real-time rules due to the thread
|
||||
/// synchronization involved.
|
||||
///
|
||||
/// If the host knows that it is running under hard real-time pressure it may decide to not
|
||||
/// provide this interface.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_THREAD_POOL[] = "clap.thread-pool";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_thread_pool {
|
||||
// Called by the thread pool
|
||||
void(CLAP_ABI *exec)(const clap_plugin_t *plugin, uint32_t task_index);
|
||||
} clap_plugin_thread_pool_t;
|
||||
|
||||
typedef struct clap_host_thread_pool {
|
||||
// Schedule num_tasks jobs in the host thread pool.
|
||||
// It can't be called concurrently or from the thread pool.
|
||||
// Will block until all the tasks are processed.
|
||||
// This must be used exclusively for realtime processing within the process call.
|
||||
// Returns true if the host did execute all the tasks, false if it rejected the request.
|
||||
// The host should check that the plugin is within the process call, and if not, reject the exec
|
||||
// request.
|
||||
// [audio-thread]
|
||||
bool(CLAP_ABI *request_exec)(const clap_host_t *host, uint32_t num_tasks);
|
||||
} clap_host_thread_pool_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
31
third_party/clap/include/clap/ext/timer-support.h
vendored
Normal file
31
third_party/clap/include/clap/ext/timer-support.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TIMER_SUPPORT[] = "clap.timer-support";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_timer_support {
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *on_timer)(const clap_plugin_t *plugin, clap_id timer_id);
|
||||
} clap_plugin_timer_support_t;
|
||||
|
||||
typedef struct clap_host_timer_support {
|
||||
// Registers a periodic timer.
|
||||
// The host may adjust the period if it is under a certain threshold.
|
||||
// 30 Hz should be allowed.
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *register_timer)(const clap_host_t *host, uint32_t period_ms, clap_id *timer_id);
|
||||
|
||||
// Returns true on success.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *unregister_timer)(const clap_host_t *host, clap_id timer_id);
|
||||
} clap_host_timer_support_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
66
third_party/clap/include/clap/ext/track-info.h
vendored
Normal file
66
third_party/clap/include/clap/ext/track-info.h
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
#include "../color.h"
|
||||
#include "../string-sizes.h"
|
||||
|
||||
// This extension let the plugin query info about the track it's in.
|
||||
// It is useful when the plugin is created, to initialize some parameters (mix, dry, wet)
|
||||
// and pick a suitable configuration regarding audio port type and channel count.
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TRACK_INFO[] = "clap.track-info/1";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_TRACK_INFO_COMPAT[] = "clap.track-info.draft/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CLAP_TRACK_INFO_HAS_TRACK_NAME = (1 << 0),
|
||||
CLAP_TRACK_INFO_HAS_TRACK_COLOR = (1 << 1),
|
||||
CLAP_TRACK_INFO_HAS_AUDIO_CHANNEL = (1 << 2),
|
||||
|
||||
// This plugin is on a return track, initialize with wet 100%
|
||||
CLAP_TRACK_INFO_IS_FOR_RETURN_TRACK = (1 << 3),
|
||||
|
||||
// This plugin is on a bus track, initialize with appropriate settings for bus processing
|
||||
CLAP_TRACK_INFO_IS_FOR_BUS = (1 << 4),
|
||||
|
||||
// This plugin is on the master, initialize with appropriate settings for channel processing
|
||||
CLAP_TRACK_INFO_IS_FOR_MASTER = (1 << 5),
|
||||
};
|
||||
|
||||
typedef struct clap_track_info {
|
||||
uint64_t flags; // see the flags above
|
||||
|
||||
// track name, available if flags contain CLAP_TRACK_INFO_HAS_TRACK_NAME
|
||||
char name[CLAP_NAME_SIZE];
|
||||
|
||||
// track color, available if flags contain CLAP_TRACK_INFO_HAS_TRACK_COLOR
|
||||
clap_color_t color;
|
||||
|
||||
// available if flags contain CLAP_TRACK_INFO_HAS_AUDIO_CHANNEL
|
||||
// see audio-ports.h, struct clap_audio_port_info to learn how to use channel count and port type
|
||||
int32_t audio_channel_count;
|
||||
const char *audio_port_type;
|
||||
} clap_track_info_t;
|
||||
|
||||
typedef struct clap_plugin_track_info {
|
||||
// Called when the info changes.
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_plugin_t *plugin);
|
||||
} clap_plugin_track_info_t;
|
||||
|
||||
typedef struct clap_host_track_info {
|
||||
// Get info about the track the plugin belongs to.
|
||||
// Returns true on success and stores the result into info.
|
||||
// [main-thread]
|
||||
bool(CLAP_ABI *get)(const clap_host_t *host, clap_track_info_t *info);
|
||||
} clap_host_track_info_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
56
third_party/clap/include/clap/ext/voice-info.h
vendored
Normal file
56
third_party/clap/include/clap/ext/voice-info.h
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// This extension indicates the number of voices the synthesizer has.
|
||||
// It is useful for the host when performing polyphonic modulations,
|
||||
// because the host needs its own voice management and should try to follow
|
||||
// what the plugin is doing:
|
||||
// - make the host's voice pool coherent with what the plugin has
|
||||
// - turn the host's voice management to mono when the plugin is mono
|
||||
|
||||
static CLAP_CONSTEXPR const char CLAP_EXT_VOICE_INFO[] = "clap.voice-info";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
// Allows the host to send overlapping NOTE_ON events.
|
||||
// The plugin will then rely upon the note_id to distinguish between them.
|
||||
CLAP_VOICE_INFO_SUPPORTS_OVERLAPPING_NOTES = 1 << 0,
|
||||
};
|
||||
|
||||
typedef struct clap_voice_info {
|
||||
// voice_count is the current number of voices that the patch can use
|
||||
// voice_capacity is the number of voices allocated voices
|
||||
// voice_count should not be confused with the number of active voices.
|
||||
//
|
||||
// 1 <= voice_count <= voice_capacity
|
||||
//
|
||||
// For example, a synth can have a capacity of 8 voices, but be configured
|
||||
// to only use 4 voices: {count: 4, capacity: 8}.
|
||||
//
|
||||
// If the voice_count is 1, then the synth is working in mono and the host
|
||||
// can decide to only use global modulation mapping.
|
||||
uint32_t voice_count;
|
||||
uint32_t voice_capacity;
|
||||
|
||||
uint64_t flags;
|
||||
} clap_voice_info_t;
|
||||
|
||||
typedef struct clap_plugin_voice_info {
|
||||
// gets the voice info, returns true on success
|
||||
// [main-thread & active]
|
||||
bool(CLAP_ABI *get)(const clap_plugin_t *plugin, clap_voice_info_t *info);
|
||||
} clap_plugin_voice_info_t;
|
||||
|
||||
typedef struct clap_host_voice_info {
|
||||
// informs the host that the voice info has changed
|
||||
// [main-thread]
|
||||
void(CLAP_ABI *changed)(const clap_host_t *host);
|
||||
} clap_host_voice_info_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
third_party/clap/include/clap/factory/draft/plugin-invalidation.h
vendored
Normal file
47
third_party/clap/include/clap/factory/draft/plugin-invalidation.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../private/std.h"
|
||||
#include "../../private/macros.h"
|
||||
|
||||
// Use it to retrieve const clap_plugin_invalidation_factory_t* from
|
||||
// clap_plugin_entry.get_factory()
|
||||
static const CLAP_CONSTEXPR char CLAP_PLUGIN_INVALIDATION_FACTORY_ID[] =
|
||||
"clap.plugin-invalidation-factory/1";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_invalidation_source {
|
||||
// Directory containing the file(s) to scan, must be absolute
|
||||
const char *directory;
|
||||
|
||||
// globing pattern, in the form *.dll
|
||||
const char *filename_glob;
|
||||
|
||||
// should the directory be scanned recursively?
|
||||
bool recursive_scan;
|
||||
} clap_plugin_invalidation_source_t;
|
||||
|
||||
// Used to figure out when a plugin needs to be scanned again.
|
||||
// Imagine a situation with a single entry point: my-plugin.clap which then scans itself
|
||||
// a set of "sub-plugins". New plugin may be available even if my-plugin.clap file doesn't change.
|
||||
// This interfaces solves this issue and gives a way to the host to monitor additional files.
|
||||
typedef struct clap_plugin_invalidation_factory {
|
||||
// Get the number of invalidation source.
|
||||
uint32_t(CLAP_ABI *count)(const struct clap_plugin_invalidation_factory *factory);
|
||||
|
||||
// Get the invalidation source by its index.
|
||||
// [thread-safe]
|
||||
const clap_plugin_invalidation_source_t *(CLAP_ABI *get)(
|
||||
const struct clap_plugin_invalidation_factory *factory, uint32_t index);
|
||||
|
||||
// In case the host detected a invalidation event, it can call refresh() to let the
|
||||
// plugin_entry update the set of plugins available.
|
||||
// If the function returned false, then the plugin needs to be reloaded.
|
||||
bool(CLAP_ABI *refresh)(const struct clap_plugin_invalidation_factory *factory);
|
||||
} clap_plugin_invalidation_factory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
99
third_party/clap/include/clap/factory/draft/plugin-state-converter.h
vendored
Normal file
99
third_party/clap/include/clap/factory/draft/plugin-state-converter.h
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../id.h"
|
||||
#include "../../universal-plugin-id.h"
|
||||
#include "../../stream.h"
|
||||
#include "../../version.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_plugin_state_converter_descriptor {
|
||||
clap_version_t clap_version;
|
||||
|
||||
clap_universal_plugin_id_t src_plugin_id;
|
||||
clap_universal_plugin_id_t dst_plugin_id;
|
||||
|
||||
const char *id; // eg: "com.u-he.diva-converter", mandatory
|
||||
const char *name; // eg: "Diva Converter", mandatory
|
||||
const char *vendor; // eg: "u-he"
|
||||
const char *version; // eg: 1.1.5
|
||||
const char *description; // eg: "Official state converter for u-he Diva."
|
||||
} clap_plugin_state_converter_descriptor_t;
|
||||
|
||||
// This interface provides a mechanism for the host to convert a plugin state and its automation
|
||||
// points to a new plugin.
|
||||
//
|
||||
// This is useful to convert from one plugin ABI to another one.
|
||||
// This is also useful to offer an upgrade path: from EQ version 1 to EQ version 2.
|
||||
// This can also be used to convert the state of a plugin that isn't maintained anymore into
|
||||
// another plugin that would be similar.
|
||||
typedef struct clap_plugin_state_converter {
|
||||
const clap_plugin_state_converter_descriptor_t *desc;
|
||||
|
||||
void *converter_data;
|
||||
|
||||
// Destroy the converter.
|
||||
void(CLAP_ABI *destroy)(struct clap_plugin_state_converter *converter);
|
||||
|
||||
// Converts the input state to a state usable by the destination plugin.
|
||||
//
|
||||
// error_buffer is a place holder of error_buffer_size bytes for storing a null-terminated
|
||||
// error message in case of failure, which can be displayed to the user.
|
||||
//
|
||||
// Returns true on success.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *convert_state)(struct clap_plugin_state_converter *converter,
|
||||
const clap_istream_t *src,
|
||||
const clap_ostream_t *dst,
|
||||
char *error_buffer,
|
||||
size_t error_buffer_size);
|
||||
|
||||
// Converts a normalized value.
|
||||
// Returns true on success.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *convert_normalized_value)(struct clap_plugin_state_converter *converter,
|
||||
clap_id src_param_id,
|
||||
double src_normalized_value,
|
||||
clap_id *dst_param_id,
|
||||
double *dst_normalized_value);
|
||||
|
||||
// Converts a plain value.
|
||||
// Returns true on success.
|
||||
// [thread-safe]
|
||||
bool(CLAP_ABI *convert_plain_value)(struct clap_plugin_state_converter *converter,
|
||||
clap_id src_param_id,
|
||||
double src_plain_value,
|
||||
clap_id *dst_param_id,
|
||||
double *dst_plain_value);
|
||||
} clap_plugin_state_converter_t;
|
||||
|
||||
// Factory identifier
|
||||
static CLAP_CONSTEXPR const char CLAP_PLUGIN_STATE_CONVERTER_FACTORY_ID[] =
|
||||
"clap.plugin-state-converter-factory/1";
|
||||
|
||||
// List all the plugin state converters available in the current DSO.
|
||||
typedef struct clap_plugin_state_converter_factory {
|
||||
// Get the number of converters.
|
||||
// [thread-safe]
|
||||
uint32_t(CLAP_ABI *count)(const struct clap_plugin_state_converter_factory *factory);
|
||||
|
||||
// Retrieves a plugin state converter descriptor by its index.
|
||||
// Returns null in case of error.
|
||||
// The descriptor must not be freed.
|
||||
// [thread-safe]
|
||||
const clap_plugin_state_converter_descriptor_t *(CLAP_ABI *get_descriptor)(
|
||||
const struct clap_plugin_state_converter_factory *factory, uint32_t index);
|
||||
|
||||
// Create a plugin state converter by its converter_id.
|
||||
// The returned pointer must be freed by calling converter->destroy(converter);
|
||||
// Returns null in case of error.
|
||||
// [thread-safe]
|
||||
clap_plugin_state_converter_t *(CLAP_ABI *create)(
|
||||
const struct clap_plugin_state_converter_factory *factory, const char *converter_id);
|
||||
} clap_plugin_state_converter_factory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
43
third_party/clap/include/clap/factory/plugin-factory.h
vendored
Normal file
43
third_party/clap/include/clap/factory/plugin-factory.h
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "../plugin.h"
|
||||
|
||||
// Use it to retrieve const clap_plugin_factory_t* from
|
||||
// clap_plugin_entry.get_factory()
|
||||
static const CLAP_CONSTEXPR char CLAP_PLUGIN_FACTORY_ID[] = "clap.plugin-factory";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Every method must be thread-safe.
|
||||
// It is very important to be able to scan the plugin as quickly as possible.
|
||||
//
|
||||
// The host may use clap_plugin_invalidation_factory to detect filesystem changes
|
||||
// which may change the factory's content.
|
||||
typedef struct clap_plugin_factory {
|
||||
// Get the number of plugins available.
|
||||
// [thread-safe]
|
||||
uint32_t(CLAP_ABI *get_plugin_count)(const struct clap_plugin_factory *factory);
|
||||
|
||||
// Retrieves a plugin descriptor by its index.
|
||||
// The descriptor is owned by the plugin and is valid until the call to clap_plugin_entry->deinit()
|
||||
// Returns null in case of error.
|
||||
// [thread-safe]
|
||||
const clap_plugin_descriptor_t *(CLAP_ABI *get_plugin_descriptor)(
|
||||
const struct clap_plugin_factory *factory, uint32_t index);
|
||||
|
||||
// Create a clap_plugin by its plugin_id.
|
||||
// The clap_host pointer must be valid until after the call to plugin->destroy(plugin).
|
||||
// The returned pointer is owned by the plugin and must be freed by calling plugin->destroy(plugin);
|
||||
// The plugin is not allowed to use the host callbacks in the create method.
|
||||
// Returns null in case of error.
|
||||
// [thread-safe]
|
||||
const clap_plugin_t *(CLAP_ABI *create_plugin)(const struct clap_plugin_factory *factory,
|
||||
const clap_host_t *host,
|
||||
const char *plugin_id);
|
||||
} clap_plugin_factory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
313
third_party/clap/include/clap/factory/preset-discovery.h
vendored
Normal file
313
third_party/clap/include/clap/factory/preset-discovery.h
vendored
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
/*
|
||||
Preset Discovery API.
|
||||
|
||||
Preset Discovery enables a plug-in host to identify where presets are found, what
|
||||
extensions they have, which plug-ins they apply to, and other metadata associated with the
|
||||
presets so that they can be indexed and searched for quickly within the plug-in host's browser.
|
||||
|
||||
This has a number of advantages for the user:
|
||||
- it allows them to browse for presets from one central location in a consistent way
|
||||
- the user can browse for presets without having to commit to a particular plug-in first
|
||||
|
||||
The API works as follow to index presets and presets metadata:
|
||||
1. clap_plugin_entry.get_factory(CLAP_PRESET_DISCOVERY_FACTORY_ID)
|
||||
2. clap_preset_discovery_factory_t.create(...)
|
||||
3. clap_preset_discovery_provider.init() (only necessary the first time, declarations
|
||||
can be cached)
|
||||
`-> clap_preset_discovery_indexer.declare_filetype()
|
||||
`-> clap_preset_discovery_indexer.declare_location()
|
||||
`-> clap_preset_discovery_indexer.declare_soundpack() (optional)
|
||||
`-> clap_preset_discovery_indexer.set_invalidation_watch_file() (optional)
|
||||
4. crawl the given locations and monitor file system changes
|
||||
`-> clap_preset_discovery_indexer.get_metadata() for each presets files
|
||||
|
||||
Then to load a preset, use ext/draft/preset-load.h.
|
||||
TODO: create a dedicated repo for other plugin abi preset-load extension.
|
||||
|
||||
The design of this API deliberately does not define a fixed set tags or categories. It is the
|
||||
plug-in host's job to try to intelligently map the raw list of features that are found for a
|
||||
preset and to process this list to generate something that makes sense for the host's tagging and
|
||||
categorization system. The reason for this is to reduce the work for a plug-in developer to add
|
||||
Preset Discovery support for their existing preset file format and not have to be concerned with
|
||||
all the different hosts and how they want to receive the metadata.
|
||||
|
||||
VERY IMPORTANT:
|
||||
- the whole indexing process has to be **fast**
|
||||
- clap_preset_provider->get_metadata() has to be fast and avoid unnecessary operations
|
||||
- the whole indexing process must not be interactive
|
||||
- don't show dialogs, windows, ...
|
||||
- don't ask for user input
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../private/std.h"
|
||||
#include "../private/macros.h"
|
||||
#include "../timestamp.h"
|
||||
#include "../version.h"
|
||||
#include "../universal-plugin-id.h"
|
||||
|
||||
// Use it to retrieve const clap_preset_discovery_factory_t* from
|
||||
// clap_plugin_entry.get_factory()
|
||||
static const CLAP_CONSTEXPR char CLAP_PRESET_DISCOVERY_FACTORY_ID[] =
|
||||
"clap.preset-discovery-factory/2";
|
||||
|
||||
// The latest draft is 100% compatible.
|
||||
// This compat ID may be removed in 2026.
|
||||
static const CLAP_CONSTEXPR char CLAP_PRESET_DISCOVERY_FACTORY_ID_COMPAT[] =
|
||||
"clap.preset-discovery-factory/draft-2";
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum clap_preset_discovery_location_kind {
|
||||
// The preset are located in a file on the OS filesystem.
|
||||
// The location is then a path which works with the OS file system functions (open, stat, ...)
|
||||
// So both '/' and '\' shall work on Windows as a separator.
|
||||
CLAP_PRESET_DISCOVERY_LOCATION_FILE = 0,
|
||||
|
||||
// The preset is bundled within the plugin DSO itself.
|
||||
// The location must then be null, as the preset are within the plugin itself and then the plugin
|
||||
// will act as a preset container.
|
||||
CLAP_PRESET_DISCOVERY_LOCATION_PLUGIN = 1,
|
||||
};
|
||||
|
||||
enum clap_preset_discovery_flags {
|
||||
// This is for factory or sound-pack presets.
|
||||
CLAP_PRESET_DISCOVERY_IS_FACTORY_CONTENT = 1 << 0,
|
||||
|
||||
// This is for user presets.
|
||||
CLAP_PRESET_DISCOVERY_IS_USER_CONTENT = 1 << 1,
|
||||
|
||||
// This location is meant for demo presets, those are preset which may trigger
|
||||
// some limitation in the plugin because they require additional features which the user
|
||||
// needs to purchase or the content itself needs to be bought and is only available in
|
||||
// demo mode.
|
||||
CLAP_PRESET_DISCOVERY_IS_DEMO_CONTENT = 1 << 2,
|
||||
|
||||
// This preset is a user's favorite
|
||||
CLAP_PRESET_DISCOVERY_IS_FAVORITE = 1 << 3,
|
||||
};
|
||||
|
||||
// Receiver that receives the metadata for a single preset file.
|
||||
// The host would define the various callbacks in this interface and the preset parser function
|
||||
// would then call them.
|
||||
//
|
||||
// This interface isn't thread-safe.
|
||||
typedef struct clap_preset_discovery_metadata_receiver {
|
||||
void *receiver_data; // reserved pointer for the metadata receiver
|
||||
|
||||
// If there is an error reading metadata from a file this should be called with an error
|
||||
// message.
|
||||
// os_error: the operating system error, if applicable. If not applicable set it to a non-error
|
||||
// value, eg: 0 on unix and Windows.
|
||||
void(CLAP_ABI *on_error)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
int32_t os_error,
|
||||
const char *error_message);
|
||||
|
||||
// This must be called for every preset in the file and before any preset metadata is
|
||||
// sent with the calls below.
|
||||
//
|
||||
// If the preset file is a preset container then name and load_key are mandatory, otherwise
|
||||
// they are optional.
|
||||
//
|
||||
// The load_key is a machine friendly string used to load the preset inside the container via a
|
||||
// the preset-load plug-in extension. The load_key can also just be the subpath if that's what
|
||||
// the plugin wants but it could also be some other unique id like a database primary key or a
|
||||
// binary offset. It's use is entirely up to the plug-in.
|
||||
//
|
||||
// If the function returns false, then the provider must stop calling back into the receiver.
|
||||
bool(CLAP_ABI *begin_preset)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *name,
|
||||
const char *load_key);
|
||||
|
||||
// Adds a plug-in id that this preset can be used with.
|
||||
void(CLAP_ABI *add_plugin_id)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const clap_universal_plugin_id_t *plugin_id);
|
||||
|
||||
// Sets the sound pack to which the preset belongs to.
|
||||
void(CLAP_ABI *set_soundpack_id)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *soundpack_id);
|
||||
|
||||
// Sets the flags, see clap_preset_discovery_flags.
|
||||
// If unset, they are then inherited from the location.
|
||||
void(CLAP_ABI *set_flags)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
uint32_t flags);
|
||||
|
||||
// Adds a creator name for the preset.
|
||||
void(CLAP_ABI *add_creator)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *creator);
|
||||
|
||||
// Sets a description of the preset.
|
||||
void(CLAP_ABI *set_description)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *description);
|
||||
|
||||
// Sets the creation time and last modification time of the preset.
|
||||
// If one of the times isn't known, set it to CLAP_TIMESTAMP_UNKNOWN.
|
||||
// If this function is not called, then the indexer may look at the file's creation and
|
||||
// modification time.
|
||||
void(CLAP_ABI *set_timestamps)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
clap_timestamp creation_time,
|
||||
clap_timestamp modification_time);
|
||||
|
||||
// Adds a feature to the preset.
|
||||
//
|
||||
// The feature string is arbitrary, it is the indexer's job to understand it and remap it to its
|
||||
// internal categorization and tagging system.
|
||||
//
|
||||
// However, the strings from plugin-features.h should be understood by the indexer and one of the
|
||||
// plugin category could be provided to determine if the preset will result into an audio-effect,
|
||||
// instrument, ...
|
||||
//
|
||||
// Examples:
|
||||
// kick, drum, tom, snare, clap, cymbal, bass, lead, metalic, hardsync, crossmod, acid,
|
||||
// distorted, drone, pad, dirty, etc...
|
||||
void(CLAP_ABI *add_feature)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *feature);
|
||||
|
||||
// Adds extra information to the metadata.
|
||||
void(CLAP_ABI *add_extra_info)(const struct clap_preset_discovery_metadata_receiver *receiver,
|
||||
const char *key,
|
||||
const char *value);
|
||||
} clap_preset_discovery_metadata_receiver_t;
|
||||
|
||||
typedef struct clap_preset_discovery_filetype {
|
||||
const char *name;
|
||||
const char *description; // optional
|
||||
|
||||
// `.' isn't included in the string.
|
||||
// If empty or NULL then every file should be matched.
|
||||
const char *file_extension;
|
||||
} clap_preset_discovery_filetype_t;
|
||||
|
||||
// Defines a place in which to search for presets
|
||||
typedef struct clap_preset_discovery_location {
|
||||
uint32_t flags; // see enum clap_preset_discovery_flags
|
||||
const char *name; // name of this location
|
||||
uint32_t kind; // See clap_preset_discovery_location_kind
|
||||
|
||||
// Actual location in which to crawl presets.
|
||||
// For FILE kind, the location can be either a path to a directory or a file.
|
||||
// For PLUGIN kind, the location must be null.
|
||||
const char *location;
|
||||
} clap_preset_discovery_location_t;
|
||||
|
||||
// Describes an installed sound pack.
|
||||
typedef struct clap_preset_discovery_soundpack {
|
||||
uint32_t flags; // see enum clap_preset_discovery_flags
|
||||
const char *id; // sound pack identifier
|
||||
const char *name; // name of this sound pack
|
||||
const char *description; // optional, reasonably short description of the sound pack
|
||||
const char *homepage_url; // optional, url to the pack's homepage
|
||||
const char *vendor; // optional, sound pack's vendor
|
||||
const char *image_path; // optional, an image on disk
|
||||
clap_timestamp release_timestamp; // release date, CLAP_TIMESTAMP_UNKNOWN if unavailable
|
||||
} clap_preset_discovery_soundpack_t;
|
||||
|
||||
// Describes a preset provider
|
||||
typedef struct clap_preset_discovery_provider_descriptor {
|
||||
clap_version_t clap_version; // initialized to CLAP_VERSION
|
||||
const char *id; // see plugin.h for advice on how to choose a good identifier
|
||||
const char *name; // eg: "Diva's preset provider"
|
||||
const char *vendor; // optional, eg: u-he
|
||||
} clap_preset_discovery_provider_descriptor_t;
|
||||
|
||||
// This interface isn't thread-safe.
|
||||
typedef struct clap_preset_discovery_provider {
|
||||
const clap_preset_discovery_provider_descriptor_t *desc;
|
||||
|
||||
void *provider_data; // reserved pointer for the provider
|
||||
|
||||
// Initialize the preset provider.
|
||||
// It should declare all its locations, filetypes and sound packs.
|
||||
// Returns false if initialization failed.
|
||||
bool(CLAP_ABI *init)(const struct clap_preset_discovery_provider *provider);
|
||||
|
||||
// Destroys the preset provider
|
||||
void(CLAP_ABI *destroy)(const struct clap_preset_discovery_provider *provider);
|
||||
|
||||
// reads metadata from the given file and passes them to the metadata receiver
|
||||
// Returns true on success.
|
||||
bool(CLAP_ABI *get_metadata)(const struct clap_preset_discovery_provider *provider,
|
||||
uint32_t location_kind,
|
||||
const char *location,
|
||||
const clap_preset_discovery_metadata_receiver_t *metadata_receiver);
|
||||
|
||||
// Query an extension.
|
||||
// The returned pointer is owned by the provider.
|
||||
// It is forbidden to call it before provider->init().
|
||||
// You can call it within provider->init() call, and after.
|
||||
const void *(CLAP_ABI *get_extension)(const struct clap_preset_discovery_provider *provider,
|
||||
const char *extension_id);
|
||||
} clap_preset_discovery_provider_t;
|
||||
|
||||
// This interface isn't thread-safe
|
||||
typedef struct clap_preset_discovery_indexer {
|
||||
clap_version_t clap_version; // initialized to CLAP_VERSION
|
||||
const char *name; // eg: "Bitwig Studio"
|
||||
const char *vendor; // optional, eg: "Bitwig GmbH"
|
||||
const char *url; // optional, eg: "https://bitwig.com"
|
||||
const char *version; // optional, eg: "4.3", see plugin.h for advice on how to format the version
|
||||
|
||||
void *indexer_data; // reserved pointer for the indexer
|
||||
|
||||
// Declares a preset filetype.
|
||||
// Don't callback into the provider during this call.
|
||||
// Returns false if the filetype is invalid.
|
||||
bool(CLAP_ABI *declare_filetype)(const struct clap_preset_discovery_indexer *indexer,
|
||||
const clap_preset_discovery_filetype_t *filetype);
|
||||
|
||||
// Declares a preset location.
|
||||
// Don't callback into the provider during this call.
|
||||
// Returns false if the location is invalid.
|
||||
bool(CLAP_ABI *declare_location)(const struct clap_preset_discovery_indexer *indexer,
|
||||
const clap_preset_discovery_location_t *location);
|
||||
|
||||
// Declares a sound pack.
|
||||
// Don't callback into the provider during this call.
|
||||
// Returns false if the sound pack is invalid.
|
||||
bool(CLAP_ABI *declare_soundpack)(const struct clap_preset_discovery_indexer *indexer,
|
||||
const clap_preset_discovery_soundpack_t *soundpack);
|
||||
|
||||
// Query an extension.
|
||||
// The returned pointer is owned by the indexer.
|
||||
// It is forbidden to call it before provider->init().
|
||||
// You can call it within provider->init() call, and after.
|
||||
const void *(CLAP_ABI *get_extension)(const struct clap_preset_discovery_indexer *indexer,
|
||||
const char *extension_id);
|
||||
} clap_preset_discovery_indexer_t;
|
||||
|
||||
// Every methods in this factory must be thread-safe.
|
||||
// It is encouraged to perform preset indexing in background threads, maybe even in background
|
||||
// process.
|
||||
//
|
||||
// The host may use clap_plugin_invalidation_factory to detect filesystem changes
|
||||
// which may change the factory's content.
|
||||
typedef struct clap_preset_discovery_factory {
|
||||
// Get the number of preset providers available.
|
||||
// [thread-safe]
|
||||
uint32_t(CLAP_ABI *count)(const struct clap_preset_discovery_factory *factory);
|
||||
|
||||
// Retrieves a preset provider descriptor by its index.
|
||||
// Returns null in case of error.
|
||||
// The descriptor must not be freed.
|
||||
// [thread-safe]
|
||||
const clap_preset_discovery_provider_descriptor_t *(CLAP_ABI *get_descriptor)(
|
||||
const struct clap_preset_discovery_factory *factory, uint32_t index);
|
||||
|
||||
// Create a preset provider by its id.
|
||||
// The returned pointer must be freed by calling preset_provider->destroy(preset_provider);
|
||||
// The preset provider is not allowed to use the indexer callbacks in the create method.
|
||||
// It is forbidden to call back into the indexer before the indexer calls provider->init().
|
||||
// Returns null in case of error.
|
||||
// [thread-safe]
|
||||
const clap_preset_discovery_provider_t *(CLAP_ABI *create)(
|
||||
const struct clap_preset_discovery_factory *factory,
|
||||
const clap_preset_discovery_indexer_t *indexer,
|
||||
const char *provider_id);
|
||||
} clap_preset_discovery_factory_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
16
third_party/clap/include/clap/fixedpoint.h
vendored
Normal file
16
third_party/clap/include/clap/fixedpoint.h
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "private/std.h"
|
||||
#include "private/macros.h"
|
||||
|
||||
/// We use fixed point representation of beat time and seconds time
|
||||
/// Usage:
|
||||
/// double x = ...; // in beats
|
||||
/// clap_beattime y = round(CLAP_BEATTIME_FACTOR * x);
|
||||
|
||||
// This will never change
|
||||
static const CLAP_CONSTEXPR int64_t CLAP_BEATTIME_FACTOR = 1LL << 31;
|
||||
static const CLAP_CONSTEXPR int64_t CLAP_SECTIME_FACTOR = 1LL << 31;
|
||||
|
||||
typedef int64_t clap_beattime;
|
||||
typedef int64_t clap_sectime;
|
||||
51
third_party/clap/include/clap/host.h
vendored
Normal file
51
third_party/clap/include/clap/host.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct clap_host {
|
||||
clap_version_t clap_version; // initialized to CLAP_VERSION
|
||||
|
||||
void *host_data; // reserved pointer for the host
|
||||
|
||||
// name and version are mandatory.
|
||||
const char *name; // eg: "Bitwig Studio"
|
||||
const char *vendor; // eg: "Bitwig GmbH"
|
||||
const char *url; // eg: "https://bitwig.com"
|
||||
const char *version; // eg: "4.3", see plugin.h for advice on how to format the version
|
||||
|
||||
// Query an extension, returns null if not supported.
|
||||
// The returned pointer is owned by the host and is valid until after the call to plugin->destroy()
|
||||
// It is forbidden to call it before plugin->init().
|
||||
// You can call it within plugin->init() call, and after.
|
||||
// [thread-safe]
|
||||
const void *(CLAP_ABI *get_extension)(const struct clap_host *host, const char *extension_id);
|
||||
|
||||
// Request the host to deactivate and then reactivate the plugin.
|
||||
// The operation may be delayed by the host.
|
||||
// [thread-safe]
|
||||
void(CLAP_ABI *request_restart)(const struct clap_host *host);
|
||||
|
||||
// Request the host to activate and start processing the plugin.
|
||||
// This is useful if you have external IO and need to wake up the plugin from "sleep".
|
||||
// [thread-safe]
|
||||
void(CLAP_ABI *request_process)(const struct clap_host *host);
|
||||
|
||||
// Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread.
|
||||
// This callback should be called as soon as practicable, usually in the host application's next
|
||||
// available main thread time slice. Typically callbacks occur within 33ms / 30hz.
|
||||
// Despite this guidance, plugins should not make assumptions about the exactness of timing for
|
||||
// a main thread callback, but hosts should endeavour to be prompt. For example, in high load
|
||||
// situations the environment may starve the gui/main thread in favor of audio processing,
|
||||
// leading to substantially longer latencies for the callback than the indicative times given
|
||||
// here.
|
||||
// [thread-safe]
|
||||
void(CLAP_ABI *request_callback)(const struct clap_host *host);
|
||||
} clap_host_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
8
third_party/clap/include/clap/id.h
vendored
Normal file
8
third_party/clap/include/clap/id.h
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "private/std.h"
|
||||
#include "private/macros.h"
|
||||
|
||||
typedef uint32_t clap_id;
|
||||
|
||||
static const CLAP_CONSTEXPR clap_id CLAP_INVALID_ID = UINT32_MAX;
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue