commit 065d685d4e9657f0344f350eef748be2b4d8e318 parent d6cbd4fd6540e80be816994f6f6bccc7933998ef Author: Alexandre Bique <bique.alexandre@gmail.com> Date: Wed, 25 Jan 2023 18:38:25 +0100 Merge pull request #270 from free-audio/next 1.1.7 Diffstat:
22 files changed, 550 insertions(+), 126 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -72,7 +72,11 @@ 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) diff --git a/ChangeLog.md b/ChangeLog.md @@ -1,3 +1,24 @@ +# 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 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 @@ -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/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 @@ -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" { @@ -42,8 +42,9 @@ typedef struct clap_plugin_audio_ports_activation { // 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 @@ -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() 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 @@ -18,6 +18,7 @@ typedef struct clap_host { 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] 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/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 }