VST 3 Interfaces  VST 3.6.14
SDK for developing VST Plug-in
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Groups Pages
Parameters and Automation

All parameter changes of a processing block.


  • Up to 2^31 parameters can be exported [0, 2147483648] (the range [2147483649, 429496729] is reserved for host application). Steinberg::Vst::IEditController::getParameterCount allows host to ask the Plug-in its count of exported parameters. The Plug-in has to assign a unique 32-bit identifier to each exported parameter. Please note that it is not allowed to change this assignment at any time. In particular a Plug-in must not perform any reconfigurations that lead to a different set of automatable parameters. The only allowed variation is to add or remove parameters in a future Plug-in version, but keep in mind that automation data can get lost when parameters are removed.

  • Usually the host is unaware of a parameter's semantics. However there are a few important exceptions that the controller has to announce using the Steinberg::Vst::ParameterInfo::flags :
    • Bypass : If the Plug-in performs bypass processing itself, it has to export an according parameter and flag it with kIsBypass. It is highly recommended that this bypass parameter is provided by Effect Plug-in. If the Plug-in does not export such a parameter, the host could perform bypass processing and the Plug-in process call will be discontinued. Only one bypass parameter is allowed. The Plug-in should save the state of this bypass parameter like other parameters (when getState and setState are used)
    • Program : If the Plug-in supports program lists (see Units), each 'unit' of the Plug-in needs to export a program selector parameter. Such parameter is not allowed to be automated when the affected parameters are flagged as automatable as well. A host can display program parameters at exposed locations of its GUI.

  • The controller must support the conversion to a string for any exported parameter. The conversion method Steinberg::Vst::IEditController::getParamStringByValue must provide a result for any possible normalized parameter value.

  • Parameter values are always transmitted in a normalized floating point (64bit double) representation [0.0, 1.0].
Representation of parameter values
A Plug-in parameter usually has more than one representation. The GUI of a Plug-in can display something that appears to be a single parameter, but it might control multiple processing parameters at the same time. Or the GUI representation displays a scale-transformed representation of a DSP-parameter.

Somewhere on the way from the GUI to the DSP-algorithm this transformation has to be performed. The host does not and must not know anything about DSP-parameters, but it is responsible for reporting parameter changes to the processor. According to this, the processor is the only place where a transformation can happen and all parameters always have to match the GUI representation.

Does this fit into the idea of separating GUI and processing? No problem so far - it is a separation of duties, nothing more. The processor component and the controller component have to work on the same internal Plug-in model. The controller knows how this model has to be presented in GUI. The processor knows how the model has to be translated into DSP-parameters.
The VST 3 interfaces suggest a normalized value representation for the a part of this model (the part that is exported as parameters). This means every value has to be inside the range from 0.0 to 1.0.
Parameter styles / 'Step Count'
Although values are transmitted in a normalized format, the host needs to know some details of the parameter's displayed GUI representation. When editing automation data for example, the host must know the nature of a parameter expressed in its 'step count' (see Steinberg::Vst::ParameterInfo::stepCount).

Step count semantics :
  • 0 : A continuous parameter. Any normalized value has an exact mapping (0 = there are no steps between the values)
  • 1 : A discrete parameter with 2 states like [on/off] [yes/no] etc. (1 = there is one step between these states)
  • 2 : A discrete parameter with 3 states [0,1,2] or [3,5,7] (2 = there are two steps between these states)
  • 3 : etc...
Conversion of normalized values
The controller and the processor have to deal with normalized parameter values.
  • Step count 0 : Continuous parameters simply need to be mapped accordingly
  • Step count n : Discrete parameters need a little bit more care
    • Normalize:
      double normalized = discreteValue / (double) stepCount;
    • Denormalize :
      int discreteValue = min (stepCount, normalized * (stepCount + 1));

Example: Step Count 3


A host that supports parameter automation is dependent on a proper cooperation of the component owning these parameters. One intention in the design of the VST 3 interfaces was to reduce the amount of possible mistakes for an implementation. The separation of processor and controller enforces that all parameter changes have to be handled by the host in a defined way. And additionally this way allows the host to store the changes as automation data. Nevertheless there are some more things to consider:

No automated parameter must influence another automated parameter

The prime example for this is the automation of preset changes. A preset change can lead to the change of all 'normal' parameters. So if automation data already has been recorded for these parameters and the preset change is recorded as well: who wins? This question can not be answered and the problem can only be resolved by avoiding it. This is why automation of preset changes is not allowed by default.


A fix value range from 0.0 to 1.0 simplifies the handling of parameters in some ways, but there are problems:

  • Non-linear Scaling
    If the DSP representation of a value does not scale in a linear way to the exported normalized representation (which can happen when a decibel scale is used for example), the edit controller must provide a conversion to a plain representation. This allows the host to move automation data (being in GUI representation) and keep the original value relations intact. (Steinberg::Vst::IEditController::normalizedParamToPlain / Steinberg::Vst::IEditController::plainParamToNormalized).

  • Changes in future Plug-in versions
    Take a discrete parameter for example that controls an option of three choices. If the host stores normalized values as automation data and a new version of a Plug-in invented a fourth choice, the automation data will be invalid now. So either the host has to store denormalized values as automation or it must recalculate the automation data accordingly.

Automation Recording

Automation recording is performed by the host of course. In doing so it is essential for the host to know the start and the end of a manipulation. Therefore the Plug-in must operate the Steinberg::Vst::IComponentHandler interface in the following way:

Sliders & Knobs
These kind of controls usually control continuous parameters and they are usually operated using the mouse. This common case is most simple to handle: On mouse-click-down call beginEdit (followed by performEdit when the control allows a jump), on mouse-drag call performEdit and on mouse-click-up call endEdit.

Trouble starts with the Mouse wheel: There simply is nothing like a defined start or end when the wheel is operated - each wheel event arrives out of the blue. The only way to enable proper automation recording in this case is the usage of a timer.

  • A dutiful Plug-in implementation should call beginEdit when the first wheel event is handled and start a timer (followed by the first call to performEdit). Further wheel events that arrive inside of the timeout interval are reported with performEdit and the timer is restarted. When the timeout period has passed without further events endEdit should be called and the timer can be removed.

  • But since it is the host's task to record automation data, one can say that it shall be the host's task to care about the timer in this case as well. This is the reason for the exception to the rule:

Mouse wheel events can be reported without beginEdit and endEdit to the host. The host must be prepared to receive a performEdit without a previous call of beginEdit for a parameter and handle the timeout itself.
Buttons / Radio Groups / Popup Menus
These kind of controls usually control discrete parameters and simply switch the state of something. A proper handling is to call beginEdit, performEdit and endEdit in a row. The affected parameter has to be exported to the host with the correct step count since discrete parameters have to be handled differently than continuous parameters in regard to automation.

Mouse wheel handling usually is not supported for buttons, but sometimes for pop-up menus. Discrete parameters do not require the usage of a timer in order to be recorded correctly.

So the Plug-in should call the 3 functions in a row for each wheel event - again the other option is to omit beginEdit and endEdit, only make sure to report the discrete nature of the parameter to the host correctly.
Text Input
For reporting the results of any text input value change, regardless if a continuous or a discrete parameter is affected, always call beginEdit, performEdit and endEdit in a row.

Automation Playback

In VST 3, automation playback is the task of the Plug-in and it is the host's task to provide the automation data. The only way for a parameter change to arrive in the processor is the processing call. Indeed, receiving parameter changes from the edit controller and playing back automation data is one and the same thing.
Of course the need to do all transformations from the normalized GUI representation to the DSP representation produces some overhead. Performing sample accurate automation requires even more overhead, since the DSP value must be calculated for each single sample. While this can not be avoided totally, it is the choice of the Plug-in implementation of how much processing time should be spent on automation accuracy. The host always transmits value changes in a way that allows a sample accurate reconstruction of the underlying automation curve. The Plug-in is responsible for the realization.

GUI playback
The host is responsible for updating the Plug-in GUI when automation data is transmitted to the processor. This is realized by frequent calls of Steinberg::Vst::IEditController::setParamNormalized.

- [host imp]

  • [released: 3.0.0]
  • [mandatory]

This interface is used to transmit any changes that shall be applied to parameters in the current processing block. A change can be caused by GUI interaction as well as automation. They are transmitted as a list of queues (IParamValueQueue) containing only queues for parameters that actually did change.

See also
IParamValueQueue, ProcessData

Queue of changes for a specific parameter.
  • [host imp]
  • [released: 3.0.0]
  • [mandatory]

The change queue can be interpreted as segment of an automation curve. For each processing block a segment with the size of the block is transmitted to the processor. The curve is expressed as sampling points of a linear approximation of the original automation curve. If the original already is a linear curve it can be transmitted precisely. A non-linear curve has to be converted to a linear approximation by the host. Every point of the value queue defines a linear section of the curve as a straight line from the previous point of a block to the new one. So the Plug-in can calculate the value of the curve for any sample position in the block.

Implicit Points:
In each processing block the section of the curve for each parameter is transmitted. In order to reduce the amount of points, the point at block position 0 can be omitted.

  • If the curve has a slope of 0 over a period of multiple blocks, only one point is transmitted for the block where the constant curve section starts. The queue for the following blocks will be empty as long as the curve slope is 0.
  • If the curve has a constant slope other than 0 over the period of several blocks, only the value for the last sample of the block is transmitted. In this case the last valid point is at block position -1. The processor can calculate the value for each sample in the block by using a linear interpolation:
    double x1 = -1; // position of last point related to current buffer
    double y1 = currentParameterValue; // last transmitted value
    int32 pointTime = 0;
    ParamValue pointValue = 0;
    IParamValueQueue::getPoint (0, pointTime, pointValue);
    double x2 = pointTime;
    double y2 = pointValue;
    double slope = (y2 - y1) / (x2 - x1);
    double offset = y1 - (slope * x1);
    double curveValue = (slope * bufferTime) + offset; // bufferTime is any position in buffer

A jump in the automation curve has to be transmitted as two points: one with the old value and one with the new value at the next sample position.

See also
IParameterChanges, ProcessData

Back to Contents


Copyright ©2019 Steinberg Media Technologies GmbH. All Rights Reserved. This documentation is under this license.