comparison DPF-Prymula-audioplugins/dpf/distrho/src/clap/ext/params.h @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
1 #pragma once
2
3 #include "../plugin.h"
4 #include "../string-sizes.h"
5
6 /// @page Parameters
7 /// @brief parameters management
8 ///
9 /// Main idea:
10 ///
11 /// The host sees the plugin as an atomic entity; and acts as a controller on top of its parameters.
12 /// The plugin is responsible for keeping its audio processor and its GUI in sync.
13 ///
14 /// The host can at any time read parameters' value on the [main-thread] using
15 /// @ref clap_plugin_params.value().
16 ///
17 /// There are two options to communicate parameter value changes, and they are not concurrent.
18 /// - send automation points during clap_plugin.process()
19 /// - send automation points during clap_plugin_params.flush(), for parameter changes
20 /// without processing audio
21 ///
22 /// When the plugin changes a parameter value, it must inform the host.
23 /// It will send @ref CLAP_EVENT_PARAM_VALUE event during process() or flush().
24 /// If the user is adjusting the value, don't forget to mark the begining and end
25 /// of the gesture by sending CLAP_EVENT_PARAM_GESTURE_BEGIN and CLAP_EVENT_PARAM_GESTURE_END
26 /// events.
27 ///
28 /// @note MIDI CCs are tricky because you may not know when the parameter adjustment ends.
29 /// Also if the host records incoming MIDI CC and parameter change automation at the same time,
30 /// there will be a conflict at playback: MIDI CC vs Automation.
31 /// The parameter automation will always target the same parameter because the param_id is stable.
32 /// The MIDI CC may have a different mapping in the future and may result in a different playback.
33 ///
34 /// When a MIDI CC changes a parameter's value, set the flag CLAP_EVENT_DONT_RECORD in
35 /// clap_event_param.header.flags. That way the host may record the MIDI CC automation, but not the
36 /// parameter change and there won't be conflict at playback.
37 ///
38 /// Scenarios:
39 ///
40 /// I. Loading a preset
41 /// - load the preset in a temporary state
42 /// - call @ref clap_host_params.rescan() if anything changed
43 /// - call @ref clap_host_latency.changed() if latency changed
44 /// - invalidate any other info that may be cached by the host
45 /// - if the plugin is activated and the preset will introduce breaking changes
46 /// (latency, audio ports, new parameters, ...) be sure to wait for the host
47 /// to deactivate the plugin to apply those changes.
48 /// If there are no breaking changes, the plugin can apply them them right away.
49 /// The plugin is resonsible for updating both its audio processor and its gui.
50 ///
51 /// II. Turning a knob on the DAW interface
52 /// - the host will send an automation event to the plugin via a process() or flush()
53 ///
54 /// III. Turning a knob on the Plugin interface
55 /// - the plugin is responsible for sending the parameter value to its audio processor
56 /// - call clap_host_params->request_flush() or clap_host->request_process().
57 /// - when the host calls either clap_plugin->process() or clap_plugin_params->flush(),
58 /// send an automation event and don't forget to set begin_adjust,
59 /// end_adjust and should_record flags
60 ///
61 /// IV. Turning a knob via automation
62 /// - host sends an automation point during clap_plugin->process() or clap_plugin_params->flush().
63 /// - the plugin is responsible for updating its GUI
64 ///
65 /// V. Turning a knob via plugin's internal MIDI mapping
66 /// - the plugin sends a CLAP_EVENT_PARAM_SET output event, set should_record to false
67 /// - the plugin is responsible to update its GUI
68 ///
69 /// VI. Adding or removing parameters
70 /// - if the plugin is activated call clap_host->restart()
71 /// - once the plugin isn't active:
72 /// - apply the new state
73 /// - if a parameter is gone or is created with an id that may have been used before,
74 /// call clap_host_params.clear(host, param_id, CLAP_PARAM_CLEAR_ALL)
75 /// - call clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL)
76
77 static CLAP_CONSTEXPR const char CLAP_EXT_PARAMS[] = "clap.params";
78
79 #ifdef __cplusplus
80 extern "C" {
81 #endif
82
83 enum {
84 // Is this param stepped? (integer values only)
85 // if so the double value is converted to integer using a cast (equivalent to trunc).
86 CLAP_PARAM_IS_STEPPED = 1 << 0,
87
88 // Useful for for periodic parameters like a phase
89 CLAP_PARAM_IS_PERIODIC = 1 << 1,
90
91 // The parameter should not be shown to the user, because it is currently not used.
92 // It is not necessary to process automation for this parameter.
93 CLAP_PARAM_IS_HIDDEN = 1 << 2,
94
95 // The parameter can't be changed by the host.
96 CLAP_PARAM_IS_READONLY = 1 << 3,
97
98 // This parameter is used to merge the plugin and host bypass button.
99 // It implies that the parameter is stepped.
100 // min: 0 -> bypass off
101 // max: 1 -> bypass on
102 CLAP_PARAM_IS_BYPASS = 1 << 4,
103
104 // When set:
105 // - automation can be recorded
106 // - automation can be played back
107 //
108 // The host can send live user changes for this parameter regardless of this flag.
109 //
110 // If this parameters affect the internal processing structure of the plugin, ie: max delay, fft
111 // size, ... and the plugins needs to re-allocate its working buffers, then it should call
112 // host->request_restart(), and perform the change once the plugin is re-activated.
113 CLAP_PARAM_IS_AUTOMATABLE = 1 << 5,
114
115 // Does this parameter support per note automations?
116 CLAP_PARAM_IS_AUTOMATABLE_PER_NOTE_ID = 1 << 6,
117
118 // Does this parameter support per key automations?
119 CLAP_PARAM_IS_AUTOMATABLE_PER_KEY = 1 << 7,
120
121 // Does this parameter support per channel automations?
122 CLAP_PARAM_IS_AUTOMATABLE_PER_CHANNEL = 1 << 8,
123
124 // Does this parameter support per port automations?
125 CLAP_PARAM_IS_AUTOMATABLE_PER_PORT = 1 << 9,
126
127 // Does this parameter support the modulation signal?
128 CLAP_PARAM_IS_MODULATABLE = 1 << 10,
129
130 // Does this parameter support per note modulations?
131 CLAP_PARAM_IS_MODULATABLE_PER_NOTE_ID = 1 << 11,
132
133 // Does this parameter support per key modulations?
134 CLAP_PARAM_IS_MODULATABLE_PER_KEY = 1 << 12,
135
136 // Does this parameter support per channel modulations?
137 CLAP_PARAM_IS_MODULATABLE_PER_CHANNEL = 1 << 13,
138
139 // Does this parameter support per port modulations?
140 CLAP_PARAM_IS_MODULATABLE_PER_PORT = 1 << 14,
141
142 // Any change to this parameter will affect the plugin output and requires to be done via
143 // process() if the plugin is active.
144 //
145 // A simple example would be a DC Offset, changing it will change the output signal and must be
146 // processed.
147 CLAP_PARAM_REQUIRES_PROCESS = 1 << 15,
148 };
149 typedef uint32_t clap_param_info_flags;
150
151 /* This describes a parameter */
152 typedef struct clap_param_info {
153 // stable parameter identifier, it must never change.
154 clap_id id;
155
156 clap_param_info_flags flags;
157
158 // This value is optional and set by the plugin. The host will
159 // set it on all subsequent events regarding this param_id
160 // or set the cookie to nullptr if the host chooses to
161 // not implement cookies.
162 //
163 // The plugin must gracefully handle the case of a cookie
164 // which is nullptr, but can safely assume any cookie
165 // which is not nullptr is the value it issued.
166 //
167 // It is very strongly recommended that the host implement
168 // cookies. Some plugins may have noticably reduced
169 // performance when addressing params in hosts without cookies.
170 //
171 // The cookie's purpose is to provide a fast access to the
172 // plugin parameter objects. For instance:
173 //
174 // in clap_plugin_params.get_info
175 // Parameter *p = findParameter(param_id);
176 // param_info->cookie = p;
177 //
178 // later, in clap_plugin.process:
179 //
180 // Parameter *p{nullptr};
181 // if (evt->cookie) [[likely]]
182 // p = (Parameter *)evt->cookie;
183 // else
184 // p = -- alternate mechanism --
185 //
186 // where "alternate mechanism" is a mechanism the plugin implements
187 // to map parameter ids to internal objects.
188 //
189 // The host should make no assumption about the
190 // value of the cookie other than passing it back to the plugin or
191 // replacing it with nullptr.
192 //
193 // Once set, the cookie is valid until invalidated by a call to
194 // clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) or when the plugin is
195 // destroyed.
196 void *cookie;
197
198 // the display name
199 char name[CLAP_NAME_SIZE];
200
201 // the module path containing the param, eg:"oscillators/wt1"
202 // '/' will be used as a separator to show a tree like structure.
203 char module[CLAP_PATH_SIZE];
204
205 double min_value; // minimum plain value
206 double max_value; // maximum plain value
207 double default_value; // default plain value
208 } clap_param_info_t;
209
210 typedef struct clap_plugin_params {
211 // Returns the number of parameters.
212 // [main-thread]
213 uint32_t(CLAP_ABI *count)(const clap_plugin_t *plugin);
214
215 // Copies the parameter's info to param_info and returns true on success.
216 // [main-thread]
217 bool(CLAP_ABI *get_info)(const clap_plugin_t *plugin,
218 uint32_t param_index,
219 clap_param_info_t *param_info);
220
221 // Gets the parameter plain value.
222 // [main-thread]
223 bool(CLAP_ABI *get_value)(const clap_plugin_t *plugin, clap_id param_id, double *value);
224
225 // Formats the display text for the given parameter value.
226 // The host should always format the parameter value to text using this function
227 // before displaying it to the user.
228 // [main-thread]
229 bool(CLAP_ABI *value_to_text)(
230 const clap_plugin_t *plugin, clap_id param_id, double value, char *display, uint32_t size);
231
232 // Converts the display text to a parameter value.
233 // [main-thread]
234 bool(CLAP_ABI *text_to_value)(const clap_plugin_t *plugin,
235 clap_id param_id,
236 const char *display,
237 double *value);
238
239 // Flushes a set of parameter changes.
240 // This method must not be called concurrently to clap_plugin->process().
241 //
242 // Note: if the plugin is processing, then the process() call will already achieve the
243 // parameter update (bi-directionnal), so a call to flush isn't required, also be aware
244 // that the plugin may use the sample offset in process(), while this information would be
245 // lost within flush().
246 //
247 // [active ? audio-thread : main-thread]
248 void(CLAP_ABI *flush)(const clap_plugin_t *plugin,
249 const clap_input_events_t *in,
250 const clap_output_events_t *out);
251 } clap_plugin_params_t;
252
253 enum {
254 // The parameter values did change, eg. after loading a preset.
255 // The host will scan all the parameters value.
256 // The host will not record those changes as automation points.
257 // New values takes effect immediately.
258 CLAP_PARAM_RESCAN_VALUES = 1 << 0,
259
260 // The value to text conversion changed, and the text needs to be rendered again.
261 CLAP_PARAM_RESCAN_TEXT = 1 << 1,
262
263 // The parameter info did change, use this flag for:
264 // - name change
265 // - module change
266 // - is_periodic (flag)
267 // - is_hidden (flag)
268 // New info takes effect immediately.
269 CLAP_PARAM_RESCAN_INFO = 1 << 2,
270
271 // Invalidates everything the host knows about parameters.
272 // It can only be used while the plugin is deactivated.
273 // If the plugin is activated use clap_host->restart() and delay any change until the host calls
274 // clap_plugin->deactivate().
275 //
276 // You must use this flag if:
277 // - some parameters were added or removed.
278 // - some parameters had critical changes:
279 // - is_per_note (flag)
280 // - is_per_channel (flag)
281 // - is_readonly (flag)
282 // - is_bypass (flag)
283 // - is_stepped (flag)
284 // - is_modulatable (flag)
285 // - min_value
286 // - max_value
287 // - cookie
288 CLAP_PARAM_RESCAN_ALL = 1 << 3,
289 };
290 typedef uint32_t clap_param_rescan_flags;
291
292 enum {
293 // Clears all possible references to a parameter
294 CLAP_PARAM_CLEAR_ALL = 1 << 0,
295
296 // Clears all automations to a parameter
297 CLAP_PARAM_CLEAR_AUTOMATIONS = 1 << 1,
298
299 // Clears all modulations to a parameter
300 CLAP_PARAM_CLEAR_MODULATIONS = 1 << 2,
301 };
302 typedef uint32_t clap_param_clear_flags;
303
304 typedef struct clap_host_params {
305 // Rescan the full list of parameters according to the flags.
306 // [main-thread]
307 void(CLAP_ABI *rescan)(const clap_host_t *host, clap_param_rescan_flags flags);
308
309 // Clears references to a parameter.
310 // [main-thread]
311 void(CLAP_ABI *clear)(const clap_host_t *host, clap_id param_id, clap_param_clear_flags flags);
312
313 // Request a parameter flush.
314 //
315 // The host will then schedule a call to either:
316 // - clap_plugin.process()
317 // - clap_plugin_params.flush()
318 //
319 // This function is always safe to use and should not be called from an [audio-thread] as the
320 // plugin would already be within process() or flush().
321 //
322 // [thread-safe,!audio-thread]
323 void(CLAP_ABI *request_flush)(const clap_host_t *host);
324 } clap_host_params_t;
325
326 #ifdef __cplusplus
327 }
328 #endif