commit e3f2bf9c9d02cce33e6c9b1a3b1dd3e28105de9c
parent 14251f8f99445e956344c9dbe420582b5bee3b08
Author: Russell McClellan <russell.mcclellan@gmail.com>
Date: Fri, 10 Mar 2023 10:07:26 -0500
Merge remote-tracking branch 'origin/main' into gui-threading-clarification
Diffstat:
27 files changed, 729 insertions(+), 186 deletions(-)
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
@@ -10,7 +10,7 @@
# described by the vcpkg.json manifest file. It will be a no-op if those are restored from cache.
# - Finally builds the sources with Ninja.
name: build
-on: [push, workflow_dispatch]
+on: [push, pull_request, workflow_dispatch]
jobs:
VCPKG:
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -3,11 +3,11 @@ enable_testing()
# Extract the version from header file
file(READ "include/clap/version.h" clap_version_header)
-string(REGEX MATCH "CLAP_VERSION_MAJOR \\(\\(uint32_t\\)([0-9]+)\\)" _ ${clap_version_header})
+string(REGEX MATCH "CLAP_VERSION_MAJOR ([0-9]+)" _ ${clap_version_header})
set(CLAP_VERSION_MAJOR ${CMAKE_MATCH_1})
-string(REGEX MATCH "CLAP_VERSION_MINOR \\(\\(uint32_t\\)([0-9]+)\\)" _ ${clap_version_header})
+string(REGEX MATCH "CLAP_VERSION_MINOR ([0-9]+)" _ ${clap_version_header})
set(CLAP_VERSION_MINOR ${CMAKE_MATCH_1})
-string(REGEX MATCH "CLAP_VERSION_REVISION \\(\\(uint32_t\\)([0-9]+)\\)" _ ${clap_version_header})
+string(REGEX MATCH "CLAP_VERSION_REVISION ([0-9]+)" _ ${clap_version_header})
set(CLAP_VERSION_REVISION ${CMAKE_MATCH_1})
message(STATUS "CLAP version: ${CLAP_VERSION_MAJOR}.${CLAP_VERSION_MINOR}.${CLAP_VERSION_REVISION}")
@@ -72,13 +72,18 @@ if (${CLAP_BUILD_TESTS})
clap_compile_cpp(c11 c 11 11)
clap_compile_cpp(cpp11 cc 11 11)
clap_compile_cpp(cpp14 cc 11 14)
- clap_compile_cpp(c17 c 17 17)
+ if(${CMAKE_VERSION} VERSION_LESS "3.21")
+ message(STATUS "Skipping C17 tests due to older CMAKE_VERSION ${CMAKE_VERSION}")
+ else()
+ clap_compile_cpp(c17 c 17 17)
+ endif()
clap_compile_cpp(cpp17 cc 17 17)
clap_compile_cpp(cpp20 cc 17 20)
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(CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_link_libraries(clap-plugin-template PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/linux-my_plug.version)
diff --git a/ChangeLog.md b/ChangeLog.md
@@ -1,3 +1,44 @@
+# Changes in 1.1.7
+
+* Add a [factory](include/clap/factory) folder for better organization and move our factories there
+* [params.h](include/clap/ext/params.h): fix typos
+* CMake: disable C17 targets for CMake < 3.21
+* [plugin-features.h](include/clap/plugin-features.h): adds `note-detector` category for plugins which converts audio to notes
+
+## Draft extensions
+
+* [context-menu.h](include/clap/ext/draft/context-menu.h): add "title" menu entry
+* [preset-load.h](include/clap/ext/draft/preset-load.h): load from URI instead of path, making the extension more powerful
+* [remote-controls.h](include/clap/ext/draft/remote-controls.h): distinguish between device pages and preset pages
+* [audio-ports-activation.h](include/clap/ext/draft/audio-ports-activation.h): `set_active()` now returns bool instead of void, this helps catching problems earlier especially with invalid arguments
+* [audio-ports-config.h](include/clap/ext/audio-ports-config.h): add new draft extension: `clap_plugin_audio_ports_config_info` which lets the host query detailed port information in a given configuration.
+* [surround.h](include/clap/ext/draft/surround.h): add `config_id` parameter when fetching port info
+* [ambisonic.h](include/clap/ext/draft/ambisonic.h): add `config_id` parameter when fetching port info
+
+## Draft factories
+
+* [preset-discovery.h](include/clap/factory/draft/preset-discovery.h): new factory which allows the host to index the plugin presets which are stored on disk.
+
+# Changes in 1.1.6
+
+* [version.h](include/clap/version.h) `CLAP_VERSION_LT` was backwards (comparing current with arg
+ vs arg with current). Correct and enhance tests.
+
+# Changes in 1.1.5
+
+* [plugin.h](include/clap/plugin.h): clarify plugin state after init()
+* [plugin.h](include/clap/plugin.h): clarify when it is allowed to call get_extension()
+* [plugin.h](include/clap/plugin.h): advice for plugin id and version strings
+* [host.h](include/clap/host.h): clarify when it is allowed to call get_extension()
+* [CMakeLists.txt](CMakeLists.txt): the target `clap-test` now includes `clap-plugin-template`
+* Remove UTF-8 BOM from a few files
+* [plugin-template.c](src/plugin-template.c): add state impl and some comments
+* [audio-ports-activation.h](include/clap/ext/draft/audio-ports-activation.h): improved documentation
+* [version.h](include/clap/version.h):
+ * Add a CLAP_VERSION_GE(maj,min,rev), _EQ and _LT macro.
+ * Remove the uint32_t cast from CLAP_VERSION_MAJOR, _MINOR, and _REVISION macro, and introduce it to the CLAP_VERSION_INIT macro.
+ * If you rely on these macros being a uint32_t or parse this header using external software, this may be a breaking change.
+
# Changes in 1.1.4
* CMake: update some targets to link against `clap` instead of `clap-core`
diff --git a/README.md b/README.md
@@ -37,7 +37,7 @@ The entry point is declared in [entry.h](include/clap/entry.h).
## Extensions
-Most features comes from extensions, which are in fact C interfaces.
+Most features come from extensions, which are in fact C interfaces.
```C
// host extension
const clap_host_log *log = host->extension(host, CLAP_EXT_LOG);
diff --git a/include/clap/clap.h b/include/clap/clap.h
@@ -1,4 +1,4 @@
-/*
+/*
* CLAP - CLever Audio Plugin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -26,11 +26,13 @@
#pragma once
#include "entry.h"
-#include "plugin-factory.h"
-#include "plugin-invalidation.h"
-#include "plugin-features.h"
+
+#include "factory/plugin-factory.h"
+#include "factory/draft/plugin-invalidation.h"
+#include "factory/draft/preset-discovery.h"
#include "plugin.h"
+#include "plugin-features.h"
#include "host.h"
#include "ext/audio-ports-config.h"
diff --git a/include/clap/entry.h b/include/clap/entry.h
@@ -53,7 +53,7 @@ typedef struct clap_plugin_entry {
// No more calls into the DSO must be made after calling deinit().
void(CLAP_ABI *deinit)(void);
- // Get the pointer to a factory. See plugin-factory.h for an example.
+ // 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.
diff --git a/include/clap/events.h b/include/clap/events.h
@@ -83,14 +83,14 @@ enum {
// Plugin->Host NoteEnd(port:0, channel:0, key:16, time:ignored)
//
// These four events use clap_event_note.
- CLAP_EVENT_NOTE_ON,
- CLAP_EVENT_NOTE_OFF,
- CLAP_EVENT_NOTE_CHOKE,
- CLAP_EVENT_NOTE_END,
+ CLAP_EVENT_NOTE_ON = 0,
+ CLAP_EVENT_NOTE_OFF = 1,
+ CLAP_EVENT_NOTE_CHOKE = 2,
+ CLAP_EVENT_NOTE_END = 3,
// Represents a note expression.
// Uses clap_event_note_expression.
- CLAP_EVENT_NOTE_EXPRESSION,
+ CLAP_EVENT_NOTE_EXPRESSION = 4,
// PARAM_VALUE sets the parameter's value; uses clap_event_param_value.
// PARAM_MOD sets the parameter's modulation amount; uses clap_event_param_mod.
@@ -100,20 +100,20 @@ enum {
// In case of a concurrent global value/modulation versus a polyphonic one,
// the voice should only use the polyphonic one and the polyphonic modulation
// amount will already include the monophonic signal.
- CLAP_EVENT_PARAM_VALUE,
- CLAP_EVENT_PARAM_MOD,
+ CLAP_EVENT_PARAM_VALUE = 5,
+ CLAP_EVENT_PARAM_MOD = 6,
// Indicates that the user started or finished adjusting a knob.
// This is not mandatory to wrap parameter changes with gesture events, but this improves
// the user experience a lot when recording automation or overriding automation playback.
// Uses clap_event_param_gesture.
- CLAP_EVENT_PARAM_GESTURE_BEGIN,
- CLAP_EVENT_PARAM_GESTURE_END,
+ CLAP_EVENT_PARAM_GESTURE_BEGIN = 7,
+ CLAP_EVENT_PARAM_GESTURE_END = 8,
- CLAP_EVENT_TRANSPORT, // update the transport info; clap_event_transport
- CLAP_EVENT_MIDI, // raw midi event; clap_event_midi
- CLAP_EVENT_MIDI_SYSEX, // raw midi sysex event; clap_event_midi_sysex
- CLAP_EVENT_MIDI2, // raw midi 2 event; clap_event_midi2
+ CLAP_EVENT_TRANSPORT = 9, // update the transport info; clap_event_transport
+ CLAP_EVENT_MIDI = 10, // raw midi event; clap_event_midi
+ CLAP_EVENT_MIDI_SYSEX = 11, // raw midi sysex event; clap_event_midi_sysex
+ CLAP_EVENT_MIDI2 = 12, // raw midi 2 event; clap_event_midi2
};
// Note on, off, end and choke events.
@@ -132,19 +132,19 @@ typedef struct clap_event_note {
enum {
// with 0 < x <= 4, plain = 20 * log(x)
- CLAP_NOTE_EXPRESSION_VOLUME,
+ CLAP_NOTE_EXPRESSION_VOLUME = 0,
// pan, 0 left, 0.5 center, 1 right
- CLAP_NOTE_EXPRESSION_PAN,
+ CLAP_NOTE_EXPRESSION_PAN = 1,
// relative tuning in semitone, from -120 to +120
- CLAP_NOTE_EXPRESSION_TUNING,
+ CLAP_NOTE_EXPRESSION_TUNING = 2,
// 0..1
- CLAP_NOTE_EXPRESSION_VIBRATO,
- CLAP_NOTE_EXPRESSION_EXPRESSION,
- CLAP_NOTE_EXPRESSION_BRIGHTNESS,
- CLAP_NOTE_EXPRESSION_PRESSURE,
+ CLAP_NOTE_EXPRESSION_VIBRATO = 3,
+ CLAP_NOTE_EXPRESSION_EXPRESSION = 4,
+ CLAP_NOTE_EXPRESSION_BRIGHTNESS = 5,
+ CLAP_NOTE_EXPRESSION_PRESSURE = 6,
};
typedef int32_t clap_note_expression;
diff --git a/include/clap/ext/audio-ports-config.h b/include/clap/ext/audio-ports-config.h
@@ -2,6 +2,7 @@
#include "../string-sizes.h"
#include "../plugin.h"
+#include "audio-ports.h"
/// @page Audio Ports Config
///
@@ -20,8 +21,13 @@
///
/// Plugins with very complex configuration possibilities should let the user configure the ports
/// from the plugin GUI, and call @ref clap_host_audio_ports.rescan(CLAP_AUDIO_PORTS_RESCAN_ALL).
+///
+/// To inquire the exact bus layout, the plugin implements the clap_plugin_audio_ports_config_info_t
+/// extension where all busses can be retrieved in the same way as in the audio-port extension.
static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_CONFIG[] = "clap.audio-ports-config";
+static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS_CONFIG_INFO[] =
+ "clap.audio-ports-config-info/draft-0";
#ifdef __cplusplus
extern "C" {
@@ -65,6 +71,25 @@ typedef struct clap_plugin_audio_ports_config {
bool(CLAP_ABI *select)(const clap_plugin_t *plugin, clap_id config_id);
} clap_plugin_audio_ports_config_t;
+// Extended config info
+typedef struct clap_plugin_audio_ports_config_info {
+
+ // Gets the id of the currently selected config, or CLAP_INVALID_ID if the current port
+ // layout isn't part of the config list.
+ //
+ // [main-thread]
+ clap_id(CLAP_ABI *current_config)(const clap_plugin_t *plugin);
+
+ // Get info about about an audio port, for a given config_id.
+ // This is analogous to clap_plugin_audio_ports.get().
+ // [main-thread]
+ bool(CLAP_ABI *get)(const clap_plugin_t *plugin,
+ clap_id config_id,
+ uint32_t port_index,
+ bool is_input,
+ clap_audio_port_info_t *info);
+} clap_plugin_audio_ports_config_info_t;
+
typedef struct clap_host_audio_ports_config {
// Rescan the full list of configs.
// [main-thread]
diff --git a/include/clap/ext/audio-ports.h b/include/clap/ext/audio-ports.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#include "../plugin.h"
#include "../string-sizes.h"
diff --git a/include/clap/ext/draft/ambisonic.h b/include/clap/ext/draft/ambisonic.h
@@ -4,7 +4,7 @@
// 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/0";
+static CLAP_CONSTEXPR const char CLAP_EXT_AMBISONIC[] = "clap.ambisonic.draft/1";
static CLAP_CONSTEXPR const char CLAP_PORT_AMBISONIC[] = "ambisonic";
@@ -35,8 +35,12 @@ typedef struct clap_ambisonic_info {
typedef struct clap_plugin_ambisonic {
// 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_info)(const clap_plugin_t *plugin,
+ clap_id config_id,
bool is_input,
uint32_t port_index,
clap_ambisonic_info_t *info);
diff --git a/include/clap/ext/draft/audio-ports-activation.h b/include/clap/ext/draft/audio-ports-activation.h
@@ -7,9 +7,9 @@
/// 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
+/// an optimized computation path,
/// - the plugin knows that an output is not consumed by the host, and doesn't need to
-/// compute it
+/// compute it.
///
/// Audio ports can only be activated or deactivated when the plugin is deactivated, unless
/// can_activate_while_processing() returns true.
@@ -26,7 +26,7 @@
/// 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-0";
+ "clap.audio-ports-activation/draft-1";
#ifdef __cplusplus
extern "C" {
@@ -39,11 +39,12 @@ typedef struct clap_plugin_audio_ports_activation {
// Activate the given port.
//
- // It is only possible to activate on the audio-thread if can_activate_while_processing() returns
- // true.
+ // It is only possible to activate and de-activate on the audio-thread if
+ // can_activate_while_processing() returns true.
//
+ // returns false if failed, or invalid parameters
// [active ? audio-thread : main-thread]
- void(CLAP_ABI *set_active)(const clap_plugin_t *plugin,
+ bool(CLAP_ABI *set_active)(const clap_plugin_t *plugin,
bool is_input,
uint32_t port_index,
bool is_active);
diff --git a/include/clap/ext/draft/context-menu.h b/include/clap/ext/draft/context-menu.h
@@ -44,6 +44,10 @@ enum {
// 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;
@@ -68,6 +72,14 @@ typedef struct clap_context_menu_check_entry {
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;
diff --git a/include/clap/ext/draft/preset-load.h b/include/clap/ext/draft/preset-load.h
@@ -2,18 +2,43 @@
#include "../../plugin.h"
-static const char CLAP_EXT_PRESET_LOAD[] = "clap.preset-load.draft/0";
+static const char CLAP_EXT_PRESET_LOAD[] = "clap.preset-load.draft/1";
#ifdef __cplusplus
extern "C" {
#endif
typedef struct clap_plugin_preset_load {
- // Loads a preset in the plugin native preset file format from a path.
+ // Loads a preset in the plugin native preset file format from a URI. eg:
+ // - "file:///home/abique/.u-he/Diva/Presets/Diva/HS Bass Nine.h2p", load_key: null
+ // - "plugin://<plugin-id>", load_key: <XXX>
+ //
+ // The preset discovery provider defines the uri and load_key to be passed to this function.
+ //
// [main-thread]
- bool(CLAP_ABI *from_file)(const clap_plugin_t *plugin, const char *path);
+ bool(CLAP_ABI *from_uri)(const clap_plugin_t *plugin, const char *uri, 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,
+ const char *uri,
+ 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, const char *uri, 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
@@ -31,7 +31,7 @@
// 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/1";
+static CLAP_CONSTEXPR const char CLAP_EXT_REMOTE_CONTROLS[] = "clap.remote-controls.draft/2";
#ifdef __cplusplus
extern "C" {
@@ -44,6 +44,10 @@ typedef struct clap_remote_controls_page {
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 {
diff --git a/include/clap/ext/draft/surround.h b/include/clap/ext/draft/surround.h
@@ -24,7 +24,7 @@
// 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/1";
+static CLAP_CONSTEXPR const char CLAP_EXT_SURROUND[] = "clap.surround.draft/2";
static CLAP_CONSTEXPR const char CLAP_PORT_SURROUND[] = "surround";
@@ -55,9 +55,13 @@ enum {
typedef struct clap_plugin_surround {
// Stores into the channel_map array, the surround identifer of each channels.
- // Returns the number of elements stored in channel_map
+ // Returns the number of elements stored in channel_map.
+ //
+ // 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]
uint32_t(CLAP_ABI *get_channel_map)(const clap_plugin_t *plugin,
+ clap_id config_id,
bool is_input,
uint32_t port_index,
uint8_t *channel_map,
diff --git a/include/clap/ext/params.h b/include/clap/ext/params.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#include "../plugin.h"
#include "../string-sizes.h"
@@ -46,7 +46,7 @@
/// (latency, audio ports, new parameters, ...) be sure to wait for the host
/// to deactivate the plugin to apply those changes.
/// If there are no breaking changes, the plugin can apply them them right away.
-/// The plugin is resonsible for updating both its audio processor and its gui.
+/// The plugin is responsible for updating both its audio processor and its gui.
///
/// II. Turning a knob on the DAW interface
/// - the host will send an automation event to the plugin via a process() or flush()
@@ -63,8 +63,8 @@
/// - the plugin is responsible for updating its GUI
///
/// V. Turning a knob via plugin's internal MIDI mapping
-/// - the plugin sends a CLAP_EVENT_PARAM_SET output event, set should_record to false
-/// - the plugin is responsible to update its GUI
+/// - the plugin sends a CLAP_EVENT_PARAM_VALUE output event, set should_record to false
+/// - the plugin is responsible for updating its GUI
///
/// VI. Adding or removing parameters
/// - if the plugin is activated call clap_host->restart()
@@ -97,7 +97,7 @@
/// ..... . .
/// before: . . and after: . .
///
-/// Advices for the host:
+/// Advice for the host:
/// - store plain values in the document (automation)
/// - store modulation amount in plain value delta, not in percentage
/// - when you apply a CC mapping, remember the min/max plain values so you can adjust
@@ -185,14 +185,13 @@ typedef uint32_t clap_param_info_flags;
/* This describes a parameter */
typedef struct clap_param_info {
- // stable parameter identifier, it must never change.
+ // Stable parameter identifier, it must never change.
clap_id id;
clap_param_info_flags flags;
// This value is optional and set by the plugin.
- // Its purpose is to provide a fast access to the
- // plugin parameter object by caching its pointer.
+ // Its purpose is to provide a fast access to the plugin parameter object by caching its pointer.
// For instance:
//
// in clap_plugin_params.get_info():
@@ -205,32 +204,31 @@ typedef struct clap_param_info {
// if (!p) [[unlikely]]
// p = findParameter(event->param_id);
//
- // where findParameter() is a function the plugin implements
- // to map parameter ids to internal objects.
+ // where findParameter() is a function the plugin implements to map parameter ids to internal
+ // objects.
//
// Important:
- // - The cookie is invalidated by a call to
- // clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) or when the plugin is
- // destroyed.
- // - The host will either provide the cookie as issued or nullptr
- // in events addressing parameters.
- // - The plugin must gracefully handle the case of a cookie
- // which is nullptr.
- // - Many plugins will process the parameter events more quickly if the host
- // can provide the cookie in a faster time than a hashmap lookup per param
- // per event.
+ // - The cookie is invalidated by a call to clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) or
+ // when the plugin is destroyed.
+ // - The host will either provide the cookie as issued or nullptr in events addressing
+ // parameters.
+ // - The plugin must gracefully handle the case of a cookie which is nullptr.
+ // - Many plugins will process the parameter events more quickly if the host can provide the
+ // cookie in a faster time than a hashmap lookup per param per event.
void *cookie;
- // the display name
+ // The display name. eg: "Volume". This does not need to be unique. Do not include the module
+ // text in this. The host should concatenate/format the module + name in the case where showing
+ // the name alone would be too vague.
char name[CLAP_NAME_SIZE];
- // the module path containing the param, eg:"oscillators/wt1"
- // '/' will be used as a separator to show a tree like structure.
+ // The module path containing the param, eg: "Oscillators/Wavetable 1".
+ // '/' will be used as a separator to show a tree-like structure.
char module[CLAP_PATH_SIZE];
- double min_value; // minimum plain value
- double max_value; // maximum plain value
- double default_value; // default plain value
+ double min_value; // Minimum plain value
+ double max_value; // Maximum plain value
+ double default_value; // Default plain value
} clap_param_info_t;
typedef struct clap_plugin_params {
@@ -238,29 +236,32 @@ typedef struct clap_plugin_params {
// [main-thread]
uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
- // Copies the parameter's info to param_info and returns true on success.
+ // Copies the parameter's info to param_info. Returns true on success.
// [main-thread]
bool(CLAP_ABI *get_info)(const clap_plugin_t *plugin,
uint32_t param_index,
clap_param_info_t *param_info);
- // Gets the parameter plain value.
+ // Writes the parameter's current value to out_value. Returns true on success.
// [main-thread]
- bool(CLAP_ABI *get_value)(const clap_plugin_t *plugin, clap_id param_id, double *value);
+ bool(CLAP_ABI *get_value)(const clap_plugin_t *plugin, clap_id param_id, double *out_value);
- // Formats the display text for the given parameter value.
- // The host should always format the parameter value to text using this function
- // before displaying it to the user.
- // [main-thread]
- bool(CLAP_ABI *value_to_text)(
- const clap_plugin_t *plugin, clap_id param_id, double value, char *display, uint32_t size);
+ // Fills out_buffer with a null-terminated UTF-8 string that represents the parameter at the
+ // given 'value' argument. eg: "2.3 kHz". Returns true on success. The host should always use
+ // this to format parameter values before displaying it to the user. [main-thread]
+ bool(CLAP_ABI *value_to_text)(const clap_plugin_t *plugin,
+ clap_id param_id,
+ double value,
+ char *out_buffer,
+ uint32_t out_buffer_capacity);
- // Converts the display text to a parameter value.
+ // Converts the null-terminated UTF-8 param_value_text into a double and writes it to out_value.
+ // Returns true on success. The host can use this to convert user input into a parameter value.
// [main-thread]
bool(CLAP_ABI *text_to_value)(const clap_plugin_t *plugin,
clap_id param_id,
- const char *display,
- double *value);
+ const char *param_value_text,
+ double *out_value);
// Flushes a set of parameter changes.
// This method must not be called concurrently to clap_plugin->process().
diff --git a/include/clap/factory/draft/plugin-invalidation.h b/include/clap/factory/draft/plugin-invalidation.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "../../private/std.h"
+#include "../../private/macros.h"
+
+// Use it to retrieve const clap_plugin_invalidation_factory_t* from
+// clap_plugin_entry.get_factory()
+static const CLAP_CONSTEXPR char CLAP_PLUGIN_INVALIDATION_FACTORY_ID[] =
+ "clap.plugin-invalidation-factory/draft0";
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct clap_plugin_invalidation_source {
+ // Directory containing the file(s) to scan, must be absolute
+ const char *directory;
+
+ // globing pattern, in the form *.dll
+ const char *filename_glob;
+
+ // should the directory be scanned recursively?
+ bool recursive_scan;
+} clap_plugin_invalidation_source_t;
+
+// Used to figure out when a plugin needs to be scanned again.
+// Imagine a situation with a single entry point: my-plugin.clap which then scans itself
+// a set of "sub-plugins". New plugin may be available even if my-plugin.clap file doesn't change.
+// This interfaces solves this issue and gives a way to the host to monitor additional files.
+typedef struct clap_plugin_invalidation_factory {
+ // Get the number of invalidation source.
+ uint32_t(CLAP_ABI *count)(const struct clap_plugin_invalidation_factory *factory);
+
+ // Get the invalidation source by its index.
+ // [thread-safe]
+ const clap_plugin_invalidation_source_t *(CLAP_ABI *get)(
+ const struct clap_plugin_invalidation_factory *factory, uint32_t index);
+
+ // In case the host detected a invalidation event, it can call refresh() to let the
+ // plugin_entry update the set of plugins available.
+ // If the function returned false, then the plugin needs to be reloaded.
+ bool(CLAP_ABI *refresh)(const struct clap_plugin_invalidation_factory *factory);
+} clap_plugin_invalidation_factory_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/include/clap/factory/draft/preset-discovery.h b/include/clap/factory/draft/preset-discovery.h
@@ -0,0 +1,316 @@
+/*
+ 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-1";
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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 additionnal 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 must be null.
+ //
+ // 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, the 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;
+
+ // `.' 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
+
+ // URI:
+ // - file:/// for pointing to a file or directory; directories are scanned recursively
+ // eg: file:///home/abique/.u-he/Diva/Presets/Diva (on Linux)
+ // eg: file:///C:/Users/abique/Documents/u-he/Diva.data/Presets/ (on Windows)
+ //
+ // - plugin:// for presets which are bundled within the plugin DSO.
+ // In that case, the uri must be exactly `plugin://` and nothing more.
+ const char *uri;
+} clap_preset_discovery_location_t;
+
+// Describes an installed sound pack.
+typedef struct clap_preset_discovery_soundpack {
+ uint64_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; // reasonably short description of the sound pack
+ const char *homepage_url; // url to the pack's homepage
+ const char *vendor; // sound pack's vendor
+ const char *image_uri; // may be an image on disk or from an http server
+ 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; // 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
+ bool(CLAP_ABI *get_metadata)(const struct clap_preset_discovery_provider *provider,
+ const char *uri,
+ 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; // eg: "Bitwig GmbH"
+ const char *url; // eg: "https://bitwig.com"
+ const char *version; // eg: "4.3", see plugin.h for advice on how to format the version
+
+ 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 encourraged 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/plugin-factory.h b/include/clap/factory/plugin-factory.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "../plugin.h"
+
+// Use it to retrieve const clap_plugin_factory_t* from
+// clap_plugin_entry.get_factory()
+static const CLAP_CONSTEXPR char CLAP_PLUGIN_FACTORY_ID[] = "clap.plugin-factory";
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Every method must be thread-safe.
+// It is very important to be able to scan the plugin as quickly as possible.
+//
+// The host may use clap_plugin_invalidation_factory to detect filesystem changes
+// which may change the factory's content.
+typedef struct clap_plugin_factory {
+ // Get the number of plugins available.
+ // [thread-safe]
+ uint32_t(CLAP_ABI *get_plugin_count)(const struct clap_plugin_factory *factory);
+
+ // Retrieves a plugin descriptor by its index.
+ // Returns null in case of error.
+ // The descriptor must not be freed.
+ // [thread-safe]
+ const clap_plugin_descriptor_t *(CLAP_ABI *get_plugin_descriptor)(
+ const struct clap_plugin_factory *factory, uint32_t index);
+
+ // Create a clap_plugin by its plugin_id.
+ // The returned pointer must be freed by calling plugin->destroy(plugin);
+ // The plugin is not allowed to use the host callbacks in the create method.
+ // Returns null in case of error.
+ // [thread-safe]
+ const clap_plugin_t *(CLAP_ABI *create_plugin)(const struct clap_plugin_factory *factory,
+ const clap_host_t *host,
+ const char *plugin_id);
+} clap_plugin_factory_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/include/clap/host.h b/include/clap/host.h
@@ -15,9 +15,12 @@ typedef struct clap_host {
const char *name; // eg: "Bitwig Studio"
const char *vendor; // eg: "Bitwig GmbH"
const char *url; // eg: "https://bitwig.com"
- const char *version; // eg: "4.3"
+ const char *version; // eg: "4.3", see plugin.h for advice on how to format the version
// Query an extension.
+ // The returned pointer is owned by the host.
+ // It is forbidden to call it before plugin->init().
+ // You can call it within plugin->init() call, and after.
// [thread-safe]
const void *(CLAP_ABI *get_extension)(const struct clap_host *host, const char *extension_id);
diff --git a/include/clap/plugin-factory.h b/include/clap/plugin-factory.h
@@ -1,40 +0,0 @@
-#pragma once
-
-#include "plugin.h"
-
-static const CLAP_CONSTEXPR char CLAP_PLUGIN_FACTORY_ID[] = "clap.plugin-factory";
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Every method must be thread-safe.
-// It is very important to be able to scan the plugin as quickly as possible.
-//
-// The host may use clap_plugin_invalidation_factory to detect filesystem changes
-// which may change the factory's content.
-typedef struct clap_plugin_factory {
- // Get the number of plugins available.
- // [thread-safe]
- uint32_t(CLAP_ABI *get_plugin_count)(const struct clap_plugin_factory *factory);
-
- // Retrieves a plugin descriptor by its index.
- // Returns null in case of error.
- // The descriptor must not be freed.
- // [thread-safe]
- const clap_plugin_descriptor_t *(CLAP_ABI *get_plugin_descriptor)(
- const struct clap_plugin_factory *factory, uint32_t index);
-
- // Create a clap_plugin by its plugin_id.
- // The returned pointer must be freed by calling plugin->destroy(plugin);
- // The plugin is not allowed to use the host callbacks in the create method.
- // Returns null in case of error.
- // [thread-safe]
- const clap_plugin_t *(CLAP_ABI *create_plugin)(const struct clap_plugin_factory *factory,
- const clap_host_t *host,
- const char *plugin_id);
-} clap_plugin_factory_t;
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/include/clap/plugin-features.h b/include/clap/plugin-features.h
@@ -1,7 +1,5 @@
#pragma once
-#include "private/macros.h"
-
// This file provides a set of standard plugin features meant to be used
// within clap_plugin_descriptor.features.
//
@@ -23,6 +21,9 @@
// Add this feature if your plugin is a note effect or a note generator/sequencer
#define CLAP_PLUGIN_FEATURE_NOTE_EFFECT "note-effect"
+// Add this feature if your plugin converts audio to notes
+#define CLAP_PLUGIN_FEATURE_NOTE_DETECTOR "note-detector"
+
// Add this feature if your plugin is an analyzer
#define CLAP_PLUGIN_FEATURE_ANALYZER "analyzer"
diff --git a/include/clap/plugin-invalidation.h b/include/clap/plugin-invalidation.h
@@ -1,45 +0,0 @@
-#pragma once
-
-#include "private/std.h"
-#include "private/macros.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct clap_plugin_invalidation_source {
- // Directory containing the file(s) to scan, must be absolute
- const char *directory;
-
- // globing pattern, in the form *.dll
- const char *filename_glob;
-
- // should the directory be scanned recursively?
- bool recursive_scan;
-} clap_plugin_invalidation_source_t;
-
-static const CLAP_CONSTEXPR char CLAP_PLUGIN_INVALIDATION_FACTORY_ID[] =
- "clap.plugin-invalidation-factory/draft0";
-
-// Used to figure out when a plugin needs to be scanned again.
-// Imagine a situation with a single entry point: my-plugin.clap which then scans itself
-// a set of "sub-plugins". New plugin may be available even if my-plugin.clap file doesn't change.
-// This interfaces solves this issue and gives a way to the host to monitor additional files.
-typedef struct clap_plugin_invalidation_factory {
- // Get the number of invalidation source.
- uint32_t(CLAP_ABI *count)(const struct clap_plugin_invalidation_factory *factory);
-
- // Get the invalidation source by its index.
- // [thread-safe]
- const clap_plugin_invalidation_source_t *(CLAP_ABI *get)(
- const struct clap_plugin_invalidation_factory *factory, uint32_t index);
-
- // In case the host detected a invalidation event, it can call refresh() to let the
- // plugin_entry update the set of plugins available.
- // If the function returned false, then the plugin needs to be reloaded.
- bool(CLAP_ABI *refresh)(const struct clap_plugin_invalidation_factory *factory);
-} clap_plugin_invalidation_factory_t;
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/include/clap/plugin.h b/include/clap/plugin.h
@@ -14,6 +14,14 @@ typedef struct clap_plugin_descriptor {
// Mandatory fields must be set and must not be blank.
// Otherwise the fields can be null or blank, though it is safer to make them blank.
+ //
+ // Some indications regarding id and version
+ // - id is an arbritrary string which should be unique to your plugin,
+ // we encourage you to use a reverse URI eg: "com.u-he.diva"
+ // - version is an arbitrary string which describes a plugin,
+ // it is useful for the host to understand and be able to compare two different
+ // version strings, so here is a regex like expression which is likely to be
+ // understood by most hosts: MAJOR(.MINOR(.REVISION)?)?( (Alpha|Beta) XREV)?
const char *id; // eg: "com.u-he.diva", mandatory
const char *name; // eg: "Diva", mandatory
const char *vendor; // eg: "u-he"
@@ -37,6 +45,7 @@ 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.
// [main-thread]
bool(CLAP_ABI *init)(const struct clap_plugin *plugin);
@@ -84,6 +93,8 @@ typedef struct clap_plugin {
// Query an extension.
// The returned pointer is owned by the plugin.
+ // It is forbidden to call it before plugin->init().
+ // You can call it within plugin->init() call, and after.
// [thread-safe]
const void *(CLAP_ABI *get_extension)(const struct clap_plugin *plugin, const char *id);
diff --git a/include/clap/version.h b/include/clap/version.h
@@ -20,11 +20,18 @@ typedef struct clap_version {
}
#endif
-#define CLAP_VERSION_MAJOR ((uint32_t)1)
-#define CLAP_VERSION_MINOR ((uint32_t)1)
-#define CLAP_VERSION_REVISION ((uint32_t)4)
+#define CLAP_VERSION_MAJOR 1
+#define CLAP_VERSION_MINOR 1
+#define CLAP_VERSION_REVISION 7
+
#define CLAP_VERSION_INIT \
- { CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION }
+ { (uint32_t)CLAP_VERSION_MAJOR, (uint32_t)CLAP_VERSION_MINOR, (uint32_t)CLAP_VERSION_REVISION }
+
+#define CLAP_VERSION_LT(maj,min,rev) ((CLAP_VERSION_MAJOR < (maj)) || \
+ ((maj) == CLAP_VERSION_MAJOR && CLAP_VERSION_MINOR < (min)) || \
+ ((maj) == CLAP_VERSION_MAJOR && (min) == CLAP_VERSION_MINOR && CLAP_VERSION_REVISION < (rev)))
+#define CLAP_VERSION_EQ(maj,min,rev) (((maj) == CLAP_VERSION_MAJOR) && ((min) == CLAP_VERSION_MINOR) && ((rev) == CLAP_VERSION_REVISION))
+#define CLAP_VERSION_GE(maj,min,rev) (!CLAP_VERSION_LT(maj,min,rev))
static const CLAP_CONSTEXPR clap_version_t CLAP_VERSION = CLAP_VERSION_INIT;
diff --git a/src/main.cc b/src/main.cc
@@ -2,8 +2,54 @@
// The purpose of this file is to check that all headers compile
+#if CLAP_VERSION_LT(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_LT is inconsistent
+#endif
+
+#if !CLAP_VERSION_EQ(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_EQ is inconsistent
+#endif
+
+#if CLAP_VERSION_EQ(CLAP_VERSION_MAJOR + 1, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_EQ is inconsistent (MAJOR)
+#endif
+#if CLAP_VERSION_EQ(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR + 1, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_EQ is inconsistent (MINOR)
+#endif
+#if CLAP_VERSION_EQ(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION + 1)
+#error CLAP_VERSION_EQ is inconsistent (REVISION)
+#endif
+
+#if !CLAP_VERSION_GE(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_GE is inconsistent
+#endif
+
+#if CLAP_VERSION_LT(1,1,5)
+#error CLAP_VERSION_GE was inroduced in 1.1.5 so we should be later than that version.
+#endif
+
+#if !CLAP_VERSION_LT(CLAP_VERSION_MAJOR + 1, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_LT is inconsistent (MAJOR)
+#endif
+#if !CLAP_VERSION_LT(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR + 1, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_LT is inconsistent (MINOR)
+#endif
+#if !CLAP_VERSION_LT(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION + 1)
+#error CLAP_VERSION_LT is inconsistent (REVISION)
+#endif
+
+#if CLAP_VERSION_LT(CLAP_VERSION_MAJOR - 1, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_LT is inconsistent (MAJOR)
+#endif
+#if CLAP_VERSION_LT(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR - 1, CLAP_VERSION_REVISION)
+#error CLAP_VERSION_LT is inconsistent (MINOR)
+#endif
+#if CLAP_VERSION_LT(CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION - 1)
+#error CLAP_VERSION_LT is inconsistent (REVISION)
+#endif
+
static const CLAP_CONSTEXPR clap_version m = CLAP_VERSION;
int main(int, char **) {
return !clap_version_is_compatible(m);
-}
-\ No newline at end of file
+}
diff --git a/src/plugin-template.c b/src/plugin-template.c
@@ -25,9 +25,10 @@ static const clap_plugin_descriptor_t s_my_plug_desc = {
typedef struct {
clap_plugin_t plugin;
const clap_host_t *host;
- const clap_host_latency_t *hostLatency;
- const clap_host_log_t *hostLog;
- const clap_host_thread_check_t *hostThreadCheck;
+ const clap_host_latency_t *host_latency;
+ const clap_host_log_t *host_log;
+ const clap_host_thread_check_t *host_thread_check;
+ const clap_host_state_t *host_state;
uint32_t latency;
} my_plug_t;
@@ -36,7 +37,10 @@ typedef struct {
// clap_plugin_audio_ports //
/////////////////////////////
-static uint32_t my_plug_audio_ports_count(const clap_plugin_t *plugin, bool is_input) { return 1; }
+static uint32_t my_plug_audio_ports_count(const clap_plugin_t *plugin, bool is_input) {
+ // We just declare 1 audio input and 1 audio output
+ return 1;
+}
static bool my_plug_audio_ports_get(const clap_plugin_t *plugin,
uint32_t index,
@@ -62,7 +66,10 @@ static const clap_plugin_audio_ports_t s_my_plug_audio_ports = {
// clap_plugin_note_ports //
////////////////////////////
-static uint32_t my_plug_note_ports_count(const clap_plugin_t *plugin, bool is_input) { return 1; }
+static uint32_t my_plug_note_ports_count(const clap_plugin_t *plugin, bool is_input) {
+ // We just declare 1 note input
+ return 1;
+}
static bool my_plug_note_ports_get(const clap_plugin_t *plugin,
uint32_t index,
@@ -96,6 +103,27 @@ static const clap_plugin_latency_t s_my_plug_latency = {
.get = my_plug_latency_get,
};
+////////////////
+// clap_state //
+////////////////
+
+bool my_plug_state_save(const clap_plugin_t *plugin, const clap_ostream_t *stream) {
+ my_plug_t *plug = plugin->plugin_data;
+ // TODO: write the state into stream
+ return true;
+}
+
+bool my_plug_state_load(const clap_plugin_t *plugin, const clap_istream_t *stream) {
+ my_plug_t *plug = plugin->plugin_data;
+ // TODO: read the state from stream
+ return true;
+}
+
+static const clap_plugin_state_t s_my_plug_state = {
+ .save = my_plug_state_save,
+ .load = my_plug_state_load,
+};
+
/////////////////
// clap_plugin //
/////////////////
@@ -104,9 +132,11 @@ static bool my_plug_init(const struct clap_plugin *plugin) {
my_plug_t *plug = plugin->plugin_data;
// Fetch host's extensions here
- plug->hostLog = plug->host->get_extension(plug->host, CLAP_EXT_LOG);
- plug->hostThreadCheck = plug->host->get_extension(plug->host, CLAP_EXT_THREAD_CHECK);
- plug->hostLatency = plug->host->get_extension(plug->host, CLAP_EXT_LATENCY);
+ // Make sure to check that the interface functions are not null pointers
+ plug->host_log = (const clap_host_log_t *)plug->host->get_extension(plug->host, CLAP_EXT_LOG);
+ plug->host_thread_check = (const clap_host_thread_check_t *)plug->host->get_extension(plug->host, CLAP_EXT_THREAD_CHECK);
+ plug->host_latency = (const clap_host_latency_t *)plug->host->get_extension(plug->host, CLAP_EXT_LATENCY);
+ plug->host_state = (const clap_host_state_t *)plug->host->get_extension(plug->host, CLAP_EXT_STATE);
return true;
}
@@ -249,8 +279,9 @@ static const void *my_plug_get_extension(const struct clap_plugin *plugin, const
return &s_my_plug_audio_ports;
if (!strcmp(id, CLAP_EXT_NOTE_PORTS))
return &s_my_plug_note_ports;
+ if (!strcmp(id, CLAP_EXT_STATE))
+ return &s_my_plug_state;
// TODO: add support to CLAP_EXT_PARAMS
- // TODO: add support to CLAP_EXT_STATE
return NULL;
}
@@ -340,6 +371,7 @@ static const void *entry_get_factory(const char *factory_id) {
return NULL;
}
+// 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,