A thread-safe, cross-platform C# library for hosting VST3 plugins. Built for audio applications where the UI thread, the audio thread, and the plugin's native runtime must never block each other.
- Thread-safe by design — dedicated plugin thread, lock-free UI→audio parameter queue, atomic state machine
- Full VST3 support — instruments, effects, MIDI-only plugins, parameter automation, transport context
- Cross-platform native editors — Win32 (STA), Cocoa (GCD main thread), X11 (dedicated event loop)
- Zero allocation audio path — pre-pinned buffers, no heap allocation inside
ProcessAudio - Queryable plugin state —
NotLoaded → Loaded → Ready ↔ Processing | Error - Automatic platform detection — native library resolved at runtime for
win-x64,osx-arm64,linux-x64and more
dotnet add package OwnVst3Hostusing OwnVST3Host;
using OwnVST3Host.NativeWindow;
// 1. Create the wrapper — starts the dedicated plugin thread immediately.
await using var plugin = new ThreadedVst3Wrapper();
// 2. Load and initialize on the plugin thread; the UI thread is never blocked.
bool loaded = await plugin.LoadPluginAsync("/Library/Audio/Plug-Ins/VST3/MyPlugin.vst3");
bool ready = await plugin.InitializeAsync(sampleRate: 44100, maxBlockSize: 512);
if (!ready)
{
Console.WriteLine($"State: {plugin.State}"); // VstPluginState.Error
return;
}
// 3. Query plugin info (all async, all on plugin thread).
string name = await plugin.GetNameAsync();
string vendor = await plugin.GetVendorAsync();
Console.WriteLine($"Loaded: {name} by {vendor}");
// 4. Real-time audio — call ProcessAudio directly from your audio thread.
// It drains the UI→audio parameter queue before every block.
bool ok = plugin.ProcessAudio(inputs, outputs, numChannels: 2, numSamples: 512);
// 5. Change parameters from the UI thread — lock-free, applied on next audio block.
plugin.SetParameter(paramId: 0, value: 0.75);
plugin.SetTempo(bpm: 120.0);
plugin.SetTransportState(isPlaying: true);
// 6. Open the plugin editor on the UI thread (VST3 + OS requirement).
var editor = new VstEditorController(plugin);
await editor.OpenEditorAsync(name);UI Thread ──── async/await ────▶ Plugin Thread (Load, Init, GetParameter…)
UI Thread ──── SPSC queue ────▶ Audio Thread (SetParameter, SetTempo…)
Audio Thread ──── direct call ────▶ ProcessAudio (no marshalling, no allocation)
UI Thread ──── UI thread ────▶ VstEditorController (CreateEditor, CloseEditor)
All state transitions are atomic. plugin.State and plugin.IsReady can be read safely from any thread at any time.
| State | Meaning |
|---|---|
NotLoaded |
Initial / after Dispose |
Loaded |
LoadPluginAsync succeeded |
Ready |
InitializeAsync succeeded — audio processing possible |
Processing |
Inside ProcessAudio (audio thread) |
Error |
Fatal failure — replace the instance |
// In your audio callback:
if (!plugin.IsReady) return;
plugin.ProcessAudio(inputs, outputs, channels, samples);| Platform | Architecture | Window backend |
|---|---|---|
| Windows | x64, x86 | Win32 STA thread + message loop |
| macOS | x64, ARM64 | Cocoa via GCD (dispatch_sync to main thread) |
| Linux | x64 | X11 dedicated event loop thread |
Native libraries are resolved automatically from runtimes/{rid}/native/ at runtime.
OwnAudioVST3/
├── OwnVST3Host/ # Main library
│ ├── ThreadedVst3Wrapper.cs # Primary API — thread-safe VST3 façade
│ ├── OwnVst3Wrapper.cs # Low-level native wrapper + platform detection
│ ├── LockFreeQueue.cs # SPSC ring buffer (UI → audio thread)
│ └── NativeWindow/
│ ├── INativeWindow.cs # Platform-agnostic window interface
│ ├── NativeWindowWindows.cs # Win32 STA window with message loop
│ ├── NativeWindowMac.cs # Cocoa/GCD main-thread marshalling
│ ├── NativeWindowLinux.cs # X11 event loop thread
│ ├── NativeWindowFactory.cs # Runtime platform selector
│ └── VstEditorController.cs # Editor lifecycle manager
└── OwnVST3EditorDemo/ # Avalonia demo application
# Clone the repository
git clone --recursive https://github.com/ModernMube/OwnVST3Sharp.git
cd OwnVST3Sharp
# Build the library
dotnet build OwnVST3Host/OwnVST3Host.csproj --configuration Release
# Run the demo
dotnet run --project OwnVST3EditorDemoFull developer guide with API reference, threading rules, and code examples:
Topics covered:
- Architecture overview and threading diagram
- Plugin state machine reference
- Audio processing patterns (allocation-free path, channel handling)
- Parameter control: reading on plugin thread vs. writing via SPSC queue
- Transport and tempo integration
- MIDI scheduling with
SampleOffset - Editor lifecycle with Avalonia examples
- Plugin discovery and platform detection
- Best practices and common pitfalls
If you find this project helpful, consider buying me a coffee!
MIT License — see LICENSE.txt for details.
- Built on the VST3 SDK
- UI rendering powered by Avalonia UI
- Issues and contributions: GitHub Issues
