vst3_wrapper.h
The VST3 format wrapper.
#include <sonore/vst3_wrapper.h>- 18types
- 193other declarations
- Guides: Getting started, Platforms and formats
On this page
Design notes
Written against Steinberg's C ABI (vst3_c_api.h, BSD-3-Clause) rather than the C++ SDK. That choice matters: the C header is one file under a permissive licence, so everything below is OUR code and the plugin links no framework at all. The C++ SDK would drag in a build system, a class hierarchy, and the dual GPLv3/proprietary terms this SDK exists to avoid.
Include it AFTER clap_wrapper.h in the same translation unit. The CLAP wrapper owns the machinery both formats share (the DSP instance, parameters, state, the webview bridge), and this file adapts it to VST3's shape, so one source file builds a .clap and a .vst3 that cannot drift apart.
Three differences drive everything here:
1. VST3 parameters are NORMALISED 0..1; ours are plain values. Every crossing converts, and getting one direction wrong is silent: the knob simply lands somewhere other than where the user put it. 2. VST3 is COM-like: refcounted objects reached through queryInterface. One object implements IComponent + IAudioProcessor + IEditController (a "single component effect"), which is what modern hosts expect and which halves the state that would otherwise need syncing. 3. UI edits must reach the host through IComponentHandler on the MAIN thread, unlike CLAP, where the plugin emits them from the audio thread.
Types 18
IUnitInfo: how VST3 spells a parameter hierarchy. Hosts read it to build the folders their generic editor shows.
IMidiMapping: which parameter a MIDI controller, channel aftertouch or pitch bend drives, since VST3 delivers those as parameter changes rather than MIDI. Only handed out when wantsMidiMapping() says the plugin reads MIDI.
INoteExpressionController: the per-note expression types this plugin accepts (see NoteExpressionSpec). A host sends none until it has asked.
IProcessContextRequirements: the process-context fields the plugin reads, which are exactly the ones readTransport() uses.
ChannelContext::IInfoListener: the host telling the plugin about its track (name, colour), passed on to the DSP as TrackInfo.
IComponent: the plugin's bus layout, activation and state, as the host sees the processing half.
IAudioProcessor: setup, speaker arrangements, latency and tail, and process(), which is the call that arrives on the audio thread.
IEditController: parameters, their text, the controller's copy of the state, and the editor. The same Plugin answers it as answers the processor, so both halves read one set of values.
IPlugView: the editor window as the host drives it. Points at the View, not the Plugin, because a view can outlive the plugin it came from.
The scale interface is a SEPARATE object with its own vtable pointer, because a caller that queried for it will call through it as if it were an IPlugViewContentScaleSupport -- handing back the view itself would have it dispatch setContentScaleFactor into whatever IPlugView keeps at slot 3.
The editor. Its lifetime is INDEPENDENT of the plugin's: a host may create a view, close the window, and release it much later, so it holds a plain pointer back and is told when the plugin goes away.
One object, three interfaces.
An event list seen from one piece of a block: the host's events that fall in it, at offsets within it -- and, as the output list, what the DSP sends back, moved from the piece's time to the host's.
One parameter's points as one piece of the block sees them: count of the host's, from its point first on.
The host's parameter changes as one piece of the block sees them: each queue's points that fall in the piece, so the last of them -- the one process() applies -- is the value at that point of the block, and a queue with none there shows none (an earlier piece applied its value). Only those: a MIDI controller's every point is a message, and a point an earlier piece already played, shown again at a later piece's frame 0, was a second message. One queue object serves every index: process() reads each queue through before it asks for the next.
One note expression type as INoteExpressionController reports it: the VST3 type id, the names a host shows, and the default and polarity in VST3's normalised 0..1 domain. One row of noteExpressionTable().
struct Steinberg_Vst_NoteExpressionTypeInfo* info) { if (!info || busIndex != 0 || channel < 0 || channel >= kMidiChannels) return Steinberg_kInvalidArgument; int n = 0; const NoteExpressionSpec* table = noteExpressionTable(&n); if (index < 0 || index >= n) return Steinberg_kInvalidArgument;No comment on this one in the header yet; the source says the rest.
The module's IPluginFactory2, the object GetPluginFactory() hands a host. One per module, a function-local static built on first use (factory()); it is never freed, so its reference count only keeps a host's bookkeeping honest. It describes the one class this module has and creates Plugin instances of it.
Functions 184
- fn
inline void deriveUid(const char* id, const char* salt, Steinberg_TUID out)VST3 identifies classes by a 16-byte UID. Ours is DERIVED from the plugin's reverse-URI id (FNV-1a, twice, with a salt), so it is stable across builds and unique per product without anyone generating and pasting a GUID: a step a generator would get wrong exactly once and then ship forever. The hashes make the GUID in its own order; it is stored the way the VST3 SDK stores one on this platform (vst3_uid.h), so its text -- what a session carries between Windows and macOS -- is the same on both.vst3::deriveUid · vst3_wrapper.h:64 - fn
inline const Steinberg_int8* componentUid()vst3::componentUid · vst3_wrapper.h:81 - fn
inline bool sameUid(const Steinberg_TUID a, const Steinberg_TUID b)vst3::sameUid · vst3_wrapper.h:91 - fn
inline void toString128(const char* utf8, Steinberg_Vst_String128 out)UTF-8 to VST3's String128 (UTF-16, 128 units including the terminator). The whole range: a code point past the BMP becomes a surrogate pair, and is dropped whole when only one unit of room is left -- half a pair is worse than a missing character. A malformed byte becomes '?' and the decoder moves on one byte, so garbage can never run past the terminator.vst3::toString128 · vst3_wrapper.h:100 - fn
inline void fromString128(const Steinberg_Vst_TChar* in, char* out, size_t capacity)VST3 hands parameter text back as UTF-16. We only parse numbers out of it, so narrowing is the honest conversion rather than a lossy pretence.vst3::fromString128 · vst3_wrapper.h:137 - fn
inline std::string utf16ToUtf8(const Steinberg_Vst_TChar* in, int maxUnits)UTF-16 to UTF-8, properly, for the strings a USER typed.vst3::utf16ToUtf8 · vst3_wrapper.h:156 - fn
inline double toNormalised(const ParamInfo& p, double plain)vst3::toNormalised · vst3_wrapper.h:191 - fn
inline double toPlain(const ParamInfo& p, double normalised)vst3::toPlain · vst3_wrapper.h:198 - fn
inline bool hasPrograms()vst3::hasPrograms · vst3_wrapper.h:228 - fn
inline int programIndexFromNormalised(double normalised)Normalised 0..1 to a preset index, ROUNDED rather than truncated: a host sending 0.999 for the last of three means the last one, and truncation would land on the middle.vst3::programIndexFromNormalised · vst3_wrapper.h:233 - fn
inline bool wantsMidiMapping()vst3::wantsMidiMapping · vst3_wrapper.h:281 - fn
inline int midiCcParamCount()vst3::midiCcParamCount · vst3_wrapper.h:282 - fn
inline Steinberg_Vst_ParamID midiCcParamId(int channel, int cc)vst3::midiCcParamId · vst3_wrapper.h:283 - fn
inline bool midiParamSlot(Steinberg_Vst_ParamID id, int* channel, int* cc)The (channel, controller) a hidden MIDI parameter stands for -- controller kMidiProgramSlot being program change -- or false for any other id.vst3::midiParamSlot · vst3_wrapper.h:289 - fn
inline void midiParamAt(int n, int* channel, int* cc)The same for the n-th hidden MIDI parameter in getParameterInfo's order: every channel's controllers, then the sixteen program changes.vst3::midiParamAt · vst3_wrapper.h:306 - fn
inline bool isMidiCcParam(Steinberg_Vst_ParamID id)vst3::isMidiCcParam · vst3_wrapper.h:315 - fn
inline double midiSpan(int cc)What a hidden MIDI parameter's normalised 1.0 is in MIDI: 14-bit pitch bend, 7-bit everything else (a program number included).vst3::midiSpan · vst3_wrapper.h:321 - fn
inline double midiCcDefault(int cc)Pitch bend rests at CENTRE, not at zero: a host restoring defaults would otherwise bend every voice to the bottom of its range.vst3::midiCcDefault · vst3_wrapper.h:326 - fn
inline bool hasBypassParam()vst3::hasBypassParam · vst3_wrapper.h:329 - fn
inline uint32_t speakerCount(Steinberg_Vst_SpeakerArrangement arr)VST3 speaker arrangements are bitmasks; the CHANNEL COUNT is the popcount. Negotiation stores whatever mask the host proposed (and echoes it back in getBusArrangement) rather than second-guessing which 6-channel layout it meant -- the DSP only ever sees the count.vst3::speakerCount · vst3_wrapper.h:335 - fn
inline uint64_t roleMaskFromArrangement(Steinberg_Vst_SpeakerArrangement arr)Our role mask for a VST3 arrangement, one role per channel, in the same order.vst3::roleMaskFromArrangement · vst3_wrapper.h:357 - fn
inline Steinberg_Vst_SpeakerArrangement defaultArrangementFor(uint32_t channels)vst3::defaultArrangementFor · vst3_wrapper.h:377 - fn
inline int unitCount()How many VST3 units the parameter table implies. Declared here because queryInterface consults it before the definition.vst3::unitCount · vst3_wrapper.h:400 - fn
inline uint32_t scaled(uint32_t logical, float factor)Logical pixels to device pixels, rounded rather than truncated: at 150% a 620-pixel editor is 930 and at 125% it is 775, and truncation loses a pixel off the edge on every odd multiple.vst3::scaled · vst3_wrapper.h:496 - fn
void destroyPlugin(Plugin* self)vst3::destroyPlugin · vst3_wrapper.h:621 - fn
inline Steinberg_tresult queryPlugin(Plugin* self, const Steinberg_TUID iid, void** obj)vst3::queryPlugin · vst3_wrapper.h:625 - fn
inline Steinberg_uint32 addRefPlugin(Plugin* self)vst3::addRefPlugin · vst3_wrapper.h:669 - fn
inline Steinberg_uint32 releasePlugin(Plugin* self)vst3::releasePlugin · vst3_wrapper.h:671 - fn
inline Steinberg_Vst_UnitID unitIdFor(const ParamInfo& p)vst3::unitIdFor · vst3_wrapper.h:700 - fn
inline Plugin* ownerOfUnits(void* p)vst3::ownerOfUnits · vst3_wrapper.h:706 - fn
inline Plugin* ownerOfComponent(void* p)vst3::ownerOfComponent · vst3_wrapper.h:708 - fn
inline Plugin* ownerOfProcessor(void* p)vst3::ownerOfProcessor · vst3_wrapper.h:709 - fn
inline Plugin* ownerOfController(void* p)vst3::ownerOfController · vst3_wrapper.h:710 - fn
inline Plugin* ownerOfMidiMapping(void* p)vst3::ownerOfMidiMapping · vst3_wrapper.h:711 - fn
inline Plugin* ownerOfNoteExpression(void* p)vst3::ownerOfNoteExpression · vst3_wrapper.h:712 - fn
inline Plugin* ownerOfContextReq(void* p)vst3::ownerOfContextReq · vst3_wrapper.h:713 - fn
inline Plugin* ownerOfInfoListener(void* p)vst3::ownerOfInfoListener · vst3_wrapper.h:714 - fn
inline Steinberg_tresult writeState(Plugin* self, Steinberg_IBStream* stream)vst3::writeState · vst3_wrapper.h:731 - fn
inline void readWholeStream(Steinberg_IBStream* stream, std::vector<uint8_t>& out)The whole stream, read to its end. A state blob is small; holding it is what lets the same restore be recognised when it arrives twice.vst3::readWholeStream · vst3_wrapper.h:761 - fn
inline uint64_t stateHash(const std::vector<uint8_t>& bytes)vst3::stateHash · vst3_wrapper.h:774 - fn
inline Steinberg_tresult applyStateBytes(Plugin* self, const std::vector<uint8_t>& bytes)vst3::applyStateBytes · vst3_wrapper.h:780 - fn
inline Steinberg_tresult readState(Plugin* self, Steinberg_IBStream* stream)vst3::readState · vst3_wrapper.h:794 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentInitialize( void* self, Steinberg_FUnknown* context)vst3::componentInitialize · vst3_wrapper.h:803 - fn
inline void keepHandler(Plugin* plugin, Steinberg_Vst_IComponentHandler* handler)Keep the host's component handler as COM says: a reference held while it is kept, given back when it is replaced or the controller terminates. A bare pointer left the plugin calling performEdit into whatever a host had freed after letting go of its own reference.vst3::keepHandler · vst3_wrapper.h:841 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentTerminate(void* self)vst3::componentTerminate · vst3_wrapper.h:849 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentGetControllerClassId( void*, Steinberg_TUID classId)vst3::componentGetControllerClassId · vst3_wrapper.h:856 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentSetIoMode(void*, Steinberg_Vst_IoMode)vst3::componentSetIoMode · vst3_wrapper.h:864 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE componentGetBusCount(void*, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir)vst3::componentGetBusCount · vst3_wrapper.h:868 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentGetBusInfo( void* self, Steinberg_Vst_MediaType type, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_Vst_BusInfo* bus)vst3::componentGetBusInfo · vst3_wrapper.h:889 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentGetRoutingInfo( void*, Steinberg_Vst_RoutingInfo*, Steinberg_Vst_RoutingInfo*)vst3::componentGetRoutingInfo · vst3_wrapper.h:929 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentActivateBus(void*, Steinberg_Vst_MediaType, Steinberg_Vst_BusDirection, Steinberg_int32, Steinberg_TBool)vst3::componentActivateBus · vst3_wrapper.h:934 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentSetActive(void* self, Steinberg_TBool state)vst3::componentSetActive · vst3_wrapper.h:942 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentSetState(void* self, Steinberg_IBStream* stream)vst3::componentSetState · vst3_wrapper.h:981 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE componentGetState(void* self, Steinberg_IBStream* stream)vst3::componentGetState · vst3_wrapper.h:986 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorSetBusArrangements( void* self, Steinberg_Vst_SpeakerArrangement* inputs, Steinberg_int32 numIns, Steinberg_Vst_SpeakerArrangement* outputs, Steinberg_int32 numOuts)vst3::processorSetBusArrangements · vst3_wrapper.h:993 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorGetBusArrangement( void* self, Steinberg_Vst_BusDirection dir, Steinberg_int32 index, Steinberg_Vst_SpeakerArrangement* arr)vst3::processorGetBusArrangement · vst3_wrapper.h:1025 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorCanProcessSampleSize( void*, Steinberg_int32 symbolicSampleSize)vst3::processorCanProcessSampleSize · vst3_wrapper.h:1056 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE processorGetLatencySamples(void* self)vst3::processorGetLatencySamples · vst3_wrapper.h:1068 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorSetupProcessing( void* self, Steinberg_Vst_ProcessSetup* setup)vst3::processorSetupProcessing · vst3_wrapper.h:1072 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorSetProcessing(void*, Steinberg_TBool)vst3::processorSetProcessing · vst3_wrapper.h:1088 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE processorGetTailSamples(void* self)vst3::processorGetTailSamples · vst3_wrapper.h:1092 - fn
inline TransportInfo readTransport(const Steinberg_Vst_ProcessContext* ctx)Musical time, VST3's spelling of it. Unlike CLAP's fixed-point beats these are already doubles in quarter notes, so the conversion is only about which validity flags the host set.vst3::readTransport · vst3_wrapper.h:1099 - fn
inline void drainUiEvents(Plugin* plugin)Apply what the user did to the interface. Values were already sent to the host from the main thread (viewOnMessage for the page, makeVst3EditorHost for the native editor), so here they only have to land on the DSP; this must not call back into the host.vst3::drainUiEvents · vst3_wrapper.h:1141 - fn
static void emitVst3MidiOut(Plugin* plugin, struct Steinberg_Vst_ProcessData* data, Steinberg_int32 frames)Translate the DSP's MIDI-out back into VST3 events. Format-agnostic (it reads shared.midiOut, not the audio buffer), so BOTH the float and the double process paths call it -- the 64-bit path used to skip it entirely, so an arpeggiator went mute the moment a host switched to 64-bit processing.vst3::emitVst3MidiOut · vst3_wrapper.h:1174 - fn
static inline void finishVst3Block(Plugin* plugin, Steinberg_Vst_ProcessData* data, uint32_t nAux)What every block owes at its end, in either precision: no output claims to be silent, and a state change the DSP reported marks the session dirty. One function because the 64-bit path returned before reaching the lines the float path ended with, and a 64-bit host's session was never marked.vst3::finishVst3Block · vst3_wrapper.h:1256 - fn
static inline int offsetInBlock(Steinberg_int32 offset, Steinberg_int32 frames)A host's sample offset, clamped into a block ofvst3::offsetInBlock · vst3_wrapper.h:1274frames: at or past the end a note-off was never reached and the note hung (see clapwrap::eventTime). - fn
static Steinberg_tresult processVst3Block(Plugin* plugin, Steinberg_Vst_ProcessData* data)One block of at most maxFrames: the whole of process() for a host that keeps to setupProcessing, and one piece of it otherwise (see processorProcess).vst3::processVst3Block · vst3_wrapper.h:1282 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE sliceNoInterface(void*, const Steinberg_TUID, void** obj)vst3::sliceNoInterface · vst3_wrapper.h:1766 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE sliceRef(void*)vst3::sliceRef · vst3_wrapper.h:1771 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE sliceEventCount(void* self)vst3::sliceEventCount · vst3_wrapper.h:1773 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE sliceEventGet(void* self, Steinberg_int32 index, Steinberg_Vst_Event* e)vst3::sliceEventGet · vst3_wrapper.h:1776 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE sliceEventAdd(void* self, Steinberg_Vst_Event* e)vst3::sliceEventAdd · vst3_wrapper.h:1785 - fn
inline Steinberg_Vst_IEventListVtbl& sliceEventListVtbl()vst3::sliceEventListVtbl · vst3_wrapper.h:1792 - fn
static Steinberg_Vst_ParamID SMTG_STDMETHODCALLTYPE sliceQueueId(void* self)vst3::sliceQueueId · vst3_wrapper.h:1806 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE sliceQueueCount(void* self)vst3::sliceQueueCount · vst3_wrapper.h:1810 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE sliceQueueGet(void* self, Steinberg_int32 index, Steinberg_int32* sampleOffset, Steinberg_Vst_ParamValue* value)vst3::sliceQueueGet · vst3_wrapper.h:1813 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE sliceQueueAdd(void*, Steinberg_int32, Steinberg_Vst_ParamValue, Steinberg_int32*)vst3::sliceQueueAdd · vst3_wrapper.h:1823 - fn
inline Steinberg_Vst_IParamValueQueueVtbl& sliceParamQueueVtbl()vst3::sliceParamQueueVtbl · vst3_wrapper.h:1828 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE sliceChangesCount(void* self)vst3::sliceChangesCount · vst3_wrapper.h:1851 - fn
static Steinberg_Vst_IParamValueQueue* SMTG_STDMETHODCALLTYPE sliceChangesGet(void* self, Steinberg_int32 index)vst3::sliceChangesGet · vst3_wrapper.h:1855 - fn
static Steinberg_Vst_IParamValueQueue* SMTG_STDMETHODCALLTYPE sliceChangesAdd( void* self, const Steinberg_Vst_ParamID* id, Steinberg_int32* index)vst3::sliceChangesAdd · vst3_wrapper.h:1876 - fn
inline Steinberg_Vst_IParameterChangesVtbl& sliceParamChangesVtbl()vst3::sliceParamChangesVtbl · vst3_wrapper.h:1881 - fn
static void sliceBus(const Steinberg_Vst_AudioBusBuffers& from, Steinberg_int32 offset, bool doubles, Steinberg_Vst_AudioBusBuffers& to, float** p32, double** p64)One of the host's buses, from framevst3::sliceBus · vst3_wrapper.h:1889offseton. The channel pointers live inp32/p64, which hold kMaxAudioChannels: no more is ever read. - fn
static void advanceContext(Steinberg_Vst_ProcessContext& ctx, Steinberg_int32 frames, double sampleRate)The process contextvst3::advanceContext · vst3_wrapper.h:1910frameslater: the clocks always, and while the transport plays the song position and the bar it is in. Not a cycle's wrap -- a host that loops ends the block there itself. - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE processorProcess( void* self, Steinberg_Vst_ProcessData* data)vst3::processorProcess · vst3_wrapper.h:1930 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE unitsGetUnitCount(void*)vst3::unitsGetUnitCount · vst3_wrapper.h:2019 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetUnitInfo( void*, Steinberg_int32 unitIndex, Steinberg_Vst_UnitInfo* info)vst3::unitsGetUnitInfo · vst3_wrapper.h:2023 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE unitsGetProgramListCount(void*)vst3::unitsGetProgramListCount · vst3_wrapper.h:2045 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetProgramListInfo( void*, Steinberg_int32 listIndex, Steinberg_Vst_ProgramListInfo* info)vst3::unitsGetProgramListInfo · vst3_wrapper.h:2049 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetProgramName( void*, Steinberg_Vst_ProgramListID listId, Steinberg_int32 programIndex, Steinberg_Vst_String128 name)vst3::unitsGetProgramName · vst3_wrapper.h:2059 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetProgramInfo(void*, Steinberg_Vst_ProgramListID, Steinberg_int32, Steinberg_Vst_CString, Steinberg_Vst_String128)vst3::unitsGetProgramInfo · vst3_wrapper.h:2068 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsHasProgramPitchNames( void*, Steinberg_Vst_ProgramListID, Steinberg_int32)vst3::unitsHasProgramPitchNames · vst3_wrapper.h:2076 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetProgramPitchName( void*, Steinberg_Vst_ProgramListID, Steinberg_int32, Steinberg_int16, Steinberg_Vst_String128)vst3::unitsGetProgramPitchName · vst3_wrapper.h:2081 - fn
static Steinberg_Vst_UnitID SMTG_STDMETHODCALLTYPE unitsGetSelectedUnit(void*)vst3::unitsGetSelectedUnit · vst3_wrapper.h:2087 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsSelectUnit(void*, Steinberg_Vst_UnitID)vst3::unitsSelectUnit · vst3_wrapper.h:2089 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsGetUnitByBus(void*, Steinberg_Vst_MediaType, Steinberg_Vst_BusDirection, Steinberg_int32, Steinberg_int32, Steinberg_Vst_UnitID* unitId)vst3::unitsGetUnitByBus · vst3_wrapper.h:2093 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE unitsSetUnitProgramData(void*, Steinberg_int32, Steinberg_int32, Steinberg_IBStream*)vst3::unitsSetUnitProgramData · vst3_wrapper.h:2101 - fn
inline Steinberg_Vst_IUnitInfoVtbl* unitsVtbl()vst3::unitsVtbl · vst3_wrapper.h:2107 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerInitialize(void*, Steinberg_FUnknown*)vst3::controllerInitialize · vst3_wrapper.h:2123 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerTerminate(void* self)vst3::controllerTerminate · vst3_wrapper.h:2127 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerSetComponentState( void* self, Steinberg_IBStream* stream)vst3::controllerSetComponentState · vst3_wrapper.h:2132 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerSetState(void*, Steinberg_IBStream*)vst3::controllerSetState · vst3_wrapper.h:2149 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerGetState(void*, Steinberg_IBStream*)vst3::controllerGetState · vst3_wrapper.h:2153 - fn
inline Steinberg_int32 firstMidiCcIndex()Index of the first hidden MIDI-controller parameter.vst3::firstMidiCcIndex · vst3_wrapper.h:2158 - fn
inline Steinberg_int32 programParamIndex()Index of the program-change parameter, or -1.vst3::programParamIndex · vst3_wrapper.h:2164 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE controllerGetParameterCount(void*)vst3::controllerGetParameterCount · vst3_wrapper.h:2168 - fn
inline void midiCcName(int channel, int cc, char* out, size_t capacity)"Mod Wheel Ch3", "Pitch Bend Ch1", "CC 34 Ch16" -- hidden, but a host that shows them in a MIDI-learn list should show something a human can read.vst3::midiCcName · vst3_wrapper.h:2174 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerGetParameterInfo( void*, Steinberg_int32 index, Steinberg_Vst_ParameterInfo* info)vst3::controllerGetParameterInfo · vst3_wrapper.h:2193 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerGetParamStringByValue( void*, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized, Steinberg_Vst_String128 string)vst3::controllerGetParamStringByValue · vst3_wrapper.h:2267 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerGetParamValueByString( void*, Steinberg_Vst_ParamID id, Steinberg_Vst_TChar* string, Steinberg_Vst_ParamValue* valueNormalized)vst3::controllerGetParamValueByString · vst3_wrapper.h:2297 - fn
static Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE controllerNormalizedParamToPlain( void*, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized)vst3::controllerNormalizedParamToPlain · vst3_wrapper.h:2337 - fn
static Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE controllerPlainParamToNormalized( void*, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue)vst3::controllerPlainParamToNormalized · vst3_wrapper.h:2348 - fn
inline void markDirtyIfNeeded(Plugin* plugin)[main-thread] Tell the host the session changed underneath it.vst3::markDirtyIfNeeded · vst3_wrapper.h:2379 - fn
inline void notifyLatencyIfChanged(Plugin* plugin)[main-thread] Tell the host the latency moved, if it did.vst3::notifyLatencyIfChanged · vst3_wrapper.h:2409 - fn
inline void announceOwnStateLoad(Plugin* plugin)[main-thread] The plugin changed its own state -- a preset loaded from its editor's preset bar, an undo -- and the host has to hear it, the VST3 way.vst3::announceOwnStateLoad · vst3_wrapper.h:2436 - fn
static Steinberg_Vst_ParamValue SMTG_STDMETHODCALLTYPE controllerGetParamNormalized( void* self, Steinberg_Vst_ParamID id)vst3::controllerGetParamNormalized · vst3_wrapper.h:2444 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerSetParamNormalized( void* self, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue value)vst3::controllerSetParamNormalized · vst3_wrapper.h:2476 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE contextReqGet(void*)vst3::contextReqGet · vst3_wrapper.h:2543 - fn
inline Steinberg_Vst_IProcessContextRequirementsVtbl* contextReqVtbl()vst3::contextReqVtbl · vst3_wrapper.h:2562 - fn
inline Steinberg_Vst_ChannelContext_IInfoListenerVtbl* infoListenerVtbl()vst3::infoListenerVtbl · vst3_wrapper.h:2628 - fn
inline const NoteExpressionSpec* noteExpressionTable(int* countOut)vst3::noteExpressionTable · vst3_wrapper.h:2661 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE noteExpressionGetCount(void*, Steinberg_int32 busIndex, Steinberg_int16 channel)vst3::noteExpressionGetCount · vst3_wrapper.h:2681 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE noteExpressionGetInfo( void*, Steinberg_int32 busIndex, Steinberg_int16 channel, Steinberg_int32 index, struct Steinberg_Vst_NoteExpressionTypeInfo* info)vst3::noteExpressionGetInfo · vst3_wrapper.h:2690 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE noteExpressionStringByValue( void*, Steinberg_int32, Steinberg_int16, Steinberg_Vst_NoteExpressionTypeID id, Steinberg_Vst_NoteExpressionValue valueNormalized, Steinberg_Vst_String128 string)vst3::noteExpressionStringByValue · vst3_wrapper.h:2716 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE noteExpressionValueByString( void*, Steinberg_int32, Steinberg_int16, Steinberg_Vst_NoteExpressionTypeID id, const Steinberg_Vst_TChar* string, Steinberg_Vst_NoteExpressionValue* valueNormalized)vst3::noteExpressionValueByString · vst3_wrapper.h:2731 - fn
inline Steinberg_Vst_INoteExpressionControllerVtbl* noteExpressionVtbl()vst3::noteExpressionVtbl · vst3_wrapper.h:2744 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE midiMappingGetAssignment( void*, Steinberg_int32 busIndex, Steinberg_int16 channel, Steinberg_Vst_CtrlNumber midiControllerNumber, Steinberg_Vst_ParamID* id)vst3::midiMappingGetAssignment · vst3_wrapper.h:2755 - fn
inline Steinberg_Vst_IMidiMappingVtbl* midiMappingVtbl()vst3::midiMappingVtbl · vst3_wrapper.h:2769 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE controllerSetComponentHandler( void* self, Steinberg_Vst_IComponentHandler* handler)vst3::controllerSetComponentHandler · vst3_wrapper.h:2777 - fn
Steinberg_IPlugView* SMTG_STDMETHODCALLTYPE controllerCreateView(void* self, Steinberg_FIDString name)vst3::controllerCreateView · vst3_wrapper.h:2783 - fn
inline Steinberg_Vst_IComponentVtbl& componentVtbl()vst3::componentVtbl · vst3_wrapper.h:2788 - fn
inline Steinberg_Vst_IAudioProcessorVtbl& processorVtbl()vst3::processorVtbl · vst3_wrapper.h:2799 - fn
inline Steinberg_Vst_IEditControllerVtbl& controllerVtbl()vst3::controllerVtbl · vst3_wrapper.h:2809 - fn
inline Plugin* createPlugin()vst3::createPlugin · vst3_wrapper.h:2822 - fn
inline Steinberg_FIDString nativePlatformType()Which platform handle this build embeds into.vst3::nativePlatformType · vst3_wrapper.h:2870 - fn
inline View* ownerOfView(void* p)vst3::ownerOfView · vst3_wrapper.h:2880 - fn
void destroyView(View* view)vst3::destroyView · vst3_wrapper.h:2882 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewQueryInterface(void* self, const Steinberg_TUID iid, void** obj)vst3::viewQueryInterface · vst3_wrapper.h:2884 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE viewAddRef(void* self)vst3::viewAddRef · vst3_wrapper.h:2903 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE viewRelease(void* self)vst3::viewRelease · vst3_wrapper.h:2907 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewIsPlatformTypeSupported( void*, Steinberg_FIDString type)vst3::viewIsPlatformTypeSupported · vst3_wrapper.h:2914 - fn
inline bool showHostContextMenu(Plugin* plugin, int paramIndex, int x, int y)Ask the host to show ITS menu for one parameter.vst3::showHostContextMenu · vst3_wrapper.h:2936 - fn
inline void chooseFileForPage(Plugin* plugin, const BridgeMessage& message)[main-thread] Show a native file browser and tell everyone what came back.vst3::chooseFileForPage · vst3_wrapper.h:2966 - fn
inline void viewOnMessage(Plugin* plugin, const BridgeMessage& message)A message from the page. Unlike CLAP (where the plugin emits parameter events from the audio thread), VST3 requires the host to be told through IComponentHandler on THIS (main) thread. So an edit goes two ways at once: to the host for automation and undo, and into the lock-free queue for the DSP. Sending only one of the two is how a knob either moves the sound without being recorded, or gets recorded without being heard.vst3::viewOnMessage · vst3_wrapper.h:3001 - fn
inline void viewTick(Plugin* plugin)The ~30 Hz editor clock: push whatever the page does not know yet.vst3::viewTick · vst3_wrapper.h:3094 - fn
static void requestViewResize(View* view, int width, int height)The user dragged an edge. Ask the host, through the frame it gave us.vst3::requestViewResize · vst3_wrapper.h:3121 - fn
static gfx::EditorHost makeVst3EditorHost(Plugin* plugin)The CLAP-side editor host, with the parts only VST3 can answer replaced.vst3::makeVst3EditorHost · vst3_wrapper.h:3141 - fn
static void prepareNativeEditor(View* view, Plugin* plugin)What a native editor needs told before it opens, at both call sites.vst3::prepareNativeEditor · vst3_wrapper.h:3185 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewAttached(void* self, void* parent, Steinberg_FIDString type)vst3::viewAttached · vst3_wrapper.h:3193 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewRemoved(void* self)vst3::viewRemoved · vst3_wrapper.h:3273 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewOnWheel(void*, float)vst3::viewOnWheel · vst3_wrapper.h:3294 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewOnKeyDown(void*, Steinberg_char16, Steinberg_int16, Steinberg_int16)vst3::viewOnKeyDown · vst3_wrapper.h:3297 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewOnKeyUp(void*, Steinberg_char16, Steinberg_int16, Steinberg_int16)vst3::viewOnKeyUp · vst3_wrapper.h:3301 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewOnFocus(void*, Steinberg_TBool)vst3::viewOnFocus · vst3_wrapper.h:3305 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewGetSize(void* self, Steinberg_ViewRect* size)What the host is told the editor needs, in PHYSICAL pixels.vst3::viewGetSize · vst3_wrapper.h:3321 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewSetContentScaleFactor(void* self, float factor)The host telling the plugin what a logical pixel is worth here.vst3::viewSetContentScaleFactor · vst3_wrapper.h:3342 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewOnSize(void* self, Steinberg_ViewRect* newSize)vst3::viewOnSize · vst3_wrapper.h:3378 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewSetFrame(void* self, Steinberg_IPlugFrame* frame)vst3::viewSetFrame · vst3_wrapper.h:3415 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewCanResize(void*)vst3::viewCanResize · vst3_wrapper.h:3426 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewCheckSizeConstraint(void* self, Steinberg_ViewRect* rect)vst3::viewCheckSizeConstraint · vst3_wrapper.h:3436 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE viewScaleQueryInterface(void* self, const Steinberg_TUID iid, void** obj)The scale interface's own three FUnknown slots forward to the view, so a host that releases through this pointer releases the view that owns it.vst3::viewScaleQueryInterface · vst3_wrapper.h:3462 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE viewScaleAddRef(void* self)vst3::viewScaleAddRef · vst3_wrapper.h:3468 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE viewScaleRelease(void* self)vst3::viewScaleRelease · vst3_wrapper.h:3474 - fn
inline Steinberg_IPlugViewContentScaleSupportVtbl& scaleVtbl()vst3::scaleVtbl · vst3_wrapper.h:3476 - fn
inline Steinberg_IPlugViewVtbl& viewVtbl()vst3::viewVtbl · vst3_wrapper.h:3483 - fn
inline const char* audioModuleCategory()The well-known category string every VST3 audio plugin declares. It lives in the C++ SDK rather than the C header, so it is spelled out here.vst3::audioModuleCategory · vst3_wrapper.h:3535 - fn
inline const char* subCategories()VST3 categorises plugins by a subcategory string; hosts sort their browsers by it, so an instrument that says "Fx" lands in the wrong folder forever.vst3::subCategories · vst3_wrapper.h:3539 - fn
inline Factory& factory()vst3::factory · vst3_wrapper.h:3553 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE factoryQueryInterface(void* self, const Steinberg_TUID iid, void** obj)vst3::factoryQueryInterface · vst3_wrapper.h:3555 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE factoryAddRef(void*)The factory is a process-wide singleton, so its refcount is bookkeeping the host can watch but never a reason to free anything.vst3::factoryAddRef · vst3_wrapper.h:3571 - fn
static Steinberg_uint32 SMTG_STDMETHODCALLTYPE factoryRelease(void*)vst3::factoryRelease · vst3_wrapper.h:3572 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE factoryGetFactoryInfo( void*, Steinberg_PFactoryInfo* info)vst3::factoryGetFactoryInfo · vst3_wrapper.h:3581 - fn
static Steinberg_int32 SMTG_STDMETHODCALLTYPE factoryCountClasses(void*)vst3::factoryCountClasses · vst3_wrapper.h:3592 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE factoryGetClassInfo(void*, Steinberg_int32 index, Steinberg_PClassInfo* info)vst3::factoryGetClassInfo · vst3_wrapper.h:3594 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE factoryCreateInstance(void*, Steinberg_FIDString cid, Steinberg_FIDString iid, void** obj)vst3::factoryCreateInstance · vst3_wrapper.h:3605 - fn
static Steinberg_tresult SMTG_STDMETHODCALLTYPE factoryGetClassInfo2(void*, Steinberg_int32 index, Steinberg_PClassInfo2* info)vst3::factoryGetClassInfo2 · vst3_wrapper.h:3624 - fn
inline Steinberg_IPluginFactory2Vtbl& factoryVtbl()vst3::factoryVtbl · vst3_wrapper.h:3640 - fn
SONORE_VST3_EXPORT Steinberg_IPluginFactory* GetPluginFactory()vst3_wrapper.h:3670 - fn
SONORE_VST3_EXPORT bool InitDll()vst3_wrapper.h:3676 - fn
SONORE_VST3_EXPORT bool ExitDll()vst3_wrapper.h:3677 - fn
SONORE_VST3_EXPORT bool bundleEntry(void*)vst3_wrapper.h:3679 - fn
SONORE_VST3_EXPORT bool bundleExit()vst3_wrapper.h:3680 - fn
SONORE_VST3_EXPORT bool ModuleEntry(void*)vst3_wrapper.h:3682 - fn
SONORE_VST3_EXPORT bool ModuleExit()vst3_wrapper.h:3683
Constants 9
- const
constexpr Steinberg_Vst_ParamID kBypassParamId = 0x62797073uVST3 spells host bypass as one extra automatable parameter carrying the kIsBypass flag. Its id is FIXED ('byps', as CLAP's is), so the real parameters keep index==id and appending one moves nothing: it was SONORE_NUM_PARAMS, and a session's bypass automation followed the number onto the parameter a new version added. Effects only: an instrument has no dry signal to pass, and hosts treat instrument bypass as their own mute.vst3::kBypassParamId · vst3_wrapper.h:212 - const
constexpr Steinberg_Vst_ParamID kProgramParamId = 0x7072676DuA plugin's presets showed up in CLAP through preset discovery and in LV2 as pset:Preset, and in VST3 as nothing at all: the IUnitInfo program half was a row of stubs returning "none". A saturator shipping three presets offered none of them in Cubase or Reaper.vst3::kProgramParamId · vst3_wrapper.h:225 - const
constexpr Steinberg_Vst_ProgramListID kProgramListId = 1vst3::kProgramListId · vst3_wrapper.h:226 - const
constexpr Steinberg_Vst_ParamID kMidiCcParamBase = 0x10000000uThis is the part of VST3 that surprises everyone who has written for any other format. Note on and note off arrive as events. Control change, pitch bend and aftertouch DO NOT. Steinberg's design routes them as ordinary PARAMETER changes, on ids the plugin publishes through IMidiMapping, and a plugin that does not implement that interface never sees a single one of them. No mod wheel, no sustain pedal, no pitch bend, no aftertouch.vst3::kMidiCcParamBase · vst3_wrapper.h:259 - const
constexpr int kMidiCcCount = 130vst3::kMidiCcCount · vst3_wrapper.h:260 - const
constexpr int kMidiChannels = 16vst3::kMidiChannels · vst3_wrapper.h:261 - const
constexpr int kMidiProgramSlot = Steinberg_Vst_ControllerNumbers_kCtrlProgramChangeProgram change is VST3's controller 130, and reaches a plugin the same way: as a parameter. It was refused, so a VST3 build never heard one while the CLAP, AU and LV2 builds of the same plugin did. Its sixteen ids come after the controllers' rather than among them: numbering it 130 inside each channel's block would have moved every id from channel 2 on, and a host that saved automation on one would have lost it.vst3::kMidiProgramSlot · vst3_wrapper.h:268 - const
constexpr int kMidiSlots = kMidiCcCount + 1vst3::kMidiSlots · vst3_wrapper.h:269 - const
constexpr Steinberg_Vst_ParamID kMidiProgramParamBase = kMidiCcParamBase + (Steinberg_Vst_ParamID) (kMidiChannels * kMidiCcCount)vst3::kMidiProgramParamBase · vst3_wrapper.h:270