Skip to main content

Overview

The IPlugProcessor class is the base class for audio processing in iPlug2. It handles audio buffers, MIDI messages, channel I/O configurations, sample rate, block size, and transport information. This class knows nothing about parameters, presets, or user interface. Header: IPlug/IPlugProcessor.h
Methods marked as “realtime-safe” must not perform allocations, file I/O, or blocking operations. They are called on the high-priority audio thread.

Constructor & Destructor

IPlugProcessor

IPlugProcessor(const Config& config, EAPI plugAPI);
Constructs the processor with plugin configuration.
config
const Config&
required
Plugin configuration struct from config.h
plugAPI
EAPI
required
Plugin API type (VST2, VST3, AU, etc.)

~IPlugProcessor

virtual ~IPlugProcessor();
Virtual destructor for cleanup.

Core Processing Methods

Override these methods in your plugin class. Do NOT call them directly.

ProcessBlock

virtual void ProcessBlock(sample** inputs, sample** outputs, int nFrames);
Main audio processing method. Override this to implement your DSP.
inputs
sample**
required
Two-dimensional array of non-interleaved input buffers. All channels are guaranteed valid pointers (unconnected channels contain zeros).
outputs
sample**
required
Two-dimensional array of non-interleaved output buffers for writing processed audio.
nFrames
int
required
Block size: number of samples per channel in this processing block.
REALTIME-SAFE CONTEXT: Do not allocate memory, perform file I/O, or use blocking operations in ProcessBlock.
// Example: Simple gain plugin
void MyPlugin::ProcessBlock(sample** inputs, sample** outputs, int nFrames)
{
  const int nChans = NOutChansConnected();
  const double gain = GetParam(kGain)->DBToAmp();
  
  for (int s = 0; s < nFrames; s++)
  {
    for (int c = 0; c < nChans; c++)
    {
      outputs[c][s] = inputs[c][s] * gain;
    }
  }
}

ProcessMidiMsg

virtual void ProcessMidiMsg(const IMidiMsg& msg);
Handle incoming MIDI messages. Called before ProcessBlock().
msg
const IMidiMsg&
required
MIDI message with timestamp (mOffset) indicating sample offset in the upcoming block
REALTIME-SAFE CONTEXT: Use IMidiQueue to queue messages for processing at the correct sample offset.
// Example: Queue MIDI messages
void MyPlugin::ProcessMidiMsg(const IMidiMsg& msg)
{
  mMidiQueue.Add(msg);
}

void MyPlugin::ProcessBlock(sample** inputs, sample** outputs, int nFrames)
{
  for (int s = 0; s < nFrames; s++)
  {
    // Process queued MIDI at the correct sample offset
    while (!mMidiQueue.Empty())
    {
      IMidiMsg& msg = mMidiQueue.Peek();
      if (msg.mOffset > s) break;
      
      // Handle the MIDI message
      if (msg.StatusMsg() == IMidiMsg::kNoteOn)
      {
        int note = msg.NoteNumber();
        int velocity = msg.Velocity();
        mSynth.NoteOn(note, velocity);
      }
      
      mMidiQueue.Remove();
    }
    
    // Process audio...
  }
  
  mMidiQueue.Flush(nFrames);
}

ProcessSysEx

virtual void ProcessSysEx(const ISysEx& msg);
Handle incoming MIDI System Exclusive messages. Called before ProcessBlock().
msg
const ISysEx&
required
SysEx message containing offset, size, and data pointer
REALTIME-SAFE CONTEXT: Default implementation does nothing.

OnReset

virtual void OnReset();
Called when sample rate changes or transport resets. Use this to clear buffers, update DSP coefficients, etc.
void MyPlugin::OnReset()
{
  mFilter.SetSampleRate(GetSampleRate());
  mDelay.Clear();
  mMidiQueue.Resize(GetBlockSize());
}

OnActivate

virtual void OnActivate(bool active);
Called when the plugin is activated/deactivated by the host.
active
bool
required
true if plugin is being activated, false if deactivated
Unlike OnReset(), OnActivate() is called when I/O connections change. Different hosts have different interpretations of “activate”.

MIDI Output Methods

SendMidiMsg

virtual bool SendMidiMsg(const IMidiMsg& msg) = 0;
Send a single MIDI message to the host.
msg
const IMidiMsg&
required
MIDI message to send
return
bool
true if successful
// Example: Send a note on message
IMidiMsg msg;
msg.MakeNoteOnMsg(60, 100, 0); // Middle C, velocity 100, offset 0
SendMidiMsg(msg);

SendMidiMsgs

virtual bool SendMidiMsgs(WDL_TypedBuf<IMidiMsg>& msgs);
Send multiple MIDI messages.
msgs
WDL_TypedBuf<IMidiMsg>&
required
Buffer of MIDI messages to send

SendSysEx

virtual bool SendSysEx(const ISysEx& msg);
Send a MIDI System Exclusive message.
msg
const ISysEx&
required
SysEx message to send
return
bool
true if successful (default implementation returns false)

Audio Context Information

GetSampleRate

double GetSampleRate() const;
Returns the current sample rate in Hz.

GetBlockSize

int GetBlockSize() const;
Returns the maximum block size in samples. Actual block size may vary per ProcessBlock() call.

GetLatency

int GetLatency() const;
Returns the plugin latency in samples.

SetLatency

virtual void SetLatency(int latency);
Call this to update plugin latency at runtime.
latency
int
required
New latency in samples
Not all hosts support dynamic latency changes. Call from OnReset() if latency depends on sample rate.

GetTailSize

int GetTailSize() const;
Returns the tail size in samples (for reverb, delay, etc.).

GetTailIsInfinite

bool GetTailIsInfinite() const;
Returns true if the tail size is infinite.

SetTailSize

virtual void SetTailSize(int tailSize);
Update the tail size at runtime.
tailSize
int
required
New tail size in samples, or kTailInfinite for infinite tail
// Example: Update tail based on reverb decay time
void MyPlugin::OnParamChange(int paramIdx)
{
  if (paramIdx == kDecayTime)
  {
    double decaySeconds = GetParam(kDecayTime)->Value();
    int tailSamples = static_cast<int>(decaySeconds * GetSampleRate());
    SetTailSize(tailSamples);
  }
}

TailSize Enum

enum TailSize
{
  kTailNone = 0,
  kTailInfinite = std::numeric_limits<int>::max()
};

GetBypassed

bool GetBypassed() const;
Returns true if the plugin is currently bypassed.

GetRenderingOffline

bool GetRenderingOffline() const;
Returns true if rendering offline (e.g., bouncing/freezing).

Transport Information

GetSamplePos

double GetSamplePos() const;
Returns the number of samples elapsed since the start of the project timeline.

GetTempo

double GetTempo() const;
Returns the current tempo in beats per minute (BPM).

GetPPQPos

double GetPPQPos() const;
Returns the number of beats elapsed since the start of the project (Pulse Per Quarter note position).

GetTransportIsRunning

bool GetTransportIsRunning() const;
Returns true if the transport is currently playing.

GetSamplesPerBeat

double GetSamplesPerBeat() const;
Calculates the number of samples in one beat at the current tempo and sample rate.

GetTimeSig

void GetTimeSig(int& numerator, int& denominator) const;
Get the current time signature.
numerator
int&
required
Output: numerator (e.g., 6 in 6/8)
denominator
int&
required
Output: denominator (e.g., 8 in 6/8)
// Example: Tempo-synced LFO
void MyPlugin::ProcessBlock(sample** inputs, sample** outputs, int nFrames)
{
  const double samplesPerBeat = GetSamplesPerBeat();
  const double lfoFreqHz = (1.0 / samplesPerBeat) * 4.0; // 1/4 note rate
  
  mLFO.SetFrequency(lfoFreqHz, GetSampleRate());
  
  // Process audio...
}

Channel I/O Configuration

MaxNChannels

int MaxNChannels(ERoute direction) const;
Returns the total number of channel buffers (input or output).
direction
ERoute
required
ERoute::kInput or ERoute::kOutput

NChannelsConnected

int NChannelsConnected(ERoute direction) const;
Returns the number of connected channels.
direction
ERoute
required
ERoute::kInput or ERoute::kOutput
Assumes consecutive channel connections. Not all hosts guarantee this.

NInChansConnected

inline int NInChansConnected() const;
Convenience method: returns the number of connected input channels.

NOutChansConnected

inline int NOutChansConnected() const;
Convenience method: returns the number of connected output channels.

IsChannelConnected

bool IsChannelConnected(ERoute direction, int chIdx) const;
Check if a specific channel is connected.
direction
ERoute
required
Input or output direction
chIdx
int
required
Channel index to check

LegalIO

bool LegalIO(int NInputChans, int NOutputChans) const;
Check if a channel configuration is valid based on the I/O config string.
NInputChans
int
required
Number of input channels (-1 to check outputs only)
NOutputChans
int
required
Number of output channels (-1 to check inputs only)

SetChannelLabel

void SetChannelLabel(ERoute direction, int idx, const char* formatStr, bool zeroBased = false);
Label input/output channels (VST2 only).
direction
ERoute
required
Input or output direction
idx
int
required
Channel index
formatStr
const char*
required
Printf-style format string where %i is the channel index
zeroBased
bool
If true, index in format string is zero-based
// Example: Label ambisonic channels
SetChannelLabel(ERoute::kInput, 0, "W");
SetChannelLabel(ERoute::kInput, 1, "X");
SetChannelLabel(ERoute::kInput, 2, "Y");
SetChannelLabel(ERoute::kInput, 3, "Z");

Bus Configuration

MaxNBuses

Get maximum number of buses
int MaxNBuses(ERoute direction, int* pConfigIdxWithTheMostBuses = nullptr) const;

MaxNChannelsForBus

Get max channels for a specific bus
int MaxNChannelsForBus(ERoute direction, int busIdx) const;

HasWildcardBus

Check if config has wildcard buses
bool HasWildcardBus(ERoute direction) const;

GetBusName

Get name for a bus
virtual void GetBusName(ERoute direction, int busIdx, int nBuses, WDL_String& str) const;

NIOConfigs

int NIOConfigs() const;
Returns the number of I/O configurations parsed from the channel I/O string.

GetIOConfig

const IOConfig* GetIOConfig(int idx) const;
Get a pointer to an IOConfig at a specific index.
return
const IOConfig*
Pointer to IOConfig, or nullptr if index is invalid

HasSidechainInput

bool HasSidechainInput() const;
Returns true if the plugin has a sidechain input (more than 1 input bus).

Plugin Type Information

IsInstrument

bool IsInstrument() const;
Returns true if configured as an instrument.

IsMidiEffect

bool IsMidiEffect() const;
Returns true if configured as a MIDI effect.

DoesMIDIIn

bool DoesMIDIIn() const;
Returns true if the plugin receives MIDI input.

DoesMIDIOut

bool DoesMIDIOut() const;
Returns true if the plugin produces MIDI output.

DoesMPE

bool DoesMPE() const;
Returns true if the plugin supports MIDI Polyphonic Expression.

GetAUPluginType

int GetAUPluginType() const;
Returns the 4-char identifier for AudioUnit type (e.g., ‘aufx’ for effect).

Static Utilities

ParseChannelIOStr

static int ParseChannelIOStr(const char* IOStr,
                              WDL_PtrList<IOConfig>& channelIOList,
                              int& totalNInChans,
                              int& totalNOutChans,
                              int& totalNInBuses,
                              int& totalNOutBuses);
Parse the channel I/O configuration string from config.h.
IOStr
const char*
required
Space-separated I/O configs in format “ninchans-noutchans”. Use . for multiple buses (e.g., “1.1-1” for mono in + mono sidechain → mono out)
channelIOList
WDL_PtrList<IOConfig>&
required
Output: list of parsed IOConfig structs
totalNInChans
int&
required
Output: total input channels across all buses
totalNOutChans
int&
required
Output: total output channels across all buses
totalNInBuses
int&
required
Output: total number of input buses
totalNOutBuses
int&
required
Output: total number of output buses
return
int
Number of configurations detected

Example: Complete Processor Implementation

class MySynth : public iplug::Plugin
{
public:
  MySynth(const iplug::InstanceInfo& info)
  : Plugin(info, MakeConfig(kNumParams, kNumPresets))
  {
    // Initialize parameters...
  }
  
  void OnReset() override
  {
    // Update DSP for new sample rate
    mOscillator.SetSampleRate(GetSampleRate());
    mFilter.SetSampleRate(GetSampleRate());
    
    // Resize MIDI queue for new block size
    mMidiQueue.Resize(GetBlockSize());
    
    // Clear delay lines
    mEnvelope.Reset();
  }
  
  void ProcessMidiMsg(const IMidiMsg& msg) override
  {
    // Queue all MIDI messages
    mMidiQueue.Add(msg);
  }
  
  void ProcessBlock(sample** inputs, sample** outputs, int nFrames) override
  {
    const int nChans = NOutChansConnected();
    
    for (int s = 0; s < nFrames; s++)
    {
      // Process MIDI at correct sample offset
      while (!mMidiQueue.Empty())
      {
        IMidiMsg& msg = mMidiQueue.Peek();
        if (msg.mOffset > s) break;
        
        switch (msg.StatusMsg())
        {
          case IMidiMsg::kNoteOn:
            if (msg.Velocity() > 0)
            {
              mOscillator.SetFrequency(440.0 * pow(2.0, (msg.NoteNumber() - 69) / 12.0));
              mEnvelope.Trigger();
            }
            else
            {
              mEnvelope.Release();
            }
            break;
            
          case IMidiMsg::kNoteOff:
            mEnvelope.Release();
            break;
            
          case IMidiMsg::kPitchWheel:
            mOscillator.SetPitchBend(msg.PitchWheel());
            break;
        }
        
        mMidiQueue.Remove();
      }
      
      // Generate audio
      sample output = mOscillator.Process();
      output = mFilter.Process(output);
      output *= mEnvelope.Process();
      
      // Write to all output channels
      for (int c = 0; c < nChans; c++)
      {
        outputs[c][s] = output;
      }
    }
    
    mMidiQueue.Flush(nFrames);
  }
  
private:
  IMidiQueue mMidiQueue;
  Oscillator mOscillator;
  Filter mFilter;
  Envelope mEnvelope;
};

See Also