clap

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

commit 0513d1b8e7c0338e1d2b155cd7d471fa7991dcf5
parent d6cbd4fd6540e80be816994f6f6bccc7933998ef
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date:   Mon,  2 Jan 2023 09:45:35 +0100

Merge pull request #265 from abique/preset-discovery

Adds Preset Discovery
Diffstat:
MChangeLog.md | 6++++++
Minclude/clap/clap.h | 2++
Minclude/clap/ext/draft/preset-load.h | 12+++++++++++-
Minclude/clap/plugin-features.h | 2--
Ainclude/clap/preset-discovery.h | 251+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/clap/string-sizes.h | 6++++++
Minclude/clap/version.h | 2+-
7 files changed, 277 insertions(+), 4 deletions(-)

diff --git a/ChangeLog.md b/ChangeLog.md @@ -1,3 +1,9 @@ +# Changes in 1.1.7 + +## Draft extensions + +* [preset-discovery.h](include/clap/preset-discovery.h): new extension which allows the host to index the plugin's preset 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 diff --git a/include/clap/clap.h b/include/clap/clap.h @@ -65,3 +65,5 @@ #include "ext/draft/track-info.h" #include "ext/draft/triggers.h" #include "ext/draft/tuning.h" + +#include "preset-discovery.h" diff --git a/include/clap/ext/draft/preset-load.h b/include/clap/ext/draft/preset-load.h @@ -2,7 +2,7 @@ #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" { @@ -12,6 +12,16 @@ typedef struct clap_plugin_preset_load { // Loads a preset in the plugin native preset file format from a path. // [main-thread] bool(CLAP_ABI *from_file)(const clap_plugin_t *plugin, const char *path); + + // Loads a preset in the plugin native preset file format from a path which points to a preset + // container file. + // preset_id must be a valid string, which is specific to the plugin itself and identifies the + // desired preset within the given preset container. + // + // [main-thread] + bool(CLAP_ABI *from_container_file)(const clap_plugin_t *plugin, + const char *path, + const char *preset_id); } clap_plugin_preset_load_t; #ifdef __cplusplus 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. // diff --git a/include/clap/preset-discovery.h b/include/clap/preset-discovery.h @@ -0,0 +1,251 @@ +/** + 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. get the preset discovery factory + 2. create a preset provider + 3. list locations and file extensions from the preset provider + 4. monitor file system changes on the given locations + 5. read metadata for each preset files + 6. fetch information about collections from the preset provider + + Then to load a preset, use ext/draft/preset-load.h + + 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. +*/ + +#pragma once + +#include "private/std.h" +#include "private/macros.h" +#include "string-sizes.h" +#include "version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Use it to retrieve const struct clap_preset_discovery_factory* from +// clap_plugin_entry.get_factory() +static const CLAP_CONSTEXPR char CLAP_PRESET_DISCOVERY_FACTORY_ID[] = + "clap.preset-discovery-factory/draft-0"; + +/** 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 const struct clap_preset_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: + * 0 on unix and Windows. + */ + void(CLAP_ABI *on_error)(const struct clap_preset_metadata_receiver *receiver, + int32_t os_error, + const char *error_message); + + /** Marks this file as a container file meaning that it can contain other presets. */ + void(CLAP_ABI *mark_as_container_file)(const struct clap_preset_metadata_receiver *receiver); + + /** If the file being parsed is a preset container file (mark_as_container_file has been called) + * then this must be called for every preset in the file and before any preset metadata is + * sent with the calls below. If the file is not a container file then this should not be + * called at all. + * + * The path defines a human friendly path to the preset in the container file. It + * should be unique within the container file. + * + * The preset_id is a machine friendly string used to load the preset inside the container via a + * the preset-load plug-in extension. The preset_id can also just be the path if that's what the + * extension 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. + */ + void(CLAP_ABI *begin_contained_preset)(const struct clap_preset_metadata_receiver *receiver, + const char *path, + const char *preset_id); + + /** Marks this preset as a bank preset, meaning that it can be assigned to the plug-in as a + * preset but will update the banks in the plug-in. + */ + void(CLAP_ABI *mark_as_bank_preset)(const struct clap_preset_metadata_receiver *receiver); + + /** Sets plug-in id that this preset can be used with. */ + void(CLAP_ABI *set_plugin_id)(const struct clap_preset_metadata_receiver *receiver, + const char *plugin_id); + + /** Sets the collection to which the preset belongs to. */ + void(CLAP_ABI *set_collection_id)(const struct clap_preset_metadata_receiver, + const char *collection_id); + + /** Adds a creator name for the preset. */ + void(CLAP_ABI *add_creator)(const struct clap_preset_metadata_receiver *receiver, + const char *creator); + + /** Sets a description of the preset. */ + void(CLAP_ABI *set_description)(const struct clap_preset_metadata_receiver *receiver, + const char *description); + + /** Sets the creation time and last modification time of the preset. + * If one of the time isn't known, then set it to 0. */ + void(CLAP_ABI *set_timestamps)(const struct clap_preset_metadata_receiver *receiver, + uint64_t creation_time, + uint64_t modification_time); + + /** + * Adds a feature to the preset. + * See plugin-features.h and preset-features.h + * + * The feature string is arbitrary, it is the indexer's job to understand it and remap it to its + * internal categorization and tagging system. + * + * 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_metadata_receiver *receiver, + const char *feature); + +} *clap_preset_metadata_receiver_t; + +enum clap_preset_discovery_flags { + // This location/collection is meant for storing factory presets, most likely read-only + CLAP_PRESET_DISCOVERY_IS_FACTORY_CONTENT = 1 << 0, + + // This location/collection is meant for storing user created presets + CLAP_PRESET_DISCOVERY_IS_USER_CONTENT = 1 << 1, + + // This location/collection 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, +}; + +// Defines a place in which to search for presets +typedef struct clap_preset_location { + uint64_t flags; // see enum clap_preset_discovery_flags + + // name of this location + char name[CLAP_NAME_SIZE]; + + // URI + // - file:/// for pointing to a file or directory; directories are scanned recursively + // eg: file:///home/abique/.u-he/Diva/presets/ + // - plugin://<clap-plugin-id> for presets which are bundled inside the plugin itself + char uri[CLAP_URI_SIZE]; +} clap_preset_location_t; + +// A collection, represent a collection of presets; it is will most often used to identify presets +// which belongs to the same "sound pack". +typedef struct clap_preset_collection_info { + uint64_t flags; // see enum clap_preset_discovery_flags + + char name[CLAP_NAME_SIZE]; // name of this collection + char description[CLAP_DESCRIPTION_SIZE]; // reasonably short description of the collection + char homepage_url[CLAP_URI_SIZE]; // url to the pack's homepage + char image_uri[CLAP_URI_SIZE]; // may be an image on disk or from an http server +} clap_preset_collection_info_t; + +// Describes a preset provider +typedef struct clap_preset_provider_descriptor { + clap_version_t clap_version; // initialized to CLAP_VERSION + const char *id; + const char *name; + const char *vendor; + const char *const *plugin_ids; // null terminated array of plugin ids +} clap_preset_provider_descriptor_t; + +// This interface isn't thread-safe. +typedef struct clap_preset_provider { + const clap_preset_provider_descriptor_t *desc; + + // Destroys the preset provider + void(CLAP_ABI *destroy)(const struct clap_preset_provider *provider); + + // Retrives the path to a watch file. + // Whenever the given file is "touched", then the indexer shall invalidate all the data. + bool(CLAP_ABI *invalidation_watch_file)(const struct clap_preset_provider *provider, + char *watch_file_path, + uint32_t watch_file_path_capacity); + + // returns the number of locations + uint32_t(CLAP_ABI *locations_count)(const struct clap_preset_provider *provider); + + // gets the location info at index + bool(CLAP_ABI *get_location)(const struct clap_preset_provider *provider, + uint32_t index, + clap_preset_location_t *out_info); + + // returns the number of different supported file extensions + uint32_t(CLAP_ABI *file_extensions_count)(const struct clap_preset_provider *provider); + + // stores the file extensions at index into out_extension. + // the `.' isn't included in the string. + // extension_capacity indicates the number of bytes available to store the extension + bool(CLAP_ABI *get_file_extension)(const struct clap_preset_provider *provider, + uint32_t index, + char *out_extension, + uint32_t extension_capacity); + + // gets information about a given collection. + bool(CLAP_ABI *get_collection_info)(const struct clap_preset_provider *provider, + const char *collection_id, + clap_preset_collection_info_t *out_info); + + // reads metadata from the given file and passes them to the metadata receiver + bool(CLAP_ABI *read_file_metadata)(const struct clap_preset_provider *provider, + const char *file_path, + const clap_preset_metadata_receiver_t *metadata_receiver); +} clap_preset_provider_t; + +typedef struct clap_preset_indexer { + clap_version_t clap_version; // initialized to CLAP_VERSION + const char *name; + const char *vendor; + const char *version; +} clap_preset_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. +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_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. + // Returns null in case of error. + // [thread-safe] + const clap_preset_provider_t *(CLAP_ABI *create)( + const struct clap_preset_discovery_factory *factory, + const clap_preset_indexer_t *indexer, + const char *provider_id); +} clap_preset_discovery_factory_t; + +#ifdef __cplusplus +} +#endif diff --git a/include/clap/string-sizes.h b/include/clap/string-sizes.h @@ -14,6 +14,12 @@ enum { // This is not suited for describing a file path on the disk, as NTFS allows up to 32K long // paths. CLAP_PATH_SIZE = 1024, + + // String capacity for descriptions + CLAP_DESCRIPTION_SIZE = 1024, + + // String capacity for describing a filesystem file path, an web URL, ... + CLAP_URI_SIZE = 8096, }; #ifdef __cplusplus diff --git a/include/clap/version.h b/include/clap/version.h @@ -22,7 +22,7 @@ typedef struct clap_version { #define CLAP_VERSION_MAJOR 1 #define CLAP_VERSION_MINOR 1 -#define CLAP_VERSION_REVISION 6 +#define CLAP_VERSION_REVISION 7 #define CLAP_VERSION_INIT \ { (uint32_t)CLAP_VERSION_MAJOR, (uint32_t)CLAP_VERSION_MINOR, (uint32_t)CLAP_VERSION_REVISION }