Tuesday, September 04, 2007

Redesigning the Steinberg VST SDK

This post proposes a new structure for the Steinberg VST SDK.

Steinberg's Virtual Studio Technology (VST) represents a plugin interface that allow third-party plugins to run inside a host, for instance Cubase. There are a lot of hosts that support the VST interface and there are a lot of plugin's these days.

Steinberg provides a C++ SDK in two parts. The Interface (files) declare the common ground between the host and the plugin. Then there are a couple of C++ classes that are built on top of these interfaces and allow a custom plugin to derive from an SDK-provide base class. We're not going to talk about the GUI classes here.

The Interface cannot be changed for obvious reasons. The structure of the base classes provided by the SDK is very simplistic. They just defined all functionality on one base class -assuming a plugin would consist of one root class were all features are implemented. Also, there are some methods on the base class that should be called in the constructor and nowhere else.

The VST communication between host and plug-in is basically done through callback procedures (much like a window procedure) although the plugin provides a structure with some additional information at start-up.

While I was looking into how to interop the VST plug-in Interface (version 2.4) with the managed .NET framework I also started to sketch out a new structure for the managed VST interface(s) (yes, I know there is a managed VST implementation called noise).

There were several design principles that I used:
  • Allow the plug-in design to be more flexible
    Don't force everything to be in one (base) class.
  • Group related functionality together
    Use the single responsibility principle.
  • Communicate capabilities (canDo's) via implemented interfaces
    Define interfaces for canDo's and their associated methods. Other capabilities are communicated through a property.

The Plug-in
The functionality of the plug-in is devided in several interfaces. These interfaces are implemented by the plug-in and called by the interop framework.

IVstPlugin
This interface exposes basic plugin functionality without regard to the actual purpose of the plugin (synth, effect or midi processor).

  • Open / Close
    Opens and Closes the Plug-in. Basically to allocate and clean-up resources (memory).
  • Suspend / Resume
    Suspends and Resumes plug-in processing.
  • Parameters
    A structured Parameter (collection) exposing the plug-in's parameters.

IVstAudioProcessor (IVstAudioPrecissionProcessor)
The audio processor interface is implemented by the plug-in that has Audio capabilities. The precission processor receives audio channels that represent doubles in stead of singles (float).

  • BlockSize / SampleRate
    These properties are set by the host (indirectly) and used in audio processing.
  • Process
    The Process method takes an IAudioChannel collection for both input channels and output channels.

IVstMidiProcessor
The Midi processor interface is implemented by the plug-in that processes incoming Midi events. Outgoing Midi events are implemented at the host throught this interface.

  • Process
    The process method takes a VstEventsCollection that contain VstMidiEvent instances.

IVstPluginBuilder
The plug-in builder interface exposes the different aspects if the plug-in. It is up to the implementation of the builder (and the plug-in) to decide how these request are resolved.

  • GetPlugIn
    Returns the IVstPlugIn implementation (not null).
  • GetAudioProcessor / GetMidiProcessor
    Returns the IVstAudioProcessor and the IVstMidiProcessor implementations (or null).
  • GetPlugInEditor
    Returns the custom editor (interface not discussed) for the plug-in (or null).

The Host
The host functionality is seperated into several interfaces (as well). These interfaces are implemented by the interop framework and can be called by the plug-in.

IVstHost
The main interface representing the VST host.

  • Product / Vendor / Version
    Information about the host implementation.
  • Sequencer
    Provides access to an implementation of the IVstHostSequencer interface.
  • Shell
    Provides access to an implementation of the IVstHostShell interface.

IVstHostSequencer
The sequencer interface provides access to the host's sequencing functionality.

  • Capabilities / Input- & OutputLatency
    Provides information on the capabilities of the host.
  • GetTime
    Retrieves the current time (song pointer).
  • UpdatePlugInIO
    Indicates to the host that the plug-in has changed it's IO channels.

IVstHostShell
The shell interface provides access to the host's UI.

  • BaseDirectory
    Installation directory of the host.
  • Culture
    Host language information.
  • EditParameter
    Launches the edit parameter screen.
  • OpenFileSelector
    Launches the open file dialog.
  • SizeWindow / UpdateDisplay
    Resizes and updates the host's main window.

Feedback please
I know not all features of the VST SDK (version 2.4) are covered here but the general idea should be explained. I would really like to hear your opinion on this way of structuring the VST functionality.

2 comments:

Anonymous said...

The precission processor receives audio channels that represent doubles in stead of singles

I think that the precision/speed trade offs usually favor single precision.

obiwanjacobi said...

This post is also discussed on the KVR Audio (forum).