DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

params.h (12910B)


      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