REAPERAudio Production Without Limits
About : Download : Purchase : Manual : Forum : Resources : REAPER Radio!
REAPER VST Notes and Extensions Reference

Note to plug-in developers: implement support for these APIs to encourage host developers to add support for it.

Note to host developers: implement these APIs to encourage plug-ins to support them.

Introduction

REAPER supports VST plug-ins (up to version 2.4). VST is a standard defined by Steinberg Media Technologies GMBH. To get the VST SDK (which you will need to implement VST plug-ins), you will need to download it from Steinberg, as we cannot distribute it.

It is worthwhile noting that while VST is a standard, it is neither an open standard (the fact that you cannot easily distribute the SDK or things derived from it), nor is it a well defined standard.

This document will describe some REAPER-specific implementation notes for VST, as well as list some REAPER-specific VST extensions that plug-in developers are encouraged to use to acheive great integration with REAPER. Additionally, we encourage other VST host developers to add support for these extensions, as we believe they are useful.


VST Implementation Notes

REAPER currently implements a subset of the VST 2.4 standard as well as additional extensions-- this section discusses the former.

  • Audio/sample processing: REAPER will use processDoubleReplacing if effFlagsCanDoubleReplacing is set in the flags.
    REAPER will use processReplacing if effFlagsCanReplacing is set and processReplacing != process (if it equals it assumes that it is a faulty implementation of processReplacing). Additionally there is an option in the preferences to not use processReplacing for buggy plug-ins. Note that for plug-ins that have
    Cockos extensions (see below), the option (to not use processReplacing) is ignored, allowing known-good plug-ins to always run at full speed.

  • Threading/concurrency: Since audio processing can run in other threads from the UI, it's important to note what can run at the same time. REAPER is highly optimized to prevent UI and other actions from interrupting audio, so assume everything can (and WILL) run at the same time as your process/processReplacing, except:
    • effOpen/effClose
    • effSetChunk -- while effGetChunk can run at the same time as audio (user saves project, or for automatic undo state tracking), effSetChunk is guaranteed to not run while audio is processing.
    So nearly _everything_ else should be threadsafe. For many things this doesn't mean having to do much, but there are plenty of plug-ins that barf when audio is running and you open the window (using effEditOpen). There is an option to bypass audio while opening the config window, but it sucks and shouldn't be required.

  • Dynamic parameters: REAPER can deal with the number of parameters for a plug-in changing on the fly. We will soon implement APIs so that plug-ins can notify REAPER of parameter count changes (i.e. parameter X deleted, or new parameter Y), to preserve automation of higher indexed parameters when adding/removing lower parameters.

  • Multiple inputs/outputs: REAPER allows the user to dynamically connect input/output pins of VSTs wherever they want, so enable as much I/O as you need. REAPER also allows input/output counts to change, HOWEVER it is recommended that any changes you make be done from within processReplacing() or process(), and use the old value of numInputs/numOutputs until the next call. Additionally the initial value of numInputs/numOutputs should be set to the most common settings.

  • Longer labels: effGetParamName/effGetParamLabel/effGetParamDisplay all support up to 256 character strings (255+null).

  • More coming soon.



VST Extensions

The following are extensions made available to VST plug-ins running in REAPER. Feel free to use them in your plug-ins, and encourage other VST host developers to add support for them.

Extensions
A REAPER aware VST plug-in can respond to effCanDo "hasCockosExtensions", with 0xbeef0000 (returning this value), which will inform the host that it can call certain extended calls.

  case effCanDo:
    if (ptr && !strcmp((char *)ptr,"hasCockosExtensions")) return 0xbeef0000;

Extended vendor specific calls the plug-in can implement include:
  • effVendorSpecific(effGetParamDisplay, parm, buf, val)
    Gets the formatted display of a particular value for a parameter. This REAPER uses for example when displaying the value of a VST's automated parameter on an envelope tooltip. Example implementation on host:
      char buf[256]="";
      if (effect->dispatcher(effect,effVendorSpecific,effGetParamDisplay,parm_idx,buf,val)>=0xbeef && *buf)
      {
        printf("parm %d, value=%f is %s\n",parm_idx,val,buf);
      }
    
    Example implementation on plug-in:
      case effVendorSpecific:
        if (index == effGetParamDisplay && ptr)
        {
          if (value>=0 && value<NUM_PARAMS) 
          { 
            sprintf(ptr,"%f",opt);
            return 0xbeef; 
          }
        }
    


  • effVendorSpecific(0xdeadbef0, parm, rangeptr, 0.0)
    Queries the range of a parameter (allowing the plug-in to use more than the 0.0...1.0 range that VST defines). The host does something like:
      double range[2]={0,1};
      if (effect->dispatcher(effect, effVendorSpecific, 0xdeadbef0, parm_index, range, 0.0)>=0xbeef)
      {
        // range[0]..range[1] is the range instead of 0..1
      }
    
    Or, to implement it on the plug-in side (in addition to responding to effCanDo/"hasCockosExtensions"):
      case effVendorSpecific:
        if (index == 0xdeadbef0 && ptr && value>=0 && value<NUM_PARAMS)  
        {
          ((double *)ptr)[0] = min_val;
          ((double *)ptr)[1] = max_val;
          return 0xbeef;
        }
    



Host Integration Functions

There are some additional functions to enable better integration with the host, the primary interface for accessing these extensions is via the audioMaster callback. Suppose your callback pointer is named "hostcb", then you would get each API with the following code:

  void (*someFunction)();
  *(long *)&someFunction = hostcb(NULL,0xdeadbeef,0xdeadf00d,0,"someFunction",0.0);
If an API is not implemented, hostcb() will return 0, and the resulting function shouldn't be called. Except when noted, all functions can be called from any context in any thread at any time. A list of functions defined: