/
preset-discovery.h
313 lines (263 loc) · 15.2 KB
/
preset-discovery.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
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 "../timestamp.h"
#include "../version.h"
#include "../universal-plugin-id.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/2";
// The latest draft is 100% compatible.
// This compat ID may be removed in 2026.
static const CLAP_CONSTEXPR char CLAP_PRESET_DISCOVERY_FACTORY_ID_COMPAT[] =
"clap.preset-discovery-factory/draft-2";
#ifdef __cplusplus
extern "C" {
#endif
enum clap_preset_discovery_location_kind {
// The preset are located in a file on the OS filesystem.
// The location is then a path which works with the OS file system functions (open, stat, ...)
// So both '/' and '\' shall work on Windows as a separator.
CLAP_PRESET_DISCOVERY_LOCATION_FILE = 0,
// The preset is bundled within the plugin DSO itself.
// The location must then be null, as the preset are within the plugin itself and then the plugin
// will act as a preset container.
CLAP_PRESET_DISCOVERY_LOCATION_PLUGIN = 1,
};
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 additional 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,
};
// 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 are optional.
//
// 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, then 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_universal_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 creation_time,
clap_timestamp 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; // optional
// `.' 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
uint32_t kind; // See clap_preset_discovery_location_kind
// Actual location in which to crawl presets.
// For FILE kind, the location can be either a path to a directory or a file.
// For PLUGIN kind, the location must be null.
const char *location;
} clap_preset_discovery_location_t;
// Describes an installed sound pack.
typedef struct clap_preset_discovery_soundpack {
uint32_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; // optional, reasonably short description of the sound pack
const char *homepage_url; // optional, url to the pack's homepage
const char *vendor; // optional, sound pack's vendor
const char *image_path; // optional, an image on disk
clap_timestamp 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; // optional, 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
// Returns true on success.
bool(CLAP_ABI *get_metadata)(const struct clap_preset_discovery_provider *provider,
uint32_t location_kind,
const char *location,
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; // optional, eg: "Bitwig GmbH"
const char *url; // optional, eg: "https://bitwig.com"
const char *version; // optional, 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 encouraged 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