Core Components
iPlug2 is split into two main architectural layers that work together to create audio plugins:
IPlug Audio processing, parameters, and plugin API abstraction
IGraphics Cross-platform UI toolkit with multiple rendering backends
IPlug Core
The IPlug layer provides the audio plugin abstraction, handling the differences between plugin formats (VST3, AU, AAX, CLAP, WAM) so your code works everywhere.
Class Hierarchy
IPlugProcessor (audio processing, I/O, timing)
↑
IPluginBase (parameters, presets, state)
↑
IPlugAPIBase (editor delegate, host communication)
↑
YourPlugin (your implementation)
The architecture separates concerns: IPlugProcessor handles real-time audio, IPluginBase manages state, and IPlugAPIBase handles host integration.
Key Responsibilities
IPlugProcessor
IPluginBase
IPlugAPIBase
Real-time audio processing (IPlugProcessor.h )
Audio I/O management and channel routing
MIDI processing (note on/off, CC, SysEx)
Sample rate and block size handling
Latency and tail size reporting
Transport and timing information
void ProcessBlock ( sample ** inputs , sample ** outputs , int nFrames );
void ProcessMidiMsg ( const IMidiMsg & msg );
void ProcessSysEx ( const ISysEx & msg );
void OnReset (); // Called when sample rate changes
void OnActivate ( bool active ); // Called when track is enabled/disabled
Plugin state and parameters (IPluginBase.h )
Parameter management (fixed count at compile time)
Preset system (factory and user presets)
State serialization (for DAW project saving)
Parameter groups and metadata
// Parameters are indexed by enum
GetParam (kGain)-> InitDouble ( "Gain" , 0. , 0. , 100.0 , 0.01 , "%" );
// Non-normalized access in ProcessBlock
const double gain = GetParam (kGain)-> Value () / 100. ;
Host communication (IPlugAPIBase.h )
Editor (UI) lifecycle management
Host notifications (parameter changes, preset changes)
Platform-specific adaptations
API-specific behavior
Each plugin format (VST3, AU, AAX, etc.) extends this with format-specific implementation.
IGraphics
IGraphics is an optional UI toolkit for building plugin interfaces. You can also use SwiftUI, WebView, or other UI frameworks.
Rendering Backends
NanoVG Lightweight and fast
OpenGL-based vector rendering
No external dependencies needed
Default choice for most plugins
Good performance on older hardware
Skia High quality rendering
Same engine as Chrome/Android
Better text and effects quality
Requires Skia dependency download
Used by Google, Flutter
IGraphics Architecture
IGraphics (base graphics context)
↑
IGraphicsNanoVG/Skia (drawing implementation)
↑
IGraphicsMac/Win/Linux (platform-specific event handling)
IGraphics is only instantiated when the plugin UI is opened by the host. Audio processing continues independently even without a visible UI.
UI Construction Pattern
IGraphics UIs are typically built in a lambda function:
mMakeGraphicsFunc = [ & ]() {
return MakeGraphics ( * this , PLUG_WIDTH, PLUG_HEIGHT, PLUG_FPS,
GetScaleForScreen (PLUG_WIDTH, PLUG_HEIGHT));
};
mLayoutFunc = [ & ]( IGraphics * pGraphics ) {
pGraphics -> AttachPanelBackground (COLOR_GRAY);
pGraphics -> LoadFont ( "Roboto-Regular" , ROBOTO_FN);
// Controls automatically link to parameters by index
pGraphics -> AttachControl ( new IVKnobControl (bounds, kGain));
};
Plugin Lifecycle
Understanding the plugin lifecycle is crucial for proper initialization and cleanup.
Construction
Your plugin constructor is called when the host loads the plugin. IPlugEffect :: IPlugEffect ( const InstanceInfo & info)
: Plugin (info, MakeConfig (kNumParams, kNumPresets))
{
// Initialize parameters
GetParam (kGain)-> InitDouble ( "Gain" , 0. , 0. , 100. , 0.01 , "%" );
// Setup graphics (if IPLUG_EDITOR is defined)
mMakeGraphicsFunc = [ & ]() { /* ... */ };
}
Don’t allocate large buffers in the constructor. Wait for OnReset() when you know the sample rate.
OnReset()
Called when:
Plugin is first activated
Sample rate changes
I/O configuration changes
void OnReset () override {
// Allocate DSP buffers based on GetSampleRate()
mDelay . SetDelayTime ( GetSampleRate () * 0.5 ); // 500ms
}
OnActivate()
Called when the plugin is enabled/disabled on a track. void OnActivate ( bool active ) override {
if (active) {
// Clear buffers, reset state
mPhase = 0.0 ;
}
}
Not all hosts support this reliably. Use OnReset() for critical initialization.
ProcessBlock()
Called repeatedly on the audio thread for real-time processing. void ProcessBlock ( sample ** inputs , sample ** outputs , int nFrames ) {
const double gain = GetParam (kGain)-> Value () / 100. ;
const int nChans = NOutChansConnected ();
for ( int s = 0 ; s < nFrames; s ++ ) {
for ( int c = 0 ; c < nChans; c ++ ) {
outputs [c][s] = inputs [c][s] * gain;
}
}
}
Destruction
Your plugin destructor cleans up resources when the host unloads the plugin. ~ IPlugEffect () {
// Cleanup happens automatically for smart pointers
// Manual cleanup if needed
}
Threading Model
iPlug2 uses a clear threading model to prevent audio dropouts and race conditions.
Thread Types
Audio Thread
UI Thread
Parameter Access
High priority real-time thread Methods called on audio thread:
ProcessBlock()
ProcessMidiMsg()
ProcessSysEx()
Real-time safety rules: NEVER do these on the audio thread:
Memory allocation/deallocation
File I/O or network operations
Locking mutexes (use lock-free queues)
System calls that can block
TRACE or logging in release builds
void ProcessBlock ( sample ** inputs , sample ** outputs , int nFrames ) {
// ✅ Good: direct parameter access (atomic)
double gain = GetParam (kGain)-> Value ();
// ❌ Bad: allocation
// std::vector<double> buffer(nFrames); // NO!
// ❌ Bad: file I/O
// fwrite(outputs[0], sizeof(sample), nFrames, file); // NO!
// ❌ Bad: mutex lock
// mMutex.lock(); // NO!
}
Lower priority GUI thread IGraphics controls and UI code run on the UI thread. Communication with the audio thread happens via:
ISender - Send data from audio thread to UI (visualization)
Parameter changes - Send from UI to audio thread (automatic)
// In ProcessBlock (audio thread)
mMeterSender . PushData ({kCtrlTagMeter}, {mCurrentLevel});
// In UI control (UI thread)
class MeterControl : public IControl {
void OnMsgFromDelegate ( int msgTag , int dataSize , const void* pData ) {
// Update meter display safely on UI thread
mLevel = * ( double * )pData;
}
};
Thread-safe parameter access IParam values use std::atomic<double> for thread-safe access: // Safe from any thread (atomic load)
double value = GetParam (kGain)-> Value ();
// Safe from any thread (atomic store)
GetParam (kGain)-> Set (newValue);
From IPlugParameter.h:516 : std ::atomic < double > mValue{ 0.0 };
Some plugins define PARAMS_MUTEX for additional thread safety, but atomic access is usually sufficient.
Communication Patterns
// UI → Audio Thread (via parameters)
GetParam (kGain)-> Set (newValue); // Atomic, thread-safe
// Audio Thread → UI (via ISender)
mSender . PushData ({kTagScope}, {buffer, nFrames}); // Lock-free queue
// Host → Plugin (parameter automation)
// Handled automatically by API layer
// Plugin → Host (MIDI output)
SendMidiMsg (msg); // Called from ProcessBlock or UI
API-Specific Implementations
Each plugin format has its own API class that inherits from the base classes:
class IPlugVST3 : public IPlugAPIBase ,
public IPlugVST3ProcessorBase ,
public IPlugVST3ControllerBase ,
public Steinberg :: Vst :: SingleComponentEffect
You never directly interact with these API classes in your plugin code. The abstraction handles format-specific details automatically.
Best Practices
Separation of Concerns Keep audio processing in ProcessBlock(), UI in layout functions, and state management in parameters.
Real-time Safety Never allocate, lock, or do I/O in ProcessBlock(). Pre-allocate buffers in OnReset().
Parameter Design Use non-normalized values (e.g., 0-100 for gain) - they’re easier to work with in DSP code.
Smart Initialization Initialize UI lazily (in lambda), allocate DSP buffers in OnReset() when sample rate is known.
Next Steps
Plugin Formats Learn about VST3, AU, AAX, CLAP, and WAM specifics
Parameters Master parameter types, automation, and groups
Audio Processing Deep dive into ProcessBlock and real-time audio
Project Structure Understand config.h, Plugin.h, and Plugin.cpp