Class Vst3MidiInstrument
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
pluginVst3PluginAn 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
pluginVst3PluginAn instrument plug-in (see IsInstrument).
tempoMapITempoMapDrives tempo and musical position. When
nullthe plug-in free-runs.timeSignatureMapTimeSignatureMapOptional; drives the time signature and bar position. Defaults to 4/4.
transportTransportOptional; when supplied, the playhead and playing state are read from it each block (so seek / stop / loop are honoured). When
nullthe 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
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
midiEventMidiEvent
Read(Span<float>)
Fill the specified buffer with 32 bit floating point samples
public int Read(Span<float> buffer)
Parameters
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.