commit cc7211ffcee4fcaeef60074e685a460ad7eb86e1
parent c95cbcef3631df134752fa396c1d441ee46f266b
Author: Alexandre Bique <bique.alexandre@gmail.com>
Date: Thu, 29 Dec 2022 20:13:29 +0100
Adds Preset Discovery
Diffstat:
5 files changed, 293 insertions(+), 3 deletions(-)
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,231 @@
+/**
+ 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
+
+/** 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. */
+ void(CLAP_ABI *on_error)(const struct clap_preset_metadata_receiver *receiver,
+ 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 remap it to its internal
+ * categorization and tagging system.
+ */
+ 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];
+
+ // path to a directory on the file system in which preset can be found
+ char path[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;
+
+ // 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 *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;
+
+static const CLAP_CONSTEXPR char CLAP_PRESET_DISCOVERY_FACTORY_ID[] =
+ "clap.preset-discovery-factory";
+
+// Every methods in this factory 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_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 plugin 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 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_preset_provider_t *(CLAP_ABI *create)(
+ const struct clap_preset_discovery_factory *factory,
+ const clap_preset_indexer_t *indexer,
+ const char *provider_id);
+} clap_plugin_factory_t;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/include/clap/preset-features.h b/include/clap/preset-features.h
@@ -0,0 +1,45 @@
+#pragma once
+
+// This file provides a set of standard preset features meant to be used
+// within clap_plugin_descriptor.features.
+//
+// For practical reasons we'll avoid spaces and use `-` instead to facilitate
+// scripts that generate the feature array.
+//
+// Non-standard features should be formated as follow: "$namespace:$feature"
+
+#include "plugin-features.h"
+
+#define CLAP_PRESET_FEATURE_KICK "kick"
+#define CLAP_PRESET_FEATURE_TOM "tom"
+#define CLAP_PRESET_FEATURE_SNARE "snare"
+#define CLAP_PRESET_FEATURE_CLAP "clap"
+#define CLAP_PRESET_FEATURE_CYMBAL "cymbal"
+
+#define CLAP_PRESET_FEATURE_BASS "bass"
+#define CLAP_PRESET_FEATURE_LEAD "lead"
+#define CLAP_PRESET_FEATURE_KEY "key"
+#define CLAP_PRESET_FEATURE_PLUCK "pluck"
+#define CLAP_PRESET_FEATURE_STAB "stab"
+#define CLAP_PRESET_FEATURE_WIND "wind"
+#define CLAP_PRESET_FEATURE_STRING "string"
+#define CLAP_PRESET_FEATURE_PAD "pad"
+#define CLAP_PRESET_FEATURE_DRONE "drone"
+
+#define CLAP_PRESET_FEATURE_BRIGHT "bright"
+#define CLAP_PRESET_FEATURE_DARK "dark"
+#define CLAP_PRESET_FEATURE_SATURATED "saturated"
+#define CLAP_PRESET_FEATURE_TAPE "tape"
+#define CLAP_PRESET_FEATURE_DISTORDED "distorded"
+#define CLAP_PRESET_FEATURE_METALIC "metalic"
+#define CLAP_PRESET_FEATURE_ATONAL "atonal"
+#define CLAP_PRESET_FEATURE_NOISE "noise"
+#define CLAP_PRESET_FEATURE_DETUNED "detuned"
+#define CLAP_PRESET_FEATURE_ACID "acid"
+#define CLAP_PRESET_FEATURE_ANALOG "analog"
+#define CLAP_PRESET_FEATURE_DIGITAL "digital"
+#define CLAP_PRESET_FEATURE_CHIP "chip" // 8-bits, chiptune...
+
+#define CLAP_PRESET_FEATURE_SEQUENCE "sequence"
+#define CLAP_PRESET_FEATURE_ARPEGGIATOR "arpeggiator"
+#define CLAP_PRESET_FEATURE_CHORD "chord"
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