Table of Contents

Class Vst3MidiInstrument

Namespace
NAudio.Vst3
Assembly
NAudio.Vst3.dll

Adapts a hosted VST 3® instrument (VSTi) to NAudio's IMidiInstrument seam, so it plugs into the shared MIDI playback hosts in NAudio.Midi — SequencedMidiPlayer (timeline / .mid-file playback), OfflineMidiRenderer (faster-than-real-time render to WAV) and LiveMidiInstrument (live input from another thread) — exactly as the NAudio.Sampler engine does. Feed it a MidiFileSequence through one of those hosts and a VSTi renders or plays the file with sample-accurate event timing.

public sealed class Vst3MidiInstrument : IMidiInstrument, ISampleProvider
Inheritance
Vst3MidiInstrument
Implements
Inherited Members
Extension Methods

Remarks

IMidiInstrument is a segment-render contract: ProcessMidiEvent(MidiEvent) applies an event, then the next Read(Span<float>) renders forward with it in effect. A host such as SequencedMidiPlayer splits each audio block at event boundaries, so every dispatched event belongs at the start of the following (sub-)block. This adapter therefore translates each MIDI event onto Vst3Plugin's offset-0 immediate-event path (EnqueueNoteOn(int, float, int) et al.) rather than the wall-clock Send* path, which keeps timing correct under offline rendering where there is no real-time clock.

Single-threaded, like the rest of IMidiInstrument: call ProcessMidiEvent(MidiEvent) and Read(Span<float>) from the same thread. Calling ProcessMidiEvent(MidiEvent) directly from another thread is not merely unsynchronised — an event racing AllSoundOff() can leave a note stuck on. To drive a VSTi from live MIDI input arriving on another thread, wrap this in a LiveMidiInstrument, which marshals events onto the render thread for you.

Instruments take no audio input, so the plug-in's input bus (if present) receives silence. Vocoders and other audio-consuming synths aren't covered here — use Vst3InstrumentSampleProvider for that.

Pass a tempo map (and optionally a TimeSignatureMap and the driving Transport) to feed the plug-in a populated ProcessContext — tempo, time signature, musical position and playing state — so tempo-following plug-ins (arpeggiators, synced delays) lock to the timeline. With a Transport the playhead and playing state come from it (so seek / stop / loop are handled for free); without one the adapter counts rendered frames itself (the right model for a monotonic offline render via OfflineMidiRenderer). Omit the tempo map entirely (the single-argument constructor) and the plug-in free-runs — the right choice for live keyboard input with no timeline.

When you supply a Transport, this adapter only reads its position; it does not move it. Whatever drives playback must advance the transport by the number of frames each Read(Span<float>) consumes (e.g. a host such as SequencedMidiPlayer does this), or the playhead — and the ProcessContext position it feeds the plug-in — never progresses.

Constructors

Vst3MidiInstrument(Vst3Plugin)

Wraps an instrument plug-in as an IMidiInstrument with no musical context (the plug-in free-runs) — the right choice for live keyboard input.

public Vst3MidiInstrument(Vst3Plugin plugin)

Parameters

plugin Vst3Plugin

An instrument plug-in (see IsInstrument).

Exceptions

ArgumentException

The plug-in is not an instrument.

Vst3MidiInstrument(Vst3Plugin, ITempoMap?, TimeSignatureMap?, Transport?)

Wraps an instrument plug-in as an IMidiInstrument that feeds it a populated ProcessContext built from the sequencer timing types.

public Vst3MidiInstrument(Vst3Plugin plugin, ITempoMap? tempoMap, TimeSignatureMap? timeSignatureMap = null, Transport? transport = null)

Parameters

plugin Vst3Plugin

An instrument plug-in (see IsInstrument).

tempoMap ITempoMap

Drives tempo and musical position. When null the plug-in free-runs.

timeSignatureMap TimeSignatureMap

Optional; drives the time signature and bar position. Defaults to 4/4.

transport Transport

Optional; when supplied, the playhead and playing state are read from it each block (so seek / stop / loop are honoured). When null the adapter counts rendered frames itself and is always playing — the correct model for a monotonic offline render.

Exceptions

ArgumentException

The plug-in is not an instrument.

Properties

Plugin

The wrapped plug-in.

public Vst3Plugin Plugin { get; }

Property Value

Vst3Plugin

WaveFormat

Gets the WaveFormat of this Sample Provider.

public WaveFormat WaveFormat { get; }

Property Value

WaveFormat

The wave format.

Methods

AllSoundOff()

Stops all sound promptly (the MIDI "all sound off" panic), e.g. when a host seeks or stops. Implementations should avoid clicks where they can (a short fade) but must not let notes ring out naturally.

public void AllSoundOff()

ProcessMidiEvent(MidiEvent)

Dispatches a MIDI event (note on/off, control change, pitch-bend, aftertouch, program change). Unsupported messages are ignored.

public void ProcessMidiEvent(MidiEvent midiEvent)

Parameters

midiEvent MidiEvent

Read(Span<float>)

Fill the specified buffer with 32 bit floating point samples

public int Read(Span<float> buffer)

Parameters

buffer Span<float>

The buffer to fill with samples.

Returns

int

The number of samples written. Return 0 to signal end of stream.

Remarks

buffer's length must be a whole number of frames (a multiple of WaveFormat's channel count). A non-frame-aligned length silently drops the trailing partial frame, which — because an instrument is a never-ending source — can make a caller that treats a short read as end-of-stream stop early.