Parameter API Design Requirements

Plugin parameter support is achieved through remidy::PluginParameterSupport class which is accessible via parameters().

Parameter API Differences Between Formats

LV2 brings in the following design principles:

VST3 and CLAP brings in the following design principles:

Plain vs. Normalized

In VST3 every parameter operation is expected to be within 0.0–1.0, with conversion to and from normalized values. AU, LV2, and CLAP expect plain values.

The public API in PluginParameterSupport expects plain double values. They are explicitly named as such.

UAPMD needs to convert the values betwee double and uint32_t.

Normalized-to-Plain conversion is not always available

Whereas VST3 IEditController provides normalizedParamToPlain(), it is not always implemented correctly. VST3SDK EditController implements this function as to just return the source value by default.

Plugins like Dexed does not implement these functions while it converts parameters in 0.0..1.0 to the plain value when it is converted to string.

Automatable

We support only "automatable" parameters in some use cases. Namely, non-automatable parameters are not displayed on uapmd-app and not mapped to MIDI-CI AllCtrlList property.

For example, Tracktion "Collective" contains a lot of NonRealTime parameters that I have no idea what they are for (they are unnamed).

Sample-accurate Parameter Changes

All VST3, AU, LV2, and CLAP supports sample-accurate parameter changes. Those setParameter() calls that come with non-zero timestamp are "enqueued" for the next audio processing.

Per-Note Controllers (parameters)

VST3, AU, and CLAP supports per-note parameter controllers.

It should be noted that per-note controllers are defined totally differently from normal parameters. VST3, AU, and MIDI 2.0 UMP define them as such. The only exception is CLAP, which defines parameters in unified way. We return the same list of per-note parameters as normal parameters.

The way how VST3 and AU support per-note controllers (parameters) is different from CLAP also in that they may return different set of parameter definitions for each channel (also may differ from "global"). AU even goes further and they may return different set of parameter IDs for each note. This makes constructing static list of parameters at configuring connections almost impossible.

Extraneous CC roundtrip to parameters

One of the problem mapping from parameters to Assignable Controllers is that VST3 parameters are often mapped from MIDI CCs for each channel, due to fundamental VST3 design problem that does not support MIDI messages.

If we map every single parameter to Assignable Controller, it feels extraneous to further map them again. But CC-to-parameter mappings happen at plugin side, while Assignable Controllers to parameter mappings happen at the host side. We cannot guess which parameter should map to which CC to send (while we can "guess" by parameter names).

Dynamic parameter list updates

Some plugins dynamically updates their parameter list (e.g. BYOD VST3/AUv2/CLAP, AUv3 Mela, etc.) and when they happen the plugin typically have to be "restarted" by the host (e.g. IComponentHandler::restartComponent() in VST3, clap_host.request_restart() in CLAP).

The way how we trigger this component refresh should not be in the public API, but it is currently exposed as PluginParameterSupport::refreshAllParameterMetadata(). Each plugin format overrides it by triggering update events that are registered as in PluginParameterSupport::parameterMetadataChangeEvent members. It is exposed to the users (here its notify() should not also be exposed, likewise...).

We support the entire parameter refresh in uapmd-app.

LV2 partially supports this concept as Dynamic Manifest, but there does not seem any normative way to notify the manifest updates. It is also known to not work well.