commit ddbae27c12153c864a31662ea41a5757e5603a1c
parent 650ad6a6b0215b3f964c49a004667ad876689dfd
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date: Fri, 30 Dec 2022 18:18:52 +0100
Merge pull request #253 from free-audio/next
1.1.5
Diffstat:
12 files changed, 155 insertions(+), 61 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}")
@@ -79,6 +79,7 @@ if (${CLAP_BUILD_TESTS})
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,18 @@
+# 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/include/clap/clap.h b/include/clap/clap.h
@@ -1,4 +1,4 @@
-/*
+/*
* CLAP - CLever Audio Plugin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
*
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/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.
@@ -39,8 +39,8 @@ 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.
//
// [active ? audio-thread : main-thread]
void(CLAP_ABI *set_active)(const clap_plugin_t *plugin,
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"
@@ -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/host.h b/include/clap/host.h
@@ -15,9 +15,11 @@ 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.
+ // 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.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 5
+
#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) (((maj) < CLAP_VERSION_MAJOR) || \
+ ((maj) == CLAP_VERSION_MAJOR && (min) < CLAP_VERSION_MINOR ) || \
+ ((maj) == CLAP_VERSION_MAJOR && (min) == CLAP_VERSION_MINOR && (rev) < CLAP_VERSION_REVISION))
+#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,34 @@
// 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
+
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,