VSTPluginController:
Filter:
Classes (extension) | Server > Abstractions

VSTPluginController : Object
ExtensionExtension

Client-side representation of a VSTPlugin UGen instance

Description

This class is used to control a specific VSTPlugin instance in a Synth, so you can open plugins, automate parameters, change programs, send MIDI messages, etc.

Have a look at the examples at the bottom!

Introduction

Here's a quick example showing a simple insert effect on a 2-channel audio bus:

If you have more than one instance of VSTPlugin in your SynthDef, you need to give them unique IDs so that VSTPluginController can find the right instance:

With JITLib you have to use VSTPluginNodeProxyController:

Parameter Automation

There are three different ways to automate plugin parameters (listed with increasing precedence):

Use -get and -getn to obtain current parameter values:

-set, -map and -get also accept parameter names instead of indices:

Preset Management

Select built-in FX programs with -program:

The easiest way to manage user presets are the -savePreset and -loadPreset methods. Because they use standardized preset folder locations, presets can be simply referred to by name:

Internally, preset files use the standard .fxp/.fxp (VST2) or .vstpreset (VST3) format, recognized by most DAWs and VST hosts. You can save presets to your own folders with the following methods:

It's also possible to get/set the raw plugin state as an Int8Array:

The data has the same binary format as the preset files. You can use these methods to build your own preset management!

GUI

Generally, there are two kind of GUIs:

Scheduling

Generally, synchronous methods, like -set or -map, simply send an OSC message to the Server. This is fine for interactive use, but if you need accurate timing, commands have to be scheduled as OSC bundles (see also Scheduling and Server timing).

Here are two basic ways how to schedule methods with Server latency:

Sequencing

VSTPlugin defines two custom Event types which can be used in Pbind, for example. Like with (most) other Event types, commands are scheduled as OSC bundles with Server latency.

\vst_set
sets one or more plugin parameters to the specified values; the interface is similar to \set.
\vstthe VSTPluginController instance
\paramsan Array of parameter names and/or indices which will be looked up in the Event

If you omit the \params argument, the play method will automatically try to look up parameters by name:

WARNING: This can be very inefficient for plugins with a large number of parameters! It is always better to explicitly specify the parameters you need with the \params argument

See Automation for more examples.

\vst_midi
send MIDI messages; the interface is very similar to \midi.
\vstthe VSTPluginController instance
\midicmdthe MIDI method (see below)
\chanthe MIDI channel; the default is 0
\midinoteMIDI pitch for \noteOn, \noteOff and \polyTouch
\ampamplitude (0.0 - 1.0) for \noteOn and \noteOff
\ctlNumCC number for \control
\controlCC value for \control
\valvalue argument for \touch and \bend
\polyTouchtouch value for \polyTouch
\progNumprogram number for \program
\arrayUInt8Array for \sysex

The default value for \midicmd is \noteOn, with \noteOff commands being scheduled automatically. Other possible values are \noteOff, \control, \bend, \touch, \polyTouch, \program, \allNotesOff and \sysex. The commands correspond to the methods listed in VSTPluginMIDIProxy.

NOTE: Always prefer \vst_midi over \midi because the latter doesn't schedule OSC bundles!

See VST Instruments for examples.

Tip: You can play Pbinds of type \vst_midi and \vst_set in parallel with Ppar.

Realtime Safety

VSTPlugin tries its best to be as realtime safe as possible. Plugins are always opened/closed asynchronously in the NRT thread. Some methods, like -loadPreset and -savePreset, offer two options via the async parameter:

  1. async: true means that the plugin method is called on the NRT resp. UI thread and will never block the Server. However, plugin processing is temporarily suspended and you can't call other methods until the command has finished.
  2. async: false means that the plugin method is simply called on the RT thread. The advantage is that the command is performed synchronously and plugin processing doesn't have to be suspended. Depending on the plugin, this might be just fine - or block the Server. You have to test yourself!
NOTE: If the plugin is opened with the VST GUI editor, the async option is automatically set to true because of thread safety concerns.

Class Methods

VSTPluginController.new(synth, id, synthDef, wait: -1)

Create a new VSTPluginController for a given Synth.

Arguments:

synth

the Synth containing the VSTPlugin you want to control.

id

a Symbol which uniquely identifies the VSTPlugin in the SynthDef.

NOTE: If this is the only VSTPlugin instance in the SynthDef, the id argument can be omitted.
synthDef

the synth's SynthDef. You can omit this argument if the SynthDef has been added to the global SynthDescLib, e.g. with SynthDef: -add or SynthDef: -store. In this case, the SynthDef will be automatically deduced from the synth argument.

wait

the default wait time, see -wait.

Discussion:

Initially, no VST plugin is loaded and the UGen is automatically bypassed (i.e. the input is just passed through).

VSTPluginController.collect(synth, ids, synthDef, wait: -1)

Same as -new, but returns an Event of VSTPluginControllers, with their IDs used as keys. This is useful if you have a SynthDef containing several VSTPlugin instances.

Arguments:

synth

the Synth, see -new

ids

an Array of IDs referring to VSTPlugin instances in the SynthDef, or nil (= collect all).

synthDef

the SynthDef (optional), see -new

wait

the default wait time, see -wait.

Discussion:

Inherited class methods

Undocumented class methods

VSTPluginController.prCollect(plugins, ids, fn)

Instance Methods

.open(path, editor: true, verbose: false, action, multiThreading: false, mode)

open a VST plugin.

Arguments:

path

the plugin key or file path.

- Opening plugins by key requires that the plugin has already been probed (e.g. as a result of VSTPlugin: *search).

- Alternatively, you can use a file path (with or without extension). Relative paths are resolved to the standard VST directories (see VSTPlugin: *search); this is done recursively, which means you don't necessarily have to specify any subfolders.

NOTE: This method only works for files which contain a single plugin (all VST 2.x plugins - except for shell plugins - and many VST 3 plugins).

- If the VSTPlugin UGen holds a plugin description (see VSTPlugin: *ar), the path argument can be deduced and therefore omitted.

editor

enable/disable the VST plugin editor.

NOTE: On macOS this only works with SuperCollider 3.11 and above!
NOTE: Some (buggy) plugins don't work correctly without the VST editor.
verbose

post the plugin info to the console if loaded successfully.

action

an action to be called with this and a Boolean (success/fail).

multiThreading

process the plugin in a seperate worker thread to utilize more CPU cores.

NOTE: This option is ignored for Supernova, which already offers multithreading with ParGroup.

NOTE: Multithreading introduces a delay of 1 block!
mode

select a run mode.

\autonormal mode (default).
\sandboxrun the plugin in a dedicated subprocess. This means that the plugin can safely crash without taking down the whole Server! This is useful for buggy plugins or safe experimentation.
\bridgerun the plugin in a shared subprocess. This uses less memory and possibly less CPU, but if one plugin crashes, it will inevitably take down all other plugins in the same process.

NOTE: All run modes except for \auto incur some fixed CPU overhead, which is less significant for larger blocksizes (see ServerOptions: -blockSize or the blockSize argument in VSTPlugin: -ar).

See also VSTPlugin: Bridging and Sandboxing.

Discussion:

This method is realtime-safe because the VST plugin is opened asynchronously (in the NRT thread).

.openMsg(path, editor: false, multiThreading: false, mode)

Arguments:

path

the plugin name/key or file path. Relative paths are resolved to the standard VST directories.

If the VSTPlugin UGen holds a plugin description (see VSTPlugin: *ar), the path argument can be deduced and therefor ommitted.

editor

request the VST editor.

multiThreading

enable multithreading.

mode

select a run mode.

Returns:

the message for an open command (see -open).

.close

.closeMsg

close the current plugin (but don't free the Synth!). You can open another plugin later.

Discussion:

This will automatically bypass the plugin (i.e. the input is just passed through).

Just like -open, this method is realtime-safe.

.pluginCrashed

.pluginCrashed = value

a Function or FunctionList to be called when the plugin subprocess crashes.

Discussion:

You could use this callback to automatically reopen the plugin, for example.

NOTE: This is only meant for bridged or sandboxed plugins, because a normal plugin would simply crash the server.

.browse

open the plugin browser dialog.

.editor(show: true)

.editorMsg(show: true)

show/hide the VST editor window.

Discussion:

The plugin has to be opened with editor: true.

NOTE: On macOS this only works on SuperCollider 3.11 and above!

.moveEditor(x, y)

.moveEditorMsg(x, y)

move the editor window to the given position.

.resizeEditor(w, h)

.resizeEditorMsg(w, h)

resize the editor window to the given width and height.

NOTE: This only works for VST3 plugins with a resizable editor.

.gui(parent, bounds, params: true)

creates a generic Qt GUI (see VSTPluginGui).

Arguments:

parent

the parent. If nil, the GUI is created in a new toplevel window.

bounds

the bounds.

params

show/hide parameters. Set to false, if you only need to show the preset manager!

Returns:

a new VSTPluginGui instance.

.info

.info = value

Returns:

the (static) plugin description (see VSTPluginDesc).

.loaded

Returns:

whether a plugin is currently loaded.

.latency

Returns:

the current processing latency in samples.

NOTE: The reported value includes the additional latency caused by multithreading and reblocking (see the multiThreading and blockSize arguments for -open).

.latencyChanged

.latencyChanged = value

a Function or FunctionList to be called when the plugin's processing latency changes. The function receives the new latency as its only argument. See also -latency.

.reset(async: false)

.resetMsg(async: false)

reset the plugin state.

Arguments:

async

see Realtime Safety.

Discussion:

Depending on the plugin, reset can involve expensive operations, like clearing a large delay line, and might not be realtime-safe, so be careful with setting async to false.

.setOffline(bool)

.setOfflineMsg(bool)

enable/disable offline processing.

Discussion:

In non-realtime (NRT) synthesis, some VST plugins don't render correctly unless you explicitly put them into offline processing mode. Some plugins also render at a higher quality in offline mode than in realtime mode.

On the other hand, with a few buggy plugins, certain plugin methods only work correctly in realtime mode, so you have to switch modes accordingly.

For an example, see VSTPluginController: Non-Realtime Synthesis.

.synth

.synth = value

Returns:

the Synth containing the currently controlled VSTPlugin instance.

.synthIndex

.synthIndex = value

Returns:

the index of the VSTPlugin instance within the Synth.

.wait

.wait = value

the wait time between OSC messages (in seconds).

Discussion:

-1 allows an OSC roundtrip between packets.

0 is not safe with UDP, but is probably ok with TCP.

Some methods may require lots of OSC messages (e.g. when changing programs, the UGen has to send the new state of all parameters). VSTPluginController waits for the given time after a certain number of bytes to avoid messages getting dropped. This is mostly relevant for UDP connections, especially for remote Servers, high network traffic and plugins with a large number of parameters.

The wait time can be changed anytime.

Parameters

.numParameters

Returns:

the number of parameters.

.set( ... args)

.setMsg( ... args)

Set plugin parameters.

Discussion:

This method expects pairs of parameter index/name and value. Each value should be either a number between 0.0 and 1.0 or a string/symbol.

NOTE: Some plugins don't support setting parameters by strings, others only allow it for certain parameters.

NOTE: The parameter(s) will be automatically unmapped from any control bus, see -map.

With setMsg you can schedule sample accurate parameter changes for plugins which support this (some, but not all VST3 plugins).

.setn( ... args)

.setnMsg( ... args)

set sequential ranges of parameters.

Discussion:

This method expects pairs of parameter index and Array of values (numbers or strings/symbols), see -set.

.map( ... args)

map parameters to control or audio busses.

Discussion:

This methods expects pairs of parameter index/name and bus. In case of multi-channel busses the channels are mapped to a sequential range of parameters starting at the given index/name.

The bus argument can be simply an integer referring to a control bus. If you want to map an audio bus, you have to explicitly pass an audio Bus object.

Parameters are updated whenever the data in the bus changes.

NOTE: Only map to an audio bus if you need sample accurate automation and the plugin actually supports it (some, but not all VST3 plugins).

Each parameter can only be mapped to one control bus channel at the time.

NOTE: setting a parameter with -set or -setn will automatically unmap it from any control bus.
NOTE: map will override automation via UGen arguments.

.mapMsg( ... args)

returns a bundle containing control and/or audio bus mapping messages. Takes the same arguments as map.

.mapn( ... args)

.mapnMsg( ... args)

map parameters to control busses. The arguments are triples of parameter index/name, control bus index and number of channels. See map.

.mapan( ... args)

.mapanMsg( ... args)

map parameters to audio busses. The arguments are triples of parameter index/name, audio bus index and number of channels. See map.

.unmap( ... args)

.unmapMsg( ... args)

Unmap parameters from a control bus.

Discussion:

Pass all the parameters you want to unmap. Calling the method without arguments will unmap all parameters.

.get(index, action)

get the current value of a plugin parameter.

Arguments:

index

the index/name of the parameter.

action

an action to be evaluated with the value passed as an argument.

Discussion:

.getn(index: 0, count: -1, action)

get a sequential range of parameter values.

Arguments:

index

the starting index/name.

count

the number of sequential parameter values. -1 will return all parameters starting from index.

action

an action be evaluated with the values passed as an Array.

Discussion:

.parameterAutomated

.parameterAutomated = value

a Function or FunctionList to be called when parameters are automated in the VST editor.

Discussion:

The action receives the parameter index and value. This can be helpful if you want to know the index of a parameter in the editor.

NOTE: Some plugins link parameters, so that changing one parameter will lead to several other parameters being "automated". In that case it is not possible to determine which parameter has been automated manually.

.parameterCache

An Array containing the current state ([value, display]) of each parameter. Only valid if a plugin is currently loaded!

Programs

VST plugins often contain factory presets which are called programs.

NOTE: Some VST2 plugins allow to change the name and state of the built-in programs and save all programs as a bank file (see -writeBank).

.numPrograms

Returns:

the number of available built-in plugin programs.

.program

.program = number

.programMsg(number)

select a built-in program or get the current program number.

.programName

.programName = name

.programNameMsg(name)

get/set the name of the current program (VST2 only).

.programCache

An Array containing the current name of each program. Only valid if a plugin is currently loaded!

Presets

Simple preset management.

Presets are stored at pre-defined file system locations, so they can be simply referred to by name or index (see VSTPluginDesc: -presets).

NOTE: Since the VST3 preset locations are actually standardized, any VST3 presets created with VSTPlugin should be available in other applications and vice versa.
WARNING: This only works with local Servers (for now)!

.loadPreset(preset, action, async: true)

.savePreset(preset, action, async: true)

load/save VST presets.

Arguments:

preset

a preset Event, name or index (see VSTPluginDesc: -presets).

You can create a new preset by passing a non-existing preset name to savePreset.

action

an action which is called with this and a Boolean (success/fail).

async

where to perform the plugin method, see Realtime Safety.

NOTE: The file IO itself is always performed asynchronously!

.loadPresetMsg(preset, async: true)

Create an OSC message for loading a preset. See also -readProgramMsg.

NOTE: There is no equivalent savePresetMsg method because we wouldn't be able to update the preset list.

Arguments:

preset

a preset Event, name or index (see VSTPluginDesc: -presets).

async

see above.

.deletePreset(preset)

delete a VST preset.

Arguments:

preset

the preset Event, name or index.

Returns:

true on success or false on failure.

.renamePreset(preset, name)

delete a VST preset.

Arguments:

preset

the old preset Event, name or index

name

the new preset name.

Returns:

true on success or false on failure.

.preset

Returns:

the current preset (Event) or nil (= no preset).

Preset Files

Read/write VST2 .fxp/.fxb files or VST3 .vstpreset files.

This is useful if you want to save your presets to a non-standard location, e.g. relative to your project.

The preset files are in a standard format which is recogized by every decent DAW or VST host. This means you can freely exchange presets between different applications!

.readProgram(path, action, async: true)

.writeProgram(path, action, async: true)

read/write program files.

Arguments:

path

an absolute file path.

The file extension is arbitrary but it is good practice to use .fxp for VST2 program files and .vstpreset for VST3 preset files.

action

an action to be called with this and a Boolean (success/fail).

async

where to perform the plugin method, see Realtime Safety.

NOTE: The file/buffer IO itself is always performed asynchronously!

.writeBank(path, action, async: true)

.readBank(path, action, async: true)

same as above, but for VST2 .fxb bank files.

.readProgramMsg(dest, async: true)

.writeProgramMsg(dest, async: true)

Create an OSC message for reading/writing a program file, or exchanging program data via a Buffer.

Arguments:

dest
Stringpreset file to be read or written.
Buffer or Integerexchange program data between a Client and a (remote) Server via a Buffer.

readProgramMsg: the Buffer should contain the preset data with each float representing a single byte; it has to be allocated and freed by the Client.

writeProgramMsg: the Buffer should be initially empty. The UGen will fill the Buffer on the Server, the Client can then read the data and free the Buffer.

async

see above.

Returns:

the OSC message.

.readBankMsg(dest, async: true)

.writeBankMsg(dest, async: true)

same as above, but for VST2 .fxb bank files.

Preset Data

Set/get the raw plugin state. This is useful if you want to build your own custom preset system.

NOTE: The Bank methods only work with VST2 plugins.

.setProgramData(data, action, async: true)

.setBankData(data, action, async: true)

set the new program/bank state as an Int8Array.

Arguments:

data

the raw plugin data.

action

an action to be called with this and a Boolean (success/fail).

async

where to perform the plugin method, see Realtime Safety.

NOTE: The data transfer itself is always performed asynchronously!

.getProgramData(action, async: true)

.getBankData(action, async: true)

get the current program/bank state as an Int8Array.

Arguments:

action

an action to pass the data - or nil if the method failed.

async

see above.

Discussion:

Internally, the program data is exchanged via temp files.

WARNING: This only works with a local Server!

.sendProgramData(data, wait, action, async: true)

.sendBankData(data, wait, action, async: true)

send the new program/bank state as an Int8Array.

Arguments:

data

the raw plugin data.

wait

temporarily overwrites -wait if not nil.

action

an action to be called with this and a Boolean (success/fail).

async

where to perform the plugin method, see Realtime Safety.

NOTE: The data transfer itself is always performed asynchronously!

.receiveProgramData(wait, timeout: 3, action, async: true)

.receiveBankData(wait, timeout: 3, action, async: true)

receive the current program/bank state as an Int8Array.

Arguments:

wait

temporarily overwrites -wait if not nil.

timeout

the number of seconds to wait before giving up.

action

an action to pass the data.

async

see above.

Discussion:

Contrary to -setProgramData, -getProgramData etc., the methods above also work with remote Servers because the data is streamed via OSC messages. This means it is not 100% reliable when using UDP.

MIDI

.midi

MIDI interface for VSTPluginController.

Returns:

an instance of VSTPluginMIDIProxy.

.sendMidi(status, data1: 0, data2: 0, detune)

.sendMidiMsg(status, data1: 0, data2: 0, detune)

send a raw MIDI message with 2-3 bytes (status, data1, data2) and an optional detune argument in cent (not supported by all VST instruments!). MIDI messages can be scheduled sample accurately when sent as bundles!

.sendSysex(msg)

.sendSysexMsg(msg)

send a system exclusive message as an Int8Array.

.midiReceived

.midiReceived = value

a Function or FunctionList to be called when receiving MIDI messages from the plugin.

Discussion:

The 3 bytes of the MIDI message are passed as invidual arguments:

.sysexReceived

.sysexReceived = value

a Function or FunctionList to be called when receiving SysEx messages from the plugin.

Discussion:

The SysEx data is passed to the action as an Int8Array.

Transport

.setPlaying(b)

.setPlayingMsg(b)

set the transport playing state to true or false. Only necessary for VST plugins which do some kind of sequencing.

WARNING: Transport playback is disabled by default!

.setTempo(bpm: 120)

.setTempoMsg(bpm: 120)

set the tempo in BPM (beats per minute).

.setTimeSignature(num: 4, denom: 4)

.setTimeSignatureMsg(num: 4, denom: 4)

set the time signature, e.g. 3/4 -> num = 3, denom = 4.

.setTransportPos(pos)

.setTransportPosMsg(pos)

set the current transport position (in quarter notes).

.getTransportPos(action)

get the current transport position (in quarter notes).

Arguments:

action

will be called with current transport position.

VST2 only

.canDo(what, action)

query the plugin for special capabilities.

Arguments:

what

a string describing the capability. Some of these are documented in the VST SDK, but others are not.

action

will be called with an Integer result.

1yes
-1no
0don't know

.vendorMethod(index: 0, value: 0, ptr, opt: 0.0, action, async: true)

.vendorMethodMsg(index: 0, value: 0, ptr, opt: 0.0, action, async: true)

Access special functionality of a plugin which is not available via the standard parameter interface. Check the documentation of the plugin to see what kind of data it expects.

Arguments:

index

an Integer.

value

an Integer.

ptr

some arbitrary data as an Int8Array.

opt

a Float.

action

will be called with an Integer result. The meaning depends on the VST plugin.

async

see Realtime Safety.

Inherited instance methods

Undocumented instance methods

.addDependant(dependant)

.haveEditor

.makeMsg(cmd ... args)

.sendMsg(cmd ... args)

.update(who, what ... args)

Examples

The following code is needed for most examples:

Serial FX chains

How to build a serial FX chain on an audio bus:

You can also create fixed FX chains by using several VSTPlugins inside a SynthDef:

Master FX section

This is how you would create a simple master FX section:

Automation

Automate parameters via control busses

NOTE: Parameter automation will not be visible in the Qt GUI (due to performance reasons)

Automate parameters inside the SynthDef:

Automate parameters with a Pbind of type \vst_set:

VST Instruments

You can easily play VST instruments with a Pbind of event type \vst_midi:

Non-Realtime Synthesis

Many methods of VSTPluginController have a corresponding *Msg version, returning a Server message which can be added to a Score for non-realtime synthesis.

The following code snippet will create a short soundfile with two random melodies played by VST instruments and processed with VST effects; it can be executed in a single block.