clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit df8f16c69ba1c1a15fb105f0c5a2e5b9ac6be742
parent e292447bd0dbb265ef091178bfed9e29617ebb5b
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date:   Mon, 22 Jan 2024 10:30:27 +0100

Merge pull request #371 from free-audio/next

CLAP 1.2.0
Diffstat:
MCMakeLists.txt | 7+++++++
MChangeLog.md | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MREADME.md | 43+++++++++++++++++++++++++++----------------
Aconventions/extension-id.md | 32++++++++++++++++++++++++++++++++
Ainclude/clap/all.h | 12++++++++++++
Minclude/clap/clap.h | 31++++++++++++-------------------
Minclude/clap/entry.h | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Minclude/clap/events.h | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Ainclude/clap/ext/ambisonic.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/clap/ext/audio-ports-activation.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/ext/audio-ports-config.h | 6++++++
Minclude/clap/ext/audio-ports.h | 1-
Ainclude/clap/ext/configurable-audio-ports.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/clap/ext/context-menu.h | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dinclude/clap/ext/draft/ambisonic.h | 63---------------------------------------------------------------
Dinclude/clap/ext/draft/audio-ports-activation.h | 59-----------------------------------------------------------
Dinclude/clap/ext/draft/check-for-update.h | 32--------------------------------
Dinclude/clap/ext/draft/configurable-audio-ports.h | 57---------------------------------------------------------
Dinclude/clap/ext/draft/context-menu.h | 164-------------------------------------------------------------------------------
Dinclude/clap/ext/draft/cv.h | 44--------------------------------------------
Minclude/clap/ext/draft/extensible-audio-ports.h | 2+-
Dinclude/clap/ext/draft/midi-mappings.h | 41-----------------------------------------
Dinclude/clap/ext/draft/param-indication.h | 73-------------------------------------------------------------------------
Dinclude/clap/ext/draft/preset-load.h | 49-------------------------------------------------
Dinclude/clap/ext/draft/remote-controls.h | 79-------------------------------------------------------------------------------
Minclude/clap/ext/draft/resource-directory.h | 2+-
Dinclude/clap/ext/draft/state-context.h | 64----------------------------------------------------------------
Dinclude/clap/ext/draft/surround.h | 83-------------------------------------------------------------------------------
Dinclude/clap/ext/draft/track-info.h | 62--------------------------------------------------------------
Minclude/clap/ext/draft/transport-control.h | 2+-
Minclude/clap/ext/draft/triggers.h | 2+-
Minclude/clap/ext/draft/tuning.h | 2+-
Minclude/clap/ext/latency.h | 3+--
Ainclude/clap/ext/param-indication.h | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/ext/params.h | 2+-
Ainclude/clap/ext/preset-load.h | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/clap/ext/remote-controls.h | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/clap/ext/state-context.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/ext/state.h | 4++++
Ainclude/clap/ext/surround.h | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/clap/ext/track-info.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/ext/voice-info.h | 2+-
Minclude/clap/factory/draft/plugin-invalidation.h | 2+-
Ainclude/clap/factory/draft/plugin-state-converter.h | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dinclude/clap/factory/draft/preset-discovery.h | 327-------------------------------------------------------------------------------
Ainclude/clap/factory/preset-discovery.h | 313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/plugin.h | 15+++++++++------
Ainclude/clap/timestamp.h | 11+++++++++++
Ainclude/clap/universal-plugin-id.h | 26++++++++++++++++++++++++++
Minclude/clap/version.h | 4++--
Msrc/main.c | 2+-
Msrc/main.cc | 2+-
Msrc/plugin-template.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
53 files changed, 1650 insertions(+), 1273 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -50,6 +50,7 @@ add_custom_target(clap-tests) if (${CLAP_BUILD_TESTS}) message(STATUS "Including CLAP tests, compile tests, and versions") + include(CheckIncludeFile) macro(clap_compile_cpp SUFFIX EXT STDC STDCPP) add_executable(clap-compile-${SUFFIX} EXCLUDE_FROM_ALL src/main.${EXT}) @@ -84,11 +85,17 @@ if (${CLAP_BUILD_TESTS}) clap_compile_cpp(cpp17 cc 17 17) clap_compile_cpp(cpp20 cc 17 20) + check_include_file(threads.h CLAP_HAS_THREADS_H) + add_library(clap-plugin-template MODULE EXCLUDE_FROM_ALL src/plugin-template.c) target_link_libraries(clap-plugin-template PRIVATE clap) set_target_properties(clap-plugin-template PROPERTIES C_STANDARD 11) add_dependencies(clap-tests clap-plugin-template) + if(CLAP_HAS_THREADS_H) + target_compile_definitions(clap-plugin-template PRIVATE CLAP_HAS_THREADS_H) + endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") target_link_libraries(clap-plugin-template PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/linux-my_plug.version) target_link_libraries(clap-plugin-template PRIVATE -Wl,-z,defs) diff --git a/ChangeLog.md b/ChangeLog.md @@ -1,3 +1,77 @@ +# Changes in 1.2.0 + +## New conventions + +* [extension-id](conventions/extension-id.md): introduce some rules about extension ID naming. + +## Stabilize extensions + +* `CLAP_EXT_AMBISONIC` +* `CLAP_EXT_AUDIO_PORTS_ACTIVATION` +* `CLAP_EXT_CONFIGURABLE_AUDIO_PORTS` +* `CLAP_EXT_CONTEXT_MENU` +* `CLAP_EXT_PARAM_INDICATION` +* `CLAP_EXT_PRESET_LOAD` +* `CLAP_EXT_REMOTE_CONTROLS` +* `CLAP_EXT_STATE_CONTEXT` +* `CLAP_EXT_SURROUND` +* `CLAP_EXT_TRACK_INFO` + +### Notes regarding extension ID change after draft stabilization + +We changed the extension ID in the process of stabilization which leads to a **break**. + +To mitigate this transition, we've provided compatibility extension IDs which can be used to match and use the latest draft extensions as they are 100% compatible. + +For example, `CLAP_EXT_CONTEXT_MENU` for the stable ID and `CLAP_EXT_CONTEXT_MENU_COMPAT` for the draft ID. + +As you can see in [extension-id](conventions/extension-id.md), we introduced some rules, so this kind of break won't happen again. + +We may decide to remove the `*_COMPAT` IDs in the future once their usage becomes antiquated. + +## Removed draft extensions + +* `CLAP_EXT_CHECK_FOR_UPDATE` wasn't used and it's design needed more thought. +* `CLAP_EXT_MIDI_MAPPING` wasn't used. MIDI2 seems to do it better, and the interface wasn't satisfying. +* `CLAP_EXT_CV` the interface wasn't satisfying. + +## Stabilize factory + +* `CLAP_PRESET_DISCOVERY_FACTORY_ID` + +Note: we kept the last draft factory ID in order to not break plugins already using it. + +## Plugin State Converter + +* Introduction of a new factory which provides a plugin state convertion mechanism. + +## Refactoring + +* `clap_plugin_id_t` was renamed to `clap_universal_plugin_id_t` to make it clear that it can describe more than just a CLAP plugin ID. +* `clap_timestamp_t` was renamed to `clap_timestamp` to be consistent with other types, like e.g. `clap_id`. Also it was moved to a separate header as `CLAP_PRESET_DISCOVERY_FACTORY_ID` was stabilized. + +## Documentation + +* [events.h](include/clap/events.h): Clarify how "Port Channel Key NoteID" matching works +* [events.h](include/clap/events.h): Clarify how `clap_event_note` fields map to MIDI, Host, etc... +* [events.h](include/clap/events.h): Expand clap note expression documentation +* [plugin.h](include/clap/plugin.h): Style cleanup +* [params.h](include/clap/ext/params.h): Fix incorrect function name reference +* [latency.h](include/clap/ext/latency.h): Require the plugin to be activated to get the latency and clarify that the latency can only be fetched when the plugin is activated + +## Plugin Template + +* [plugin-template.c](src/plugin-template.c): implement thread-safe plugin entry init counter + +## Organization + +* `clap.h` no longer includes headers from `ext/draft` or `factory/draft`. Draft extension and factory headers must now be explicitly included, either individually or via the `all.h` header. + +## Other changes + +* [voice-info.h](include/clap/ext/voice-info.h): Make the voice info id `CLAP_CONSTEXPR` like all other ids +* [preset-load.h](include/clap/ext/preset-load.h): Make the preset load id and compat id `CLAP_CONSTEXPR` like all other ids + # Changes in 1.1.10 * [params.h](include/clap/ext/params.h): add `CLAP_PARAM_IS_ENUM` flag. diff --git a/README.md b/README.md @@ -11,7 +11,7 @@ - [Extensions](#extensions) - [Fundamental extensions](#fundamental-extensions) - [Support extensions](#support-extensions) - - [Extra extensions](#extra-extensions) + - [Deeper Host integration](#deeper-host-integration) - [Third-party extensions](#third-party-extensions) - [Adapters](#adapters) - [Resources](#resources) @@ -32,6 +32,7 @@ that is, a plugin binary compiled with CLAP 1.x can be loaded by any other CLAP 1.y. To work with CLAP, include [clap/clap.h](include/clap/clap.h). +To also include the draft extensions, include [clap/all.h](include/clap/all.h). The two most important objects are `clap_host` and `clap_plugin`. @@ -81,34 +82,44 @@ You can create your own extensions and share them. Make sure that the extension This is a list of the extensions that you most likely want to implement and use to get a basic plugin experience: -- [log](include/clap/ext/log.h), lets the host aggregate plugin logs -- [thread-check](include/clap/ext/thread-check.h), check which thread you are currently on, useful for correctness validation -- [audio-ports](include/clap/ext/audio-ports.h), define the audio ports -- [note-ports](include/clap/ext/note-ports.h), define the note ports +- [state](include/clap/ext/state.h), save and load the plugin state + - [state-context](include/clap/ext/state-context.h), same as state but with additional context info (preset, duplicate, project) + - [resource-directory](include/clap/ext/draft/resource-directory.h), host provided folder for the plugin to save extra resource like multi-samples, ... (draft) - [params](include/clap/ext/params.h), parameters management -- [latency](include/clap/ext/latency.h), report the plugin latency +- [note-ports](include/clap/ext/note-ports.h), define the note ports +- [audio-ports](include/clap/ext/audio-ports.h), define the audio ports + - [surround](include/clap/ext/surround.h), inspect surround channel mapping + - [ambisonic](include/clap/ext/draft/ambisonic.h), inspect ambisonic channel mapping + - [configurable-audio-ports](include/clap/ext/configurable-audio-ports.h), request the plugin to apply a given configuration + - [audio-ports-config](include/clap/ext/audio-ports-config.h), simple list of pre-defined audio ports configurations, meant to be exposed to the user + - [audio-ports-activation](include/clap/ext/audio-ports-activation.h), activate and deactivate a given audio port + - [extensible-audio-ports](include/clap/ext/draft/extensible-audio-ports.h), let the host add audio ports to the plugin, this is useful for dynamic number of audio inputs (draft) - [render](include/clap/ext/render.h), renders realtime or offline +- [latency](include/clap/ext/latency.h), report the plugin latency - [tail](include/clap/ext/tail.h), processing tail length -- [state](include/clap/ext/state.h), save and load the plugin state - [gui](include/clap/ext/gui.h), generic gui controller +- [voice-info](include/clap/ext/voice-info.h), let the host know how many voices the plugin has, this is important for polyphonic modulations +- [track-info](include/clap/ext/track-info.h), give some info to the plugin about the track it belongs to +- [tuning](include/clap/ext/draft/tuning.h), host provided microtuning (draft) +- [triggers](include/clap/ext/draft/triggers.h), plugin's triggers, similar to parameters but stateless ## Support extensions +- [thread-check](include/clap/ext/thread-check.h), check which thread you are currently on, useful for correctness validation - [thread-pool](include/clap/ext/thread-pool.h), use the host thread pool +- [log](include/clap/ext/log.h), lets the host aggregate plugin logs - [timer-support](include/clap/ext/timer-support.h), lets the plugin register timer handlers - [posix-fd-support](include/clap/ext/posix-fd-support.h), lets the plugin register I/O handlers -## Extra extensions +## Deeper Host integration +- [remote-controls](include/clap/ext/remote-controls.h), bank of controls that can be mapped on a controlles with 8 knobs +- [preset-discovery](include/clap/factory/preset-discovery.h), let the host index the plugin's preset in their native file format +- [preset-load](include/clap/ext/preset-load.h), let the host ask the plugin to load a preset +- [param-indication](include/clap/ext/param-indication.h), let the plugin know when a physical control is mapped to a parameter and if there is automation data - [note-name](include/clap/ext/note-name.h), give a name to notes, useful for drum machines -- [tuning](include/clap/ext/draft/tuning.h), host provided microtuning -- [track-info](include/clap/ext/draft/track-info.h) -- [quick-controls](include/clap/ext/draft/quick-controls.h), bank of controls that can be mapped on a controlles with 8 knobs -- [file-reference](include/clap/ext/draft/file-reference.h), let the host know about the plugin's file reference, and perform "Collect & Save" -- [check-for-update](include/clap/ext/draft/check-for-update.h), check if there is a new version of a plugin -- [audio-ports-config](include/clap/ext/audio-ports-config.h), simple list of possible configurations -- [surround](include/clap/ext/draft/surround.h), inspect surround channel mapping -- [ambisonic](include/clap/ext/draft/ambisonic.h), inspect ambisonic channel mapping +- [transport-control](include/clap/ext/draft/transport-control.h), let the plugin control the host's transport (draft) +- [context-menu](include/clap/ext/context-menu.h), exchange context menu entries between host and plugin, let the plugin ask the host to popup its own context menu ## Third-party extensions diff --git a/conventions/extension-id.md b/conventions/extension-id.md @@ -0,0 +1,32 @@ +# Extension ID + +## Naming + +The extension shall be named in the form: `clap.$NAME/$REV`. +Where: +- `$NAME` is the name of the exension. +- `$REV` is the revision of the extension. This is an integer that is incremented for each iteration. It should start at 1. + +For extensions made by third-parties and not officially published by the CLAP project, please use the following form: `$REVERSE_URI.$NAME/$REV`. +Where: +- `$REVERSE_URI` would be something like `com.bitwig`. + +## Draft + +An extension is considered a draft extension if it is in the [draft](../include/clap/ext/draft/) folder. +Make sure to also include it in [all.h](../include/clap/all.h). + +When the extension is migrating from draft to stable, its extension ID must not change. +Move its inclusion from [all.h](../include/clap/all.h) into [clap.h](../include/clap/clap.h). + +All extensions must go though the draft phase first. + +## For factory ID + +Everything about the extension id symmetrically applies to factory id. + +## History + +Before version 1.2.0 when this document was written, existing extensions didn't honor these rules. +We wanted to stabilize some draft extensions without breaking compatibility, yet their extension IDs contained the string `draft`. +While these strings weren't user-facing, we still wanted to remove them, so we updated the extension IDs according to this document and introduced IDs with `_COMPAT` suffixes to provide backward compatibility with the draft versions. diff --git a/include/clap/all.h b/include/clap/all.h @@ -0,0 +1,12 @@ +#pragma once + +#include "clap.h" + +#include "factory/draft/plugin-invalidation.h" +#include "factory/draft/plugin-state-converter.h" + +#include "ext/draft/extensible-audio-ports.h" +#include "ext/draft/resource-directory.h" +#include "ext/draft/transport-control.h" +#include "ext/draft/triggers.h" +#include "ext/draft/tuning.h" diff --git a/include/clap/clap.h b/include/clap/clap.h @@ -28,44 +28,37 @@ #include "entry.h" #include "factory/plugin-factory.h" -#include "factory/draft/plugin-invalidation.h" -#include "factory/draft/preset-discovery.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" - -#include "ext/draft/ambisonic.h" -#include "ext/draft/audio-ports-activation.h" -#include "ext/draft/context-menu.h" -#include "ext/draft/cv.h" -#include "ext/draft/midi-mappings.h" -#include "ext/draft/param-indication.h" -#include "ext/draft/preset-load.h" -#include "ext/draft/remote-controls.h" -#include "ext/draft/resource-directory.h" -#include "ext/draft/state-context.h" -#include "ext/draft/surround.h" -#include "ext/draft/track-info.h" -#include "ext/draft/triggers.h" -#include "ext/draft/tuning.h" -#include "ext/draft/configurable-audio-ports.h" -#include "ext/draft/extensible-audio-ports.h" diff --git a/include/clap/entry.h b/include/clap/entry.h @@ -31,34 +31,100 @@ extern "C" { // Each directory should be recursively searched for files and/or bundles as appropriate in your OS // ending with the extension `.clap`. // -// Every method must be thread-safe. +// 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 patterh +// 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 - // This function must be called first, and can only be called once. + // 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 interface in this call. - // It is forbidden to perform user interaction in this call. + // 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. // - // If init() returns false, then the host must not call deinit() nor any other clap - // related symbols from the DSO. + // 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); - // No more calls into the DSO must be made after calling deinit(). + // 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; diff --git a/include/clap/events.h b/include/clap/events.h @@ -117,19 +117,62 @@ enum { }; // 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 choke or end events: // - the velocity is ignored. -// - key and channel are used to match active notes, a value of -1 matches all. +// - 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; // -1 if unspecified, otherwise >=0 - int16_t port_index; - int16_t channel; // 0..15 - int16_t key; // 0..127 + 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, @@ -137,7 +180,9 @@ enum { // pan, 0 left, 0.5 center, 1 right CLAP_NOTE_EXPRESSION_PAN = 1, - // relative tuning in semitone, from -120 to +120 + // 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 @@ -153,7 +198,8 @@ typedef struct clap_event_note_expression { clap_note_expression expression_id; - // target a specific note_id, port, key and channel, -1 for global + // 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; @@ -169,7 +215,8 @@ typedef struct clap_event_param_value { 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, -1 for global + // 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; @@ -185,7 +232,8 @@ typedef struct clap_event_param_mod { 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, -1 for global + // 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; diff --git a/include/clap/ext/ambisonic.h b/include/clap/ext/ambisonic.h @@ -0,0 +1,66 @@ +#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 + // + // config_id: the configuration id, see clap_plugin_audio_ports_config. + // If config_id is CLAP_INVALID_ID, then this function queries the current port info. + // [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 diff --git a/include/clap/ext/audio-ports-activation.h b/include/clap/ext/audio-ports-activation.h @@ -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 diff --git a/include/clap/ext/audio-ports-config.h b/include/clap/ext/audio-ports-config.h @@ -26,7 +26,13 @@ /// 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 diff --git a/include/clap/ext/audio-ports.h b/include/clap/ext/audio-ports.h @@ -54,7 +54,6 @@ typedef struct clap_audio_port_info { // - CLAP_PORT_STEREO // - CLAP_PORT_SURROUND (defined in the surround extension) // - CLAP_PORT_AMBISONIC (defined in the ambisonic extension) - // - CLAP_PORT_CV (defined in the cv extension) // // An extension can provide its own port type and way to inspect the channels. const char *port_type; diff --git a/include/clap/ext/configurable-audio-ports.h b/include/clap/ext/configurable-audio-ports.h @@ -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 diff --git a/include/clap/ext/context-menu.h b/include/clap/ext/context-menu.h @@ -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 diff --git a/include/clap/ext/draft/ambisonic.h b/include/clap/ext/draft/ambisonic.h @@ -1,63 +0,0 @@ -#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.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 - // - // config_id: the configuration id, see clap_plugin_audio_ports_config. - // If config_id is CLAP_INVALID_ID, then this function queries the current port info. - // [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 diff --git a/include/clap/ext/draft/audio-ports-activation.h b/include/clap/ext/draft/audio-ports-activation.h @@ -1,59 +0,0 @@ -#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/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 diff --git a/include/clap/ext/draft/check-for-update.h b/include/clap/ext/draft/check-for-update.h @@ -1,32 +0,0 @@ -#pragma once - -#include "../../plugin.h" - -static CLAP_CONSTEXPR const char CLAP_EXT_CHECK_FOR_UPDATE[] = "clap.check_for_update.draft/0"; - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct clap_check_for_update_info { - const char *version; // latest version - const char *release_date; // YYYY-MM-DD - const char *url; // url to a download page which the user can visit - - bool is_preview; // true if this version is a preview release -} clap_check_for_update_info_t; - -typedef struct clap_plugin_check_for_update { - // [main-thread] - void(CLAP_ABI *check)(const clap_plugin_t *plugin, bool include_preview); -} clap_plugin_check_for_update_t; - -typedef struct clap_host_check_for_update { - // [main-thread] - void(CLAP_ABI *on_new_version)(const clap_host_t *host, - const clap_check_for_update_info_t *update_info); -} clap_host_check_for_update_t; - -#ifdef __cplusplus -} -#endif diff --git a/include/clap/ext/draft/configurable-audio-ports.h b/include/clap/ext/draft/configurable-audio-ports.h @@ -1,57 +0,0 @@ -#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.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 diff --git a/include/clap/ext/draft/context-menu.h b/include/clap/ext/draft/context-menu.h @@ -1,164 +0,0 @@ -#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.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, - // TODO: kind trigger once the trigger ext is marked as stable -}; - -// 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 diff --git a/include/clap/ext/draft/cv.h b/include/clap/ext/draft/cv.h @@ -1,44 +0,0 @@ -#pragma once - -#include "../../plugin.h" - -// This extension can be used to specify the cv channel type used by the plugin. -// Work in progress, suggestions are welcome - -static CLAP_CONSTEXPR const char CLAP_EXT_CV[] = "clap.cv.draft/0"; -static CLAP_CONSTEXPR const char CLAP_PORT_CV[] = "cv"; - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - // TODO: standardize values? - CLAP_CV_VALUE = 0, - CLAP_CV_GATE = 1, - CLAP_CV_PITCH = 2, -}; - -// TODO: maybe we want a channel_info instead, where we could have more details about the supported -// ranges? - -typedef struct clap_plugin_cv { - // Returns true on success. - // [main-thread] - bool(CLAP_ABI *get_channel_type)(const clap_plugin_t *plugin, - bool is_input, - uint32_t port_index, - uint32_t channel_index, - uint32_t *channel_type); -} clap_plugin_cv_t; - -typedef struct clap_host_cv { - // Informs the host that the channels type have changed. - // The channels type can only change when the plugin is de-activated. - // [main-thread,!active] - void(CLAP_ABI *changed)(const clap_host_t *host); -} clap_host_cv_t; - -#ifdef __cplusplus -} -#endif diff --git a/include/clap/ext/draft/extensible-audio-ports.h b/include/clap/ext/draft/extensible-audio-ports.h @@ -8,7 +8,7 @@ extern "C" { // 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.draft0"; + "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. diff --git a/include/clap/ext/draft/midi-mappings.h b/include/clap/ext/draft/midi-mappings.h @@ -1,41 +0,0 @@ -#pragma once - -#include "../../plugin.h" - -static CLAP_CONSTEXPR const char CLAP_EXT_MIDI_MAPPINGS[] = "clap.midi-mappings.draft/0"; - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - CLAP_MIDI_MAPPING_CC7, - CLAP_MIDI_MAPPING_CC14, - CLAP_MIDI_MAPPING_RPN, - CLAP_MIDI_MAPPING_NRPN, -}; -typedef int32_t clap_midi_mapping_type; - -typedef struct clap_midi_mapping { - int32_t channel; - int32_t number; - clap_id param_id; -} clap_midi_mapping_t; - -typedef struct clap_plugin_midi_mappings { - // [main-thread] - uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin); - - // Returns true on success and stores the result into mapping. - // [main-thread] - bool(CLAP_ABI *get)(const clap_plugin_t *plugin, uint32_t index, clap_midi_mapping_t *mapping); -} clap_plugin_midi_mappings_t; - -typedef struct clap_host_midi_mappings { - // [main-thread] - void(CLAP_ABI *changed)(const clap_host_t *host); -} clap_host_midi_mappings_t; - -#ifdef __cplusplus -} -#endif diff --git a/include/clap/ext/draft/param-indication.h b/include/clap/ext/draft/param-indication.h @@ -1,73 +0,0 @@ -#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.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 diff --git a/include/clap/ext/draft/preset-load.h b/include/clap/ext/draft/preset-load.h @@ -1,49 +0,0 @@ -#pragma once - -#include "../../plugin.h" - -static const char CLAP_EXT_PRESET_LOAD[] = "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.load() 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 diff --git a/include/clap/ext/draft/remote-controls.h b/include/clap/ext/draft/remote-controls.h @@ -1,79 +0,0 @@ -#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.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 diff --git a/include/clap/ext/draft/resource-directory.h b/include/clap/ext/draft/resource-directory.h @@ -2,7 +2,7 @@ #include "../../plugin.h" -static CLAP_CONSTEXPR const char CLAP_EXT_RESOURCE_DIRECTORY[] = "clap.resource-directory.draft/0"; +static CLAP_CONSTEXPR const char CLAP_EXT_RESOURCE_DIRECTORY[] = "clap.resource-directory/1"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/ext/draft/state-context.h b/include/clap/ext/draft/state-context.h @@ -1,64 +0,0 @@ -#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. -/// -/// 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 the plugin implements CLAP_EXT_STATE_CONTEXT then it is mandatory to also implement -/// CLAP_EXT_STATE. - -#ifdef __cplusplus -extern "C" { -#endif - -static CLAP_CONSTEXPR const char CLAP_EXT_STATE_CONTEXT[] = "clap.state-context.draft/1"; - -enum clap_plugin_state_context_type { - // suitable for duplicating a plugin instance - CLAP_STATE_CONTEXT_FOR_DUPLICATE = 1, - - // suitable for loading a state as a preset - CLAP_STATE_CONTEXT_FOR_PRESET = 2, -}; - -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 diff --git a/include/clap/ext/draft/surround.h b/include/clap/ext/draft/surround.h @@ -1,83 +0,0 @@ -#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 calls clap_plugin_surround->changed() -// 3. plugin calls clap_host_surround->get_preferred_channel_map() -// 4. plugin eventually calls clap_host_surround->changed() -// 5. host calls clap_plugin_surround->get_channel_map() if changed -// 6. 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.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 Left - CLAP_SURROUND_BR = 5, // Back Right - CLAP_SURROUND_FLC = 6, // Front Left of Center - CLAP_SURROUND_FRC = 7, // Front Right of Center - CLAP_SURROUND_BC = 8, // Back Center - CLAP_SURROUND_SL = 9, // Side Left - CLAP_SURROUND_SR = 10, // Side Right - CLAP_SURROUND_TC = 11, // Top Center - CLAP_SURROUND_TFL = 12, // Front Left Height - CLAP_SURROUND_TFC = 13, // Front Center Height - CLAP_SURROUND_TFR = 14, // Front Right Height - CLAP_SURROUND_TBL = 15, // Rear Left Height - CLAP_SURROUND_TBC = 16, // Rear Center Height - CLAP_SURROUND_TBR = 17, // Rear Right Height -}; - -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 diff --git a/include/clap/ext/draft/track-info.h b/include/clap/ext/draft/track-info.h @@ -1,62 +0,0 @@ -#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.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 diff --git a/include/clap/ext/draft/transport-control.h b/include/clap/ext/draft/transport-control.h @@ -6,7 +6,7 @@ // 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.draft/0"; +static CLAP_CONSTEXPR const char CLAP_EXT_TRANSPORT_CONTROL[] = "clap.transport-control/1"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/ext/draft/triggers.h b/include/clap/ext/draft/triggers.h @@ -4,7 +4,7 @@ #include "../../events.h" #include "../../string-sizes.h" -static CLAP_CONSTEXPR const char CLAP_EXT_TRIGGERS[] = "clap.triggers.draft/0"; +static CLAP_CONSTEXPR const char CLAP_EXT_TRIGGERS[] = "clap.triggers/1"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/ext/draft/tuning.h b/include/clap/ext/draft/tuning.h @@ -4,7 +4,7 @@ #include "../../events.h" #include "../../string-sizes.h" -static CLAP_CONSTEXPR const char CLAP_EXT_TUNING[] = "clap.tuning.draft/2"; +static CLAP_CONSTEXPR const char CLAP_EXT_TUNING[] = "clap.tuning/2"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/ext/latency.h b/include/clap/ext/latency.h @@ -8,10 +8,9 @@ static CLAP_CONSTEXPR const char CLAP_EXT_LATENCY[] = "clap.latency"; extern "C" { #endif -// The audio ports scan has to be done while the plugin is deactivated. typedef struct clap_plugin_latency { // Returns the plugin latency in samples. - // [main-thread] + // [main-thread & active] uint32_t(CLAP_ABI *get)(const clap_plugin_t *plugin); } clap_plugin_latency_t; diff --git a/include/clap/ext/param-indication.h b/include/clap/ext/param-indication.h @@ -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 diff --git a/include/clap/ext/params.h b/include/clap/ext/params.h @@ -12,7 +12,7 @@ /// 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.value(). +/// @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() diff --git a/include/clap/ext/preset-load.h b/include/clap/ext/preset-load.h @@ -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.load() 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 diff --git a/include/clap/ext/remote-controls.h b/include/clap/ext/remote-controls.h @@ -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 diff --git a/include/clap/ext/state-context.h b/include/clap/ext/state-context.h @@ -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 diff --git a/include/clap/ext/state.h b/include/clap/ext/state.h @@ -10,6 +10,10 @@ /// 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"; diff --git a/include/clap/ext/surround.h b/include/clap/ext/surround.h @@ -0,0 +1,87 @@ +#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 calls clap_plugin_surround->changed() +// 3. plugin calls clap_host_surround->get_preferred_channel_map() +// 4. plugin eventually calls clap_host_surround->changed() +// 5. host calls clap_plugin_surround->get_channel_map() if changed +// 6. 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 Left + CLAP_SURROUND_BR = 5, // Back Right + CLAP_SURROUND_FLC = 6, // Front Left of Center + CLAP_SURROUND_FRC = 7, // Front Right of Center + CLAP_SURROUND_BC = 8, // Back Center + CLAP_SURROUND_SL = 9, // Side Left + CLAP_SURROUND_SR = 10, // Side Right + CLAP_SURROUND_TC = 11, // Top Center + CLAP_SURROUND_TFL = 12, // Front Left Height + CLAP_SURROUND_TFC = 13, // Front Center Height + CLAP_SURROUND_TFR = 14, // Front Right Height + CLAP_SURROUND_TBL = 15, // Rear Left Height + CLAP_SURROUND_TBC = 16, // Rear Center Height + CLAP_SURROUND_TBR = 17, // Rear Right Height +}; + +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 diff --git a/include/clap/ext/track-info.h b/include/clap/ext/track-info.h @@ -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 diff --git a/include/clap/ext/voice-info.h b/include/clap/ext/voice-info.h @@ -9,7 +9,7 @@ // - 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 const char CLAP_EXT_VOICE_INFO[] = "clap.voice-info"; +static CLAP_CONSTEXPR const char CLAP_EXT_VOICE_INFO[] = "clap.voice-info"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/factory/draft/plugin-invalidation.h b/include/clap/factory/draft/plugin-invalidation.h @@ -6,7 +6,7 @@ // 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/draft0"; + "clap.plugin-invalidation-factory/1"; #ifdef __cplusplus extern "C" { diff --git a/include/clap/factory/draft/plugin-state-converter.h b/include/clap/factory/draft/plugin-state-converter.h @@ -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 (*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 (*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 (*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 (*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 (*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 *(*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 *(*create)( + const struct clap_plugin_state_converter_factory *factory, const char *converter_id); +} clap_plugin_state_converter_factory_t; + +#ifdef __cplusplus +} +#endif diff --git a/include/clap/factory/draft/preset-discovery.h b/include/clap/factory/draft/preset-discovery.h @@ -1,327 +0,0 @@ -/* - 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 "../../version.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/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, -}; - -// TODO: move clap_timestamp_t, CLAP_TIMESTAMP_UNKNOWN and clap_plugin_id_t to parent files once we -// settle with preset discovery - -// This type defines a timestamp: the number of seconds since UNIX EPOCH. -// See C's time_t time(time_t *). -typedef uint64_t clap_timestamp_t; - -// Value for unknown timestamp. -static const clap_timestamp_t CLAP_TIMESTAMP_UNKNOWN = 0; - -// Pair of plugin ABI and plugin identifier -typedef struct clap_plugin_id { - // The plugin ABI name, in lowercase. - // eg: "clap" - const char *abi; - - // The plugin ID, for example "com.u-he.Diva". - // If the ABI rely upon binary plugin ids, then they shall be hex encoded (lower case). - const char *id; -} clap_plugin_id_t; - -// 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_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_t creation_time, - clap_timestamp_t 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_t 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 diff --git a/include/clap/factory/preset-discovery.h b/include/clap/factory/preset-discovery.h @@ -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 diff --git a/include/clap/plugin.h b/include/clap/plugin.h @@ -46,6 +46,9 @@ typedef struct clap_plugin { // Must be called after creating the plugin. // If init returns false, the host must destroy the plugin instance. // If init returns true, then the plugin is initialized and in the deactivated state. + // Unlike in `plugin-factory::create_plugin`, in init you have complete access to the host + // and host extensions, so clap related setup activities should be done here rather than in + // create_plugin. // [main-thread] bool(CLAP_ABI *init)(const struct clap_plugin *plugin); @@ -60,21 +63,21 @@ typedef struct clap_plugin { // the [min, max] range, which is bounded by [1, INT32_MAX]. // Once activated the latency and port configuration must remain constant, until deactivation. // Returns true on success. - // [main-thread & !active_state] + // [main-thread & !active] bool(CLAP_ABI *activate)(const struct clap_plugin *plugin, double sample_rate, uint32_t min_frames_count, uint32_t max_frames_count); - // [main-thread & active_state] + // [main-thread & active] void(CLAP_ABI *deactivate)(const struct clap_plugin *plugin); // Call start processing before processing. // Returns true on success. - // [audio-thread & active_state & !processing_state] + // [audio-thread & active & !processing] bool(CLAP_ABI *start_processing)(const struct clap_plugin *plugin); // Call stop processing before sending the plugin to sleep. - // [audio-thread & active_state & processing_state] + // [audio-thread & active & processing] void(CLAP_ABI *stop_processing)(const struct clap_plugin *plugin); // - Clears all buffers, performs a full reset of the processing state (filters, oscillators, @@ -82,13 +85,13 @@ typedef struct clap_plugin { // - The parameter's value remain unchanged. // - clap_process.steady_time may jump backward. // - // [audio-thread & active_state] + // [audio-thread & active] void(CLAP_ABI *reset)(const struct clap_plugin *plugin); // process audio, events, ... // All the pointers coming from clap_process_t and its nested attributes, // are valid until process() returns. - // [audio-thread & active_state & processing_state] + // [audio-thread & active & processing] clap_process_status(CLAP_ABI *process)(const struct clap_plugin *plugin, const clap_process_t *process); diff --git a/include/clap/timestamp.h b/include/clap/timestamp.h @@ -0,0 +1,11 @@ +#pragma once + +#include "private/std.h" +#include "private/macros.h" + +// This type defines a timestamp: the number of seconds since UNIX EPOCH. +// See C's time_t time(time_t *). +typedef uint64_t clap_timestamp; + +// Value for unknown timestamp. +static const CLAP_CONSTEXPR clap_timestamp CLAP_TIMESTAMP_UNKNOWN = 0; diff --git a/include/clap/universal-plugin-id.h b/include/clap/universal-plugin-id.h @@ -0,0 +1,26 @@ +#pragma once + +// Pair of plugin ABI and plugin identifier. +// +// If you want to represent other formats please send us an update to the comment with the +// name of the abi and the representation of the id. +typedef struct clap_universal_plugin_id { + // The plugin ABI name, in lowercase and null-terminated. + // eg: "clap", "vst3", "vst2", "au", ... + const char *abi; + + // The plugin ID, null-terminated and formatted as follows: + // + // CLAP: use the plugin id + // eg: "com.u-he.diva" + // + // AU: format the string like "type:subt:manu" + // eg: "aumu:SgXT:VmbA" + // + // VST2: print the id as a signed 32-bits integer + // eg: "-4382976" + // + // VST3: print the id as a standard UUID + // eg: "123e4567-e89b-12d3-a456-426614174000" + const char *id; +} clap_universal_plugin_id_t; diff --git a/include/clap/version.h b/include/clap/version.h @@ -21,8 +21,8 @@ typedef struct clap_version { #endif #define CLAP_VERSION_MAJOR 1 -#define CLAP_VERSION_MINOR 1 -#define CLAP_VERSION_REVISION 10 +#define CLAP_VERSION_MINOR 2 +#define CLAP_VERSION_REVISION 0 #define CLAP_VERSION_INIT \ { (uint32_t)CLAP_VERSION_MAJOR, (uint32_t)CLAP_VERSION_MINOR, (uint32_t)CLAP_VERSION_REVISION } diff --git a/src/main.c b/src/main.c @@ -1,4 +1,4 @@ -#include <clap/clap.h> +#include <clap/all.h> // The purpose of this file is to check that all headers compile int main(int argc, char **argv) { diff --git a/src/main.cc b/src/main.cc @@ -1,4 +1,4 @@ -#include <clap/clap.h> +#include <clap/all.h> // The purpose of this file is to check that all headers compile diff --git a/src/plugin-template.c b/src/plugin-template.c @@ -6,6 +6,12 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <assert.h> + +#if __STDC_VERSION__ >= 201112L && !defined (__STDC_NO_THREADS__) && defined (CLAP_HAS_THREADS_H) +# define CLAP_HAS_THREAD +# include <threads.h> +#endif #include <clap/clap.h> @@ -357,15 +363,82 @@ static const clap_plugin_factory_t s_plugin_factory = { //////////////// static bool entry_init(const char *plugin_path) { - // called only once, and very first + // perform the plugin initialization return true; } static void entry_deinit(void) { - // called before unloading the DSO + // perform the plugin de-initialization +} + +#ifdef CLAP_HAS_THREAD +static mtx_t g_entry_lock; +static once_flag g_entry_once = ONCE_FLAG_INIT; +#endif + +static int g_entry_init_counter = 0; + +#ifdef CLAP_HAS_THREAD +// Initializes the necessary mutex for the entry guard +static void entry_init_guard_init(void) { + mtx_init(&g_entry_lock, mtx_plain); +} +#endif + +// Thread safe init counter +static bool entry_init_guard(const char *plugin_path) { +#ifdef CLAP_HAS_THREAD + call_once(&g_entry_once, entry_init_guard_init); + + mtx_lock(&g_entry_lock); +#endif + + const int cnt = ++g_entry_init_counter; + assert(cnt > 0); + + bool succeed = true; + if (cnt == 1) { + succeed = entry_init(plugin_path); + if (!succeed) + g_entry_init_counter = 0; + } + +#ifdef CLAP_HAS_THREAD + mtx_unlock(&g_entry_lock); +#endif + + return succeed; +} + +// Thread safe deinit counter +static void entry_deinit_guard(void) { +#ifdef CLAP_HAS_THREAD + call_once(&g_entry_once, entry_init_guard_init); + + mtx_lock(&g_entry_lock); +#endif + + const int cnt = --g_entry_init_counter; + assert(cnt > 0); + + bool succeed = true; + if (cnt == 0) + entry_deinit(); + +#ifdef CLAP_HAS_THREAD + mtx_unlock(&g_entry_lock); +#endif } static const void *entry_get_factory(const char *factory_id) { +#ifdef CLAP_HAS_THREAD + call_once(&g_entry_once, entry_init_guard_init); +#endif + + assert(g_entry_init_counter > 0); + if (g_entry_init_counter <= 0) + return NULL; + if (!strcmp(factory_id, CLAP_PLUGIN_FACTORY_ID)) return &s_plugin_factory; return NULL; @@ -374,7 +447,7 @@ static const void *entry_get_factory(const char *factory_id) { // This symbol will be resolved by the host CLAP_EXPORT const clap_plugin_entry_t clap_entry = { .clap_version = CLAP_VERSION_INIT, - .init = entry_init, - .deinit = entry_deinit, + .init = entry_init_guard, + .deinit = entry_deinit_guard, .get_factory = entry_get_factory, };