VST SDK plugin example

Share your advanced PureBasic knowledge/code with the community.
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

VST SDK plugin example

Post by Aleks_Longard »

Hello all!
I wrote a small example that works on Windows x86 / x64. I only tested at Cockos Reaper, in other DAWs it should work just as well.
Thanks a lot for helping Infratec and fixing my a few bugs with pointers.

Code: Select all

;  file AEffect.pbi
;  VST SDK (version 2.4) for PureBasic
; tested only os Windows x86 / x64
; Alex Longard 20.02.2019
; Steinberg Media Technologies GmbH, All Rights Reserved

#kVstVersion = 2400
#kEffectMagic = $56737450

; prototypes for function pointers
PrototypeC.i AudioMasterCallback(*effect, opcode.l, index.l, Value.i, *ptr, opt.f)
PrototypeC.i DispatcherProc(*effect, opcode.l, index.l, Value.i, *ptr, opt.f)
PrototypeC ProcessProc(*effect, *inputs.Float, *outputs.Float, sampleframes.l)
PrototypeC SetParameterProc(*effect, index.l, parameter.f)
PrototypeC.f GetParameterProc(*effect, index.l)
PrototypeC ProcessReplacingProc(*effect, *inputs.Float, *outputs.Float, sampleframes.l)
PrototypeC ProcessDoubleReplacingProc(*effect, *inputs.Double, *outputs.Double, sampleframes.l)

; Basic VST Effect "C" Interface.
Structure AEffect Align #PB_Structure_AlignC
magic.l  ; must be #kEffectMagic ('VstP')
dispatcher.DispatcherProc  ; Host to Plug-in dispatcher
process.ProcessProc  ; \deprecated Accumulating process mode is deprecated in VST 2.4! Use AEffect::processReplacing instead!
setParameter.SetParameterProc  ; Set new value of automatable parameter
getParameter.GetParameterProc  ; Returns current value of automatable parameter
numPrograms.l  ; number of programs
numParams.l  ; all programs are assumed to have numParams parameters
numInputs.l  ; number of audio inputs
numOutputs.l  ; number of audio outputs
flags.l  ; @see VstAEffectFlags
*resvd1  ; reserved for Host, must be 0
*resvd2  ; reserved for Host, must be 0
initialDelay.l  ; for algorithms which need input in the first place (Group delay or latency in Samples). This value should be initialized in a resume state.
realQualities.l  ; \deprecated unused member
offQualities.l  ; \deprecated unused member
ioRatio.f  ; \deprecated unused member
*Object  ; #AudioEffect class pointer (for PB must be 0)
*user  ; user defined pointer
uniqueID.l  ; registered unique identifier (register it at Steinberg 3rd party support Web). This is used to identify a plug-in during save+load of preset and project.
version.l  ; plug-in version (example 1100 for version 1.1.0.0)
processReplacing.ProcessReplacingProc  ; Process audio samples in replacing mode
processDoubleReplacing.ProcessDoubleReplacingProc  ; Process double-precision audio samples in replacing mode
Array future.b(56)  ; reserved for future use (please zero)
EndStructure

; AEffect flags
#effFlagsHasEditor = 1  ; set If the plug-in provides a custom editor
#effFlagsCanReplacing = 16  ; supports replacing process mode (which should the Default mode in VST 2.4)
#effFlagsProgramChunks = 32  ; program Data is handled in formatless chunks
#effFlagsIsSynth = 256  ; plug-in is a synth (VSTi), Host may assign mixer channels For its outputs
#effFlagsNoSoundInStop = 512  ; plug-in does Not produce sound when input is all silence
#effFlagsCanDoubleReplacing = 4096  ; plug-in supports double precision processing
#effFlagsHasClip = 2  ; deprecated in VST 2.4
#effFlagsHasVu = 4  ; deprecated in VST 2.4
#effFlagsCanMono = 16  ; deprecated in VST 2.4
#effFlagsExtIsAsync = 1024  ; deprecated in VST 2.4
#effFlagsExtHasBuffer = 2048  ; deprecated in VST 2.4

; Basic dispatcher Opcodes (Host To Plug-in) */
#effOpen = 0  ; no arguments
#effClose = 1  ; no arguments

#effSetProgram = 2  ; [value]: new program number
#effGetProgram = 3  ; [Return value]: current program number
#effSetProgramName = 4  ; [ptr]: char* With new program name, limited To #kVstMaxProgNameLen
#effGetProgramName = 5  ; [ptr]: char buffer For current program name, limited To #kVstMaxProgNameLen

#effGetParamLabel = 6  ; [ptr]: char buffer For parameter label, limited To #kVstMaxParamStrLen
#effGetParamDisplay = 7; [ptr]: char buffer For parameter display, limited To #kVstMaxParamStrLen
#effGetParamName = 8   ; [ptr]: char buffer For parameter name, limited To #kVstMaxParamStrLen

#effGetVu = 9  ; deprecated in VST 2.4

#effSetSampleRate = 10  ; [opt]: new sample rate For audio processing
#effSetBlockSize = 11   ; [value]: new maximum block size For audio processing
#effMainsChanged = 12  ; [value]: 0 means "turn off", 1 means "turn on" @see AudioEffect::suspend @see AudioEffect::resume

#effEditGetRect = 13  ; [ptr]: #ERect** receiving pointer To editor size
#effEditOpen = 14  ; [ptr]: system dependent Window pointer, e.g. HWND on Windows  @see AEffEditor::open
#effEditClose = 15  ; no arguments

#effEditDraw = 16  ; deprecated in VST 2.4
#effEditMouse = 17  ; deprecated in VST 2.4
#effEditKey = 18  ; deprecated in VST 2.4

#effEditIdle = 19  ; no arguments

#effEditTop = 20  ; deprecated in VST 2.4
#effEditSleep = 21  ; deprecated in VST 2.4
#effIdentify = 22  ; deprecated in VST 2.4

#effGetChunk = 23  ; [ptr]: void** For chunk Data address [index]: 0 For bank, 1 For program
#effSetChunk = 24  ; [ptr]: chunk Data [value]: byte size [index]: 0 For bank, 1 For program

#effNumOpcodes = 25

; Basic dispatcher Opcodes (Plug-in To Host)
#audioMasterAutomate = 0  ; [index]: parameter index [opt]: parameter value
#audioMasterVersion = 1   ; [Return value]: Host VST version (For example 2400 For VST 2.4)
#audioMasterCurrentId = 2 ; [Return value]: current unique identifier on shell plug-in
#audioMasterIdle = 3      ; no arguments
#audioMasterPinConnected = 4  ; deprecated in VST 2.4 r2

; String length limits (in characters excl. 0 byte)
#kVstMaxProgNameLen = 24  ; used For #effGetProgramName, #effSetProgramName, #effGetProgramNameIndexed
#kVstMaxParamStrLen = 12  ; used For #effGetParamLabel, #effGetParamDisplay, #effGetParamName
#kVstMaxVendorStrLen = 64  ; used For #effGetVendorString, #audioMasterGetVendorString
#kVstMaxProductStrLen = 64  ; used For #effGetProductString, #audioMasterGetProductString
#kVstMaxEffectNameLen = 32  ; used For #effGetEffectName

; Structure used For #effEditGetRect.
Structure ERect Align #PB_Structure_AlignC
top.l  ; top coordinate
left.l  ; left coordinate
bottom.l  ; bottom coordinate
right.l  ; right coordinate
EndStructure

Code: Select all

;  file AEffectX.pbi
;  VST SDK (version 2.4) for PureBasic
; tested only os Windows x86 / x64
; Alex Longard 20.08.2020
; Steinberg Media Technologies GmbH, All Rights Reserved
XIncludeFile "aeffect.pbi"

; String length limits (in characters excl. 0 byte).
; Vst2StringConstants
#kVstMaxNameLen = 64  ; used For #MidiProgramName, #MidiProgramCategory, #MidiKeyName, #VstSpeakerProperties, #VstPinProperties
#kVstMaxLabelLen = 64  ; used For #VstParameterProperties->label, #VstPinProperties->label
#kVstMaxShortLabelLen = 8  ; used For #VstParameterProperties->shortLabel, #VstPinProperties->shortLabel
#kVstMaxCategLabelLen = 24  ; used For #VstParameterProperties->label
#kVstMaxFileNameLen = 100  ; used For #VstAudioFile->name

; VstEvent
; A generic timestamped event.
Structure VstEvent Align #PB_Structure_AlignC
type.l  ; @see VstEventTypes
byteSize.l  ; size of this event, excl. type and byteSize
deltaFrames.l  ; sample frames related to the current block start sample position
flags.l  ; generic flags, none defined yet
Array Data.b(15)  ; data size may vary, depending on event type
EndStructure

; VstEvent Types used by #VstEvent.
#kVstMidiType = 1  ; MIDI event  @see VstMidiEvent
#kVstAudioType = 2  ; deprecated unused event type
#kVstVideoType = 3  ; deprecated unused event type
#kVstParameterType = 4  ; deprecated unused event type
#kVstTriggerType = 5  ; deprecated unused event type
#kVstSysExType = 6  ; MIDI system exclusive  @see VstMidiSysexEvent

; A block of events For the current processed audio block.
Structure VstEvents Align #PB_Structure_AlignC
numEvents.l  ; number of Events in array
*reserved  ; zero (Reserved for future use)
*events.VstEvent[1]  ; event pointer array, variable size
EndStructure

; MIDI Event (To be casted from VstEvent).
Structure VstMidiEvent Align #PB_Structure_AlignC
type.l  ; #kVstMidiType
byteSize.l  ; sizeof (VstMidiEvent)
deltaFrames.l ; sample frames related To the current block start sample position
flags.l ; @see VstMidiEventFlags
noteLength.l  ; (in sample frames) of entire note, if available, else 0
noteOffset.l  ; offset (in sample frames) into note from note start if available, else 0
midiData.b[4]  ; 1 to 3 MIDI bytes; midiData[3] is reserved (zero)
detune.c  ; -64 to +63 cents; for scales other than 'well-tempered' ('microtuning')
noteOffVelocity.b  ; Note Off Velocity [0, 127]
reserved1.b  ; zero (Reserved for future use)
reserved2.b  ; zero (Reserved for future use)
EndStructure

; Flags used in #VstMidiEvent.
; VstMidiEventFlags
#kVstMidiEventIsRealtime = 1  ; means that this event is played life (Not in playback from a sequencer track).\n This allows the Plug-In To handle these flagged events With higher priority, especially when the Plug-In has a big latency (AEffect::initialDelay)

; MIDI Sysex Event (To be casted from #VstEvent).
Structure VstMidiSysexEvent Align #PB_Structure_AlignC
type.l  ; #kVstSysexType
byteSize.l  ; sizeof (VstMidiSysexEvent)
deltaFrames.l  ; sample frames related to the current block start sample position
flags.l  ; none defined yet (should be zero)
dumpBytes.l  ; byte size of sysexDump
*resvd1  ; zero (Reserved for future use)
sysexDump.b  ; sysex dump
*resvd2  ; zero (Reserved for future use)
EndStructure

; VstTimeInfo requested via #audioMasterGetTime.  @see AudioEffectX::getTimeInfo
; note VstTimeInfo::samplePos :Current Position. It must always be valid, And should Not cost a lot To ask For. The sample position is ahead of the time displayed To the user. In sequencer stop mode, its value does Not change. A 32 bit integer is too small For sample positions, And it's a double to make it easier to convert between ppq and samples.
; note VstTimeInfo::ppqPos : At tempo 120, 1 quarter makes 1/2 second, so 2.0 ppq translates To 48000 samples at 48kHz sample rate.
; .25 ppq is one sixteenth note then. If you need something like 480ppq, you simply multiply ppq by that scaler.
; note VstTimeInfo::barStartPos : Say we're at bars/beats readout 3.3.3. That's 2 bars + 2 q + 2 sixteenth, makes 2 * 4 + 2 + .25 = 10.25 ppq. at tempo 120, that's 10.25 * .5 = 5.125 seconds, times 48000 = 246000 samples (if my calculator servers me well :-). 
; note VstTimeInfo::samplesToNextClock : MIDI Clock Resolution (24 per Quarter Note), can be negative the distance To the Next midi clock (24 ppq, pulses per quarter) in samples. unless samplePos falls precicely on a midi clock, this will either be negative such that the previous MIDI clock is addressed, Or positive when referencing the following (future) MIDI clock.
Structure VstTimeInfo Align #PB_Structure_AlignC
samplePos.d  ; current Position in audio samples (always valid)
sampleRate.d  ; current Sample Rate in Herz (always valid)
nanoSeconds.d  ; System Time in nanoseconds (10^-9 second)
ppqPos.d  ; Musical Position, in Quarter Note (1.0 equals 1 Quarter Note)
tempo.d  ; current Tempo in BPM (Beats Per Minute)
barStartPos.d  ; last Bar Start Position, in Quarter Note
cycleStartPos.d  ; Cycle Start (left locator), in Quarter Note
cycleEndPos.d  ; Cycle End (right locator), in Quarter Note
timeSigNumerator.l  ; Time Signature Numerator (e.g. 3 for 3/4)
timeSigDenominator.l  ; Time Signature Denominator (e.g. 4 for 3/4)
smpteOffset.l  ; SMPTE offset (in SMPTE subframes (bits; 1/80 of a frame)). The current SMPTE position can be calculated using #samplePos, #sampleRate, and #smpteFrameRate.
smpteFrameRate.l  ; @see VstSmpteFrameRate
samplesToNextClock.l  ; MIDI Clock Resolution (24 Per Quarter Note), can be negative (nearest clock)
flags.l  ; @see VstTimeInfoFlags
EndStructure

; Flags used in #VstTimeInfo.
#kVstTransportChanged = 1  ; indicates that play, cycle Or record state has changed
#kVstTransportPlaying = 2  ; set If Host sequencer is currently playing
#kVstTransportCycleActive = 4  ; set If Host sequencer is in cycle mode
#kVstTransportRecording = 8  ; set If Host sequencer is in record mode
#kVstAutomationWriting = 64  ; set If automation write mode active (record parameter changes)
#kVstAutomationReading = 128  ; set If automation Read mode active (play parameter changes)
#kVstNanosValid = 256  ; VstTimeInfo::nanoSeconds valid
#kVstPpqPosValid = 512  ; VstTimeInfo::ppqPos valid
#kVstTempoValid = 1024  ; VstTimeInfo::tempo valid
#kVstBarsValid = 2048  ; VstTimeInfo::barStartPos valid
#kVstCyclePosValid = 4096  ; VstTimeInfo::cycleStartPos And VstTimeInfo::cycleEndPos valid
#kVstTimeSigValid = 8192  ; VstTimeInfo::timeSigNumerator And VstTimeInfo::timeSigDenominator valid
#kVstSmpteValid = 16384  ; VstTimeInfo::smpteOffset And VstTimeInfo::smpteFrameRate valid
#kVstClockValid = 32768  ; VstTimeInfo::samplesToNextClock valid

; SMPTE Frame Rates.
#kVstSmpte24fps = 0  ; 24 fps
#kVstSmpte25fps = 1  ; 25 fps
#kVstSmpte2997fps = 2  ; 29.97 fps
#kVstSmpte30fps = 3  ; 30 fps
#kVstSmpte2997dfps = 4  ; 29.97 drop
#kVstSmpte30dfps = 5  ; 30 drop
#kVstSmpteFilm16mm = 6  ; Film 16mm
#kVstSmpteFilm35mm = 7  ; Film 35mm
#kVstSmpte239fps = 10  ; HDTV: 23.976 fps
#kVstSmpte249fps = 11  ; HDTV: 24.976 fps
#kVstSmpte599fps = 12  ; HDTV: 59.94 fps
#kVstSmpte60fps = 13  ; HDTV: 60 fps

; Variable IO For Offline Processing.
Structure VstVariableIo Align #PB_Structure_AlignC
*inputs.Float  ; input audio buffers
*outputs.Float  ; output audio buffers
numSamplesInput.l  ; number of incoming samples
numSamplesOutput.l  ; number of outgoing samples
*numSamplesInputProcessed.integer  ; number of samples actually processed of input
*numSamplesOutputProcessed.integer  ; number of samples actually processed of output
EndStructure

; Language code returned by audioMasterGetLanguage.
#kVstLangEnglish = 1  ; English
#kVstLangGerman = 2  ; German
#kVstLangFrench = 3  ; French
#kVstLangItalian = 4  ; Italian
#kVstLangSpanish = 5  ; Spanish
#kVstLangJapanese = 6  ; Japanese

; VST 2.x dispatcher Opcodes (Plug-in To Host). Extension of #AudioMasterOpcodes
; AudioMasterOpcodesX
#audioMasterWantMidi = #audioMasterPinConnected + 2  ; deprecated in VST 2.4
#audioMasterGetTime = 7  ; [Return value]: #VstTimeInfo* Or null If Not supported [value]: request mask  @see VstTimeInfoFlags @see AudioEffectX::getTimeInfo
#audioMasterProcessEvents = 8  ; [ptr]: pointer To #VstEvents  @see VstEvents @see AudioEffectX::sendVstEventsToHost
#audioMasterSetTime = 9  ; deprecated in VST 2.4
#audioMasterTempoAt = 10  ; deprecated in VST 2.4
#audioMasterGetNumAutomatableParameters = 11  ; deprecated in VST 2.4
#audioMasterGetParameterQuantization = 12  ; deprecated in VST 2.4
#audioMasterIOChanged = 13  ; [Return value]: 1 If supported  @see AudioEffectX::ioChanged
#audioMasterNeedIdle = 14  ; deprecated in VST 2.4
#audioMasterSizeWindow = 15  ; [index]: new width [value]: new height [Return value]: 1 If supported  @see AudioEffectX::sizeWindow
#audioMasterGetSampleRate = 16  ; [Return value]: current sample rate  @see AudioEffectX::updateSampleRate
#audioMasterGetBlockSize = 17  ; [Return value]: current block size  @see AudioEffectX::updateBlockSize
#audioMasterGetInputLatency = 18  ; [Return value]: input latency in audio samples  @see AudioEffectX::getInputLatency
#audioMasterGetOutputLatency = 19  ; [Return value]: output latency in audio samples  @see AudioEffectX::getOutputLatency
#audioMasterGetPreviousPlug = 20  ; deprecated in VST 2.4
#audioMasterGetNextPlug = 21  ; deprecated in VST 2.4
#audioMasterWillReplaceOrAccumulate = 22  ; deprecated in VST 2.4
#audioMasterGetCurrentProcessLevel = 23  ; [Return value]: current process level  @see VstProcessLevels
#audioMasterGetAutomationState = 24  ; [Return value]: current automation state  @see VstAutomationStates
#audioMasterOfflineStart = 25  ; [index]: numNewAudioFiles [value]: numAudioFiles [ptr]: #VstAudioFile*  @see AudioEffectX::offlineStart
#audioMasterOfflineRead = 26  ; [index]: bool readSource [value]: #VstOfflineOption* @see VstOfflineOption [ptr]: #VstOfflineTask*  @see VstOfflineTask @see AudioEffectX::offlineRead
#audioMasterOfflineWrite = 27  ; @see audioMasterOfflineRead @see AudioEffectX::offlineRead
#audioMasterOfflineGetCurrentPass = 28  ; @see AudioEffectX::offlineGetCurrentPass
#audioMasterOfflineGetCurrentMetaPass = 29  ; @see AudioEffectX::offlineGetCurrentMetaPass
#audioMasterSetOutputSampleRate = 30  ; deprecated in VST 2.4
#audioMasterGetOutputSpeakerArrangement = 31  ; deprecated in VST 2.4
#audioMasterGetVendorString = 32  ; [ptr]: char buffer For vendor string, limited To #kVstMaxVendorStrLen  @see AudioEffectX::getHostVendorString
#audioMasterGetProductString = 33  ; [ptr]: char buffer For vendor string, limited To #kVstMaxProductStrLen  @see AudioEffectX::getHostProductString
#audioMasterGetVendorVersion = 34  ; [Return value]: vendor-specific version  @see AudioEffectX::getHostVendorVersion
#audioMasterVendorSpecific = 35  ; no definition, vendor specific handling  @see AudioEffectX::hostVendorSpecific
#audioMasterSetIcon = 36  ; deprecated in VST 2.4
#audioMasterCanDo = 37  ; [ptr]: "can do" string [Return value]: 1 For supported
#audioMasterGetLanguage = 38  ; [Return value]: language code  @see VstHostLanguage
#audioMasterOpenWindow = 39  ; deprecated in VST 2.4
#audioMasterCloseWindow = 40  ; deprecated in VST 2.4
#audioMasterGetDirectory = 41  ; [Return value]: FSSpec on MAC, Else char*  @see AudioEffectX::getDirectory
#audioMasterUpdateDisplay = 42  ; no arguments
#audioMasterBeginEdit = 43  ; [index]: parameter index  @see AudioEffectX::beginEdit
#audioMasterEndEdit = 44  ; [index]: parameter index  @see AudioEffectX::endEdit
#audioMasterOpenFileSelector = 45  ; [ptr]: VstFileSelect* [Return value]: 1 If supported  @see AudioEffectX::openFileSelector
#audioMasterCloseFileSelector = 46  ; [ptr]: VstFileSelect*  @see AudioEffectX::closeFileSelector
#audioMasterEditFile = 47  ; deprecated in VST 2.4
#audioMasterGetChunkFile = 48  ; deprecated in VST 2.4 [ptr]: char[2048] Or SizeOf (FSSpec) [Return value]: 1 If supported  @see AudioEffectX::getChunkFile
#audioMasterGetInputSpeakerArrangement = 49  ; deprecated in VST 2.4

; VST 2.x dispatcher Opcodes (Host To Plug-in). Extension of #AEffectOpcodes
; AEffectXOpcodes
#effProcessEvents = 25  ; [ptr]: #VstEvents*
#effCanBeAutomated = 26 ; [index]: parameter index [Return value]: 1=true, 0=false
#effString2Parameter = 27  ; [index]: parameter index [ptr]: parameter string [Return value]: true For success

#effGetNumProgramCategories = 28  ; deprecated in VST 2.4
#effGetProgramNameIndexed = 29    ; [index]: program index [ptr]: buffer For program name, limited To #kVstMaxProgNameLen [Return value]: true For success
#effCopyProgram = 30  ; deprecated in VST 2.4
#effConnectInput = 31  ; deprecated in VST 2.4
#effConnectOutput = 32  ; deprecated in VST 2.4
#effGetInputProperties = 33  ; [index]: input index [ptr]: #VstPinProperties* [Return value]: 1 If supported
#effGetOutputProperties = 34 ; [index]: output index [ptr]: #VstPinProperties* [Return value]: 1 If supported
#effGetPlugCategory = 35     ; [Return value]: category  @see VstPlugCategory

#effGetCurrentPosition = 36  ; deprecated in VST 2.4
#effGetDestinationBuffer = 37  ; deprecated in VST 2.4

#effOfflineNotify = 38  ; [ptr]: #VstAudioFile Array [value]: count [index]: start flag
#effOfflinePrepare = 39 ; [ptr]: #VstOfflineTask Array [value]: count
#effOfflineRun = 40      ; [ptr]: #VstOfflineTask Array [value]: count

#effProcessVarIo = 41  ; [ptr]: #VstVariableIo*
#effSetSpeakerArrangement = 42  ; [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement*

#effSetBlockSizeAndSampleRate = 43  ; deprecated in VST 2.4

#effSetBypass = 44  ; [value]: 1 = bypass, 0 = no bypass
#effGetEffectName = 45  ; [ptr]: buffer For effect name, limited To #kVstMaxEffectNameLen

#effGetErrorText = 46  ; deprecated in VST 2.4

#effGetVendorString = 47  ; [ptr]: buffer For effect vendor string, limited To #kVstMaxVendorStrLen
#effGetProductString = 48 ; [ptr]: buffer For effect vendor string, limited To #kVstMaxProductStrLen
#effGetVendorVersion = 49 ; [Return value]: vendor-specific version
#effVendorSpecific = 50   ; no definition, vendor specific handling
#effCanDo = 51            ; [ptr]: "can do" string [Return value]: 0: "don't know" -1: "no" 1: "yes"
#effGetTailSize = 52  ; [Return value]: tail size (For example the reverb time of a reverb plug-in); 0 is default (return 1 for 'no tail')

#effIdle = 53  ; deprecated in VST 2.4
#effGetIcon = 54  ; deprecated in VST 2.4
#effSetViewPosition = 55  ; deprecated in VST 2.4

#effGetParameterProperties = 56  ; [index]: parameter index [ptr]: #VstParameterProperties* [Return value]: 1 If supported

#effKeysRequired = 57  ; deprecated in VST 2.4

#effGetVstVersion = 58  ; [Return value]: VST version

; VST_2_1_EXTENSIONS
; #effEditKeyDown = 59  ; [index]: ASCII character [value]: virtual key [opt]: modifiers [Return value]: 1 If key used
; #effEditKeyUp = 60    ; [index]: ASCII character [value]: virtual key [opt]: modifiers [Return value]: 1 If key used
; #effSetEditKnobMode = 61  ; [value]: knob mode 0: circular, 1: circular relativ, 2: linear (CKnobMode in VSTGUI)
; #effGetMidiProgramName = 62  ; [index]: MIDI channel [ptr]: #MidiProgramName* [Return value]: number of used programs, 0 If unsupported
; #effGetCurrentMidiProgram = 63  ; [index]: MIDI channel [ptr]: #MidiProgramName* [Return value]: index of current program
; #effGetMidiProgramCategory = 64 ; [index]: MIDI channel [ptr]: #MidiProgramCategory* [Return value]: number of used categories, 0 If unsupported
; #effHasMidiProgramsChanged = 65 ; [index]: MIDI channel [Return value]: 1 If the #MidiProgramName(s) Or #MidiKeyName(s) have changed
; #effGetMidiKeyName = 66         ; [index]: MIDI channel [ptr]: #MidiKeyName* [Return value]: true If supported, false otherwise
; #effBeginSetProgram = 67  ; no arguments  @see AudioEffectX::beginSetProgram
; #effEndSetProgram = 68    ; no arguments

; VST_2_3_EXTENSIONS
; #effGetSpeakerArrangement = 69  ; [value]: input #VstSpeakerArrangement* [ptr]: output #VstSpeakerArrangement*
; #effShellGetNextPlugin = 70     ; [ptr]: buffer For plug-in name, limited To #kVstMaxProductStrLen [Return value]: Next plugin's uniqueID
; #effStartProcess = 71           ; no arguments
; #effStopProcess = 72            ; no arguments
; #effSetTotalSampleToProcess = 73; [value]: number of samples To process, offline only!
; #effSetPanLaw = 74              ; [value]: pan law [opt]: gain
; #effBeginLoadBank = 75          ; [ptr]: #VstPatchChunkInfo* [Return value]: -1: bank can't be loaded, 1: bank can be loaded, 0: unsupported
; #effBeginLoadProgram = 76       ; [ptr]: #VstPatchChunkInfo* [Return value]: -1: prog can't be loaded, 1: prog can be loaded, 0: unsupported

; VST_2_4_EXTENSIONS
#effSetProcessPrecision = 59  ; [value]: @see VstProcessPrecision
#effGetNumMidiInputChannels = 60  ; [Return value]: number of used MIDI input channels (1-15)
#effGetNumMidiOutputChannels = 61 ; [Return value]: number of used MIDI output channels (1-15)

; Symbolic precision constants used For effSetProcessPrecision.
; VstProcessPrecision
#kVstProcessPrecision32 = 0  ; single precision float (32bits)
#kVstProcessPrecision64 = 1  ; double precision (64bits)

; Parameter Properties used in #effGetParameterProperties.
Structure VstParameterProperties Align #PB_Structure_AlignC
stepFloat.f  ; float step
smallStepFloat.f  ; small float step
largeStepFloat.f  ; large float step
label.s{#kVstMaxLabelLen}  ; parameter label
flags.l  ; @see VstParameterFlags
minInteger.l  ; integer minimum
maxInteger.l  ; integer maximum
stepInteger.l  ; integer step
largeStepInteger.l  ; large integer Step
shortLabel.s{#kVstMaxShortLabelLen}  ; short label, recommended: 6 + delimiter

; The following are For remote controller display purposes.
; Note that the kVstParameterSupportsDisplayIndex flag must be set.
; Host can scan all parameters, And find out in what order To display them:

displayIndex.w  ; index where this parameter should be displayed (starting with 0)

; Host can also possibly display the parameter group (category), such As...
; Osc 1
; Wave  Detune  Octave  Mod
; ...If the plug-in supports it (flag #kVstParameterSupportsDisplayCategory)

category.w  ; 0: no category, else group index + 1
numParametersInCategory.w  ; number of parameters in category
reserved.w  ; zero
categoryLabel.s{#kVstMaxCategLabelLen}  ; category label, e.g. "Osc 1" 

future.c[16]  ; reserved for future use
EndStructure

; Flags used in #VstParameterProperties.
; VstParameterFlags
#kVstParameterIsSwitch = 1  ;  parameter is a switch (on/off)
#kVstParameterUsesIntegerMinMax = 2  ; minInteger, maxInteger valid
#kVstParameterUsesFloatStep = 4  ; stepFloat, smallStepFloat, largeStepFloat valid
#kVstParameterUsesIntStep = 8  ; stepInteger, largeStepInteger valid
#kVstParameterSupportsDisplayIndex  = 16  ; displayIndex valid
#kVstParameterSupportsDisplayCategory = 32  ; category, etc. valid
#kVstParameterCanRamp = 64  ; set If parameter value can ramp up/down

; Pin Properties used in #effGetInputProperties And #effGetOutputProperties.
Structure VstPinProperties Align #PB_Structure_AlignC
label.c[#kVstMaxLabelLen]  ; pin name
flags.l  ; @see VstPinPropertiesFlags
arrangementType.l  ; @see VstSpeakerArrangementType
shortLabel.c[#kVstMaxShortLabelLen]  ; short name (recommended: 6 + delimiter)
future.b[48]  ; reserved for future use
EndStructure

; Flags used in #VstPinProperties.
; VstPinPropertiesFlags
#kVstPinIsActive = 1  ; pin is active, ignored by Host
#kVstPinIsStereo = 2  ; pin is first of a stereo pair
#kVstPinUseSpeaker = 4  ; #VstPinProperties::arrangementType is valid And can be used To get the wanted arrangement

; Plug-in Categories.
; VstPlugCategory
#kPlugCategUnknown = 0  ; Unknown, category Not implemented
#kPlugCategEffect = 1  ; Simple Effect
#kPlugCategSynth = 2  ; VST Instrument (Synths, samplers,...)
#kPlugCategAnalysis = 3  ; Scope, Tuner, ...
#kPlugCategMastering = 4  ; Dynamics, ...
#kPlugCategSpacializer = 5  ; Panners, ...
#kPlugCategRoomFx = 6  ; Delays And Reverbs
#kPlugSurroundFx = 7  ; Dedicated surround processor
#kPlugCategRestoration = 8  ; Denoiser, ...
#kPlugCategOfflineProcess = 9  ; Offline Process
#kPlugCategShell = 10  ; Plug-in is container of other plug-ins  @see effShellGetNextPlugin
#kPlugCategGenerator = 11  ; ToneGenerator, ...
#kPlugCategMaxCount = 12  ; Marker To count the categories

; MIDI Programs
; MIDI Program Description.
Structure MidiProgramName Align #PB_Structure_AlignC
thisProgramIndex.l  ; 0 or greater: fill struct for this program index
name.c[#kVstMaxNameLen]  ; program name
midiProgram.c  ; -1:off, 0-127
midiBankMsb.c  ; -1:off, 0-127
midiBankLsb.c  ; -1:off, 0-127
reserved.b  ; zero
parentCategoryIndex.l  ; -1:no parent category
flags.l  ; omni etc. @see VstMidiProgramNameFlags
EndStructure

; Flags used in MidiProgramName.
; VstMidiProgramNameFlags
#kMidiIsOmni = 1  ; Default is multi. For omni mode, channel 0 is used For inquiries And program changes

Structure MidiProgramCategory Align #PB_Structure_AlignC
thisCategoryIndex.l  ; 0 or greater:  fill struct for this category index.
name.c[#kVstMaxNameLen]  ; name
parentCategoryIndex.l  ; -1:no parent category
flags.l  ; reserved, none defined yet, zero.
EndStructure

; MIDI Key Description.
Structure MidiKeyName Align #PB_Structure_AlignC
thisProgramIndex.l  ; 0 or greater:  fill struct for this program index.
thisKeyNumber.l  ; 0 - 127. fill struct for this key number.
keyName.c[#kVstMaxNameLen]  ; key name, empty means regular key names
reserved.l  ; zero
flags.l  ; reserved, none defined yet, zero.
EndStructure

; Surround Setup
; Speaker Properties.
; The origin For azimuth is Right (As by math conventions dealing With radians).
; The elevation origin is also right, visualizing a rotation of a circle across the
; -pi/pi axis of the horizontal circle. Thus, an elevation of -pi/2 corresponds
; To bottom, And a speaker standing on the left, And 'beaming' upwards would have
; an azimuth of -pi, And an elevation of pi/2.
; For user Interface representation, grads are more likely To be used, And the
; origins will obviously 'shift' accordingly. */
Structure VstSpeakerProperties Align #PB_Structure_AlignC
azimuth.f  ; unit: rad, range: -PI...PI, exception: 10.f for LFE channel
elevation.f  ; unit: rad, range: -PI/2...PI/2, exception: 10.f For LFE channel
radius.f  ; unit: meter, exception: 0.f for LFE channel
reserved.f  ; zero (reserved for future use)
name.c[#kVstMaxNameLen]  ; for new setups, new names should be given (L/R/C... won't do)
type.l  ; VstSpeakerType
future.b[28]  ; reserved for future use
EndStructure

; Speaker Arrangement.
Structure VstSpeakerArrangement Align #PB_Structure_AlignC
type.l  ; e.g. #kSpeakerArr51 for 5.1  @see VstSpeakerArrangementType
numChannels.l  ; number of channels in this speaker arrangement
speakers.VstSpeakerProperties[8]  ; variable sized speaker array
EndStructure

; Speaker Types.
; VstSpeakerType
#kSpeakerUndefined = $7fffffff  ; Undefined
#kSpeakerM = 0  ; Mono (M)
#kSpeakerL = 1  ; Left (L)
#kSpeakerR = 2  ; Right (R)
#kSpeakerC = 3  ; Center (C)
#kSpeakerLfe = 4  ; Subbass (Lfe)
#kSpeakerLs = 5  ; Left Surround (Ls)
#kSpeakerRs = 6  ; Right Surround (Rs)
#kSpeakerLc = 7  ; Left of Center (Lc)
#kSpeakerRc = 8  ; Right of Center (Rc)
#kSpeakerS = 9  ; Surround (S)
#kSpeakerCs = #kSpeakerS  ; Center of Surround (Cs) = Surround (S)
#kSpeakerSl = 10  ; Side Left (Sl)
#kSpeakerSr = 11  ; Side Right (Sr)
#kSpeakerTm = 12  ; Top Middle (Tm)
#kSpeakerTfl = 13  ; Top Front Left (Tfl)
#kSpeakerTfc = 14  ; Top Front Center (Tfc)
#kSpeakerTfr = 15  ; Top Front Right (Tfr)
#kSpeakerTrl = 16  ; Top Rear Left (Trl)
#kSpeakerTrc = 17  ; Top Rear Center (Trc)
#kSpeakerTrr = 18  ; Top Rear Right (Trr)
#kSpeakerLfe2 = 19  ; Subbass 2 (Lfe2)

; User-defined speaker types, To be extended in the negative range.
; Will be handled As their corresponding speaker types With abs values:
; e.g Abs(#kSpeakerU1) == #kSpeakerL, Abs(#kSpeakerU2) == #kSpeakerR) */
; VstUserSpeakerType
Enumeration
#kSpeakerU32 = -32
#kSpeakerU31
#kSpeakerU30
#kSpeakerU29
#kSpeakerU28
#kSpeakerU27
#kSpeakerU26
#kSpeakerU25
#kSpeakerU24
#kSpeakerU23
#kSpeakerU22
#kSpeakerU21
#kSpeakerU20 ; = #kSpeakerLfe2
#kSpeakerU19 ; == #kSpeakerTrr
#kSpeakerU18 ; == #kSpeakerTrc
#kSpeakerU17 ; == #kSpeakerTrl
#kSpeakerU16 ; == #kSpeakerTfr
#kSpeakerU15 ; == #kSpeakerTfc
#kSpeakerU14 ; == #kSpeakerTfl
#kSpeakerU13 ; == #kSpeakerTm
#kSpeakerU12 ; == #kSpeakerSr
#kSpeakerU11 ; == #kSpeakerSl
#kSpeakerU10 ; == #kSpeakerCs
#kSpeakerU9 ; == #kSpeakerS
#kSpeakerU8 ; == #kSpeakerRc
#kSpeakerU7 ; == #kSpeakerLc
#kSpeakerU6 ; == #kSpeakerRs
#kSpeakerU5 ; == #kSpeakerLs
#kSpeakerU4 ; == #kSpeakerLfe
#kSpeakerU3 ; == #kSpeakerC
#kSpeakerU2 ; == #kSpeakerR
#kSpeakerU1 ; == #kSpeakerL
EndEnumeration

; Speaker Arrangement Types
; VstSpeakerArrangementType
Enumeration
#kSpeakerArrUserDefined = -2 ; user defined
#kSpeakerArrEmpty = -1 ; empty arrangement
#kSpeakerArrMono = 0 ; M
#kSpeakerArrStereo ; L R
#kSpeakerArrStereoSurround ; Ls Rs
#kSpeakerArrStereoCenter ; Lc Rc
#kSpeakerArrStereoSide ; Sl Sr
#kSpeakerArrStereoCLfe ; C Lfe
#kSpeakerArr30Cine ; L R C
#kSpeakerArr30Music ; L R S
#kSpeakerArr31Cine ; L R C Lfe
#kSpeakerArr31Music ; L R Lfe S
#kSpeakerArr40Cine ; L R C   S (LCRS)
#kSpeakerArr40Music ; L R Ls  Rs (Quadro)
#kSpeakerArr41Cine ; L R C   Lfe S (LCRS+Lfe)
#kSpeakerArr41Music ; L R Lfe Ls Rs (Quadro+Lfe)
#kSpeakerArr50 ; L R C Ls  Rs 
#kSpeakerArr51 ; L R C Lfe Ls Rs
#kSpeakerArr60Cine ; L R C   Ls  Rs Cs
#kSpeakerArr60Music ; L R Ls  Rs  Sl Sr 
#kSpeakerArr61Cine ; L R C   Lfe Ls Rs Cs
#kSpeakerArr61Music ; L R Lfe Ls  Rs Sl Sr 
#kSpeakerArr70Cine ; L R C Ls  Rs Lc Rc 
#kSpeakerArr70Music ; L R C Ls  Rs Sl Sr
#kSpeakerArr71Cine ; L R C Lfe Ls Rs Lc Rc
#kSpeakerArr71Music ; L R C Lfe Ls Rs Sl Sr
#kSpeakerArr80Cine ; L R C Ls  Rs Lc Rc Cs
#kSpeakerArr80Music ; L R C Ls  Rs Cs Sl Sr
#kSpeakerArr81Cine ; L R C Lfe Ls Rs Lc Rc Cs
#kSpeakerArr81Music ; L R C Lfe Ls Rs Cs Sl Sr 
#kSpeakerArr102 ; L R C Lfe Ls Rs Tfl Tfc Tfr Trl Trr Lfe2
#kNumSpeakerArr
EndEnumeration

; Offline Processing
; Offline Task Description.
Structure VstOfflineTask Align #PB_Structure_AlignC
processName.c[96]  ; set by plug-in

; audio access
readPosition.d  ; set by plug-in/Host
writePosition.d  ; set by plug-in/Host
readCount.l  ; set by plug-in/Host
writeCount.l  ; set by plug-in
sizeInputBuffer.l  ; set by Host
sizeOutputBuffer.l  ; set by Host
*inputBuffer  ; set by Host
*outputBuffer  ; set by Host
positionToProcessFrom.d  ; set by Host
numFramesToProcess.d  ; set by Host
maxFramesToWrite.d  ; set by plug-in

; other Data access
*extraBuffer  ; set by plug-in
value.l  ; set by Host or plug-in
index.l  ; set by Host or plug-in

; file attributes
numFramesInSourceFile.d  ; set by Host
sourceSampleRate.d  ; set by Host or plug-in
destinationSampleRate.d  ; set by Host or plug-in
numSourceChannels.l  ; set by Host or plug-in
numDestinationChannels.l  ; set by Host or plug-in
sourceFormat.l  ; set by Host
destinationFormat.l  ; set by plug-in
outputText.c[512]  ; set by plug-in or Host

; progress notification
progress.d  ; set by plug-in
progressMode.l  ; Reserved for future use
progressText.c[100]  ; set by plug-in

flags.l  ; set by Host and plug-in; see enum #VstOfflineTaskFlags
returnValue.l  ; Reserved for future use
*hostOwned  ; set by Host
*plugOwned  ; set by plug-in

future.b[1024]  ; Reserved for future use
EndStructure

; Flags used in #VstOfflineTask.
; VstOfflineTaskFlags
#kVstOfflineUnvalidParameter = 1  ; set by Host
#kVstOfflineNewFile = 2  ; set by Host
#kVstOfflinePlugError = 1024  ; set by plug-in
#kVstOfflineInterleavedAudio = 2048  ; set by plug-in
#kVstOfflineTempOutputFile = 4096  ; set by plug-in
#kVstOfflineFloatOutputFile = 8192  ; set by plug-in
#kVstOfflineRandomWrite = 16384  ; set by plug-in
#kVstOfflineStretch = 32768  ; set by plug-in
#kVstOfflineNoThread = 65536  ; set by plug-in

; Option passed To #offlineRead/#offlineWrite.
; VstOfflineOption
#kVstOfflineAudio = 0  ; reading/writing audio samples
#kVstOfflinePeaks = 1  ; reading graphic representation
#kVstOfflineParameter = 2  ; reading/writing parameters
#kVstOfflineMarker = 3  ; reading/writing marker
#kVstOfflineCursor = 4  ; reading/moving edit cursor
#kVstOfflineSelection = 5  ; reading/changing selection
#kVstOfflineQueryFiles = 6  ; To request the Host To call asynchronously #offlineNotify

; Structure passed To #offlineNotify And #offlineStart
Structure VstAudioFile Align #PB_Structure_AlignC
flags.l  ; see enum #VstAudioFileFlags
*hostOwned  ; any data private to Host
*plugOwned  ; any data private to plug-in
name.c[#kVstMaxFileNameLen]  ; file title
uniqueId.l  ; uniquely identify a file during a session
sampleRate.d  ; file sample rate
numChannels.l  ; number of channels (1 for mono, 2 for stereo...)
numFrames.d  ; number of frames in the audio file
format.l  ; Reserved for future use
editCursorPosition.d  ; -1 if no such cursor
selectionStart.d  ; frame index of first selected frame, or -1
selectionSize.d  ; number of frames in selection, or 0
selectedChannelsMask.l  ; 1 bit per channel
numMarkers.l  ; number of markers in the file
timeRulerUnit.l  ; see doc for possible values
timeRulerOffset.d  ; offset in time ruler (positive or negative)
tempo.d  ; as BPM (Beats Per Minute)
timeSigNumerator.l  ; time signature numerator
timeSigDenominator.l  ; time signature denominator
ticksPerBlackNote.l  ; resolution
smpteFrameRate.l  ; SMPTE rate (set as in #VstTimeInfo)
future.b[64]  ; Reserved for future use
EndStructure

; Flags used in #VstAudioFile.
; VstAudioFileFlags
#kVstOfflineReadOnly = 1  ; set by Host (in call #offlineNotify)
#kVstOfflineNoRateConversion = 2  ; set by Host (in call #offlineNotify)
#kVstOfflineNoChannelChange = 4  ; set by Host (in call #offlineNotify)
#kVstOfflineCanProcessSelection = 1024  ; set by plug-in (in call #offlineStart)
#kVstOfflineNoCrossfade = 2048  ; set by plug-in (in call #offlineStart)
#kVstOfflineWantRead = 4096  ; set by plug-in (in call #offlineStart)
#kVstOfflineWantWrite = 8192  ; set by plug-in (in call #offlineStart)
#kVstOfflineWantWriteMarker = 16384  ; set by plug-in (in call #offlineStart)
#kVstOfflineWantMoveCursor = 32768  ; set by plug-in (in call #offlineStart)
#kVstOfflineWantSelect = 65536  ; set by plug-in (in call #offlineStart)

; Audio file marker.
Structure VstAudioFileMarker Align #PB_Structure_AlignC
position.d  ; marker position
name.c[32]  ; marker name
type.l  ; marker type
id.l  ; marker identifier
reserved.l  ; reserved for future use
EndStructure

; Others
; structure used For #openWindow And #closeWindow (deprecated in VST 2.4).
Structure VstWindow Align #PB_Structure_AlignC
title.c[128]
xPos.w
yPos.w
width.w
height.w
style.w
*parent
*userHandle
*winHandle
future.b[104]
EndStructure

; Structure used For keyUp/keyDown.
Structure VstKeyCode Align #PB_Structure_AlignC
character.l  ; ASCII character
virt.b  ; @see VstVirtualKey
modifier.b  ; @see VstModifierKey
EndStructure

; Platform-independent definition of Virtual Keys (used in #VstKeyCode).
Enumeration ; VstVirtualKey 
#VKEY_BACK = 1
#VKEY_TAB
#VKEY_CLEAR
#VKEY_RETURN
#VKEY_PAUSE
#VKEY_ESCAPE
#VKEY_SPACE
#VKEY_NEXT
#VKEY_END
#VKEY_HOME
#VKEY_LEFT
#VKEY_UP
#VKEY_RIGHT
#VKEY_DOWN
#VKEY_PAGEUP
#VKEY_PAGEDOWN
#VKEY_SELECT
#VKEY_PRINT
#VKEY_ENTER
#VKEY_SNAPSHOT
#VKEY_INSERT
#VKEY_DELETE
#VKEY_HELP
#VKEY_NUMPAD0
#VKEY_NUMPAD1
#VKEY_NUMPAD2
#VKEY_NUMPAD3
#VKEY_NUMPAD4
#VKEY_NUMPAD5
#VKEY_NUMPAD6
#VKEY_NUMPAD7
#VKEY_NUMPAD8
#VKEY_NUMPAD9
#VKEY_MULTIPLY
#VKEY_ADD
#VKEY_SEPARATOR
#VKEY_SUBTRACT
#VKEY_DECIMAL
#VKEY_DIVIDE
#VKEY_F1
#VKEY_F2
#VKEY_F3
#VKEY_F4
#VKEY_F5
#VKEY_F6
#VKEY_F7
#VKEY_F8
#VKEY_F9
#VKEY_F10
#VKEY_F11
#VKEY_F12
#VKEY_NUMLOCK
#VKEY_SCROLL
#VKEY_SHIFT
#VKEY_CONTROL
#VKEY_ALT
#VKEY_EQUALS
EndEnumeration

; Modifier flags used in #VstKeyCode.
; VstModifierKey
#MODIFIER_SHIFT = 1  ; Shift
#MODIFIER_ALTERNATE = 2  ; Alt
#MODIFIER_COMMAND = 4  ; Control on Mac
#MODIFIER_CONTROL = 8  ; Ctrl on PC, Apple on Mac

; File filter used in #VstFileSelect.
Structure VstFileType Align #PB_Structure_AlignC
name.c[128]  ; display name
macType.c[8]  ; MacOS type
dosType.c[8]  ; Windows file extension
unixType.c[8]  ; Unix file extension
mimeType1.c[128]  ; MIME type
mimeType2.c[128]  ; additional MIME type
EndStructure

; File Selector Description used in #audioMasterOpenFileSelector.
Structure VstFileSelect Align #PB_Structure_AlignC
command.l  ; @see VstFileSelectCommand
type.l  ; @see VstFileSelectType
macCreator.l  ; optional: 0 = no creator
nbFileTypes.l  ; number of fileTypes
*fileTypes.VstFileType  ; list of fileTypes  @see VstFileType
title.c[1024]  ; text to display in file selector's title
*initialPath.string  ; initial path
*returnPath.String  ; use with #kVstFileLoad and #kVstDirectorySelect. null: Host allocates memory, plug-in must call #closeOpenFileSelector!
sizeReturnPath.l  ; size of allocated memory for return paths
*returnMultiplePaths.String  ; use with kVstMultipleFilesLoad. Host allocates memory, plug-in must call #closeOpenFileSelector!
nbReturnPath.l  ; number of selected paths
reserved.i  ; reserved for Host application
future.b[116]  ; reserved for future use
EndStructure

; Command constants used in #VstFileSelect Structure.
Enumeration VstFileSelectCommand
#kVstFileLoad = 0  ; For loading a file
#kVstFileSave  ; For saving a file
#kVstMultipleFilesLoad  ; For loading multiple files
#kVstDirectorySelect  ; For selecting a directory/folder
 EndEnumeration

; Types used in #VstFileSelect Structure.
#kVstFileType = 0  ; regular file selector

; Structure used For #effBeginLoadBank/#effBeginLoadProgram.
Structure VstPatchChunkInfo Align #PB_Structure_AlignC
version.l  ; Format Version (should be 1)
pluginUniqueID.l  ; UniqueID of the plug-in
pluginVersion.l  ; Plug-in Version
numElements.l  ; Number of Programs (Bank) or Parameters (Program)
future.c[48]  ; Reserved for future use
EndStructure

; PanLaw Type.
; VstPanLawType
#kLinearPanLaw = 0  ; L = pan * M; R = (1 - pan) * M;
#kEqualPowerPanLaw = 1  ; L = Pow (pan, 0.5) * M; R = pow ((1 - pan), 0.5) * M;

; Process Levels returned by #audioMasterGetCurrentProcessLevel.
Enumeration ; VstProcessLevels
#kVstProcessLevelUnknown = 0  ; Not supported by Host
#kVstProcessLevelUser  ; 1: currently in user thread (GUI)
#kVstProcessLevelRealtime  ; 2: currently in audio thread (where process is called)
#kVstProcessLevelPrefetch  ; 3: currently in 'sequencer' thread (MIDI, timer etc)
#kVstProcessLevelOffline  ; 4: currently offline processing And thus in user thread
EndEnumeration

; Automation States returned by #audioMasterGetAutomationState.
Enumeration ; VstAutomationStates
#kVstAutomationUnsupported = 0  ; Not supported by Host
#kVstAutomationOff  ; off
#kVstAutomationRead  ; Read
#kVstAutomationWrite  ; write
#kVstAutomationReadWrite  ; Read And write
EndEnumeration

; Plug-in CanDo strings
Global canDoSendVstEvents.s = "sendVstEvents" ; plug-in will send Vst events to Host
Global canDoSendVstMidiEvent.s = "sendVstMidiEvent" ; plug-in will send MIDI events to Host
Global canDoReceiveVstEvents.s = "receiveVstEvents" ; plug-in can receive MIDI events from Host
Global canDoReceiveVstMidiEvent.s = "receiveVstMidiEvent" ; plug-in can receive MIDI events from Host 
Global canDoReceiveVstTimeInfo.s = "receiveVstTimeInfo" ; plug-in can receive Time info from Host 
Global canDoOffline.s = "offline" ; plug-in supports offline functions (#offlineNotify, #offlinePrepare, #offlineRun)
Global canDoMidiProgramNames.s = "midiProgramNames" ; plug-in supports function #getMidiProgramName ()
Global canDoBypass.s = "bypass"                     ; plug-in supports function #setBypass ()

Code: Select all

;  file VSTGUI.pbi

Global winrect.ERect
winrect\top = 10
winrect\left = 10
winrect\bottom = 500
winrect\right = 500

Global hWndMain
Global hbutton
Global htext
Global hcontainer
Global htrackbar
Global hinstance = GetModuleHandle_(#Null)
Global miditext0.s
Global miditext1.s
Global miditext2.s
Global miditype.s

Procedure gadgetshandler()
  MessageRequester("event", "click " + Str(EventGadget()))
  EndProcedure

Procedure GUIOpen(*parenthandle)
hWndMain = OpenWindow(#PB_Any, 0, 0, winrect\bottom, winrect\right, "", #PB_Window_NoActivate)
SetParent_(WindowID(hWndMain), *parenthandle)
StartDrawing(WindowOutput(hWndMain))
DrawText(20, 20, "ev1 " + miditext0)
DrawText(20, 50, "ev2 " + miditext1)
DrawText(20, 100, "ev3 " + miditext2)
TextGadget(htext, 20, 300, 100, 100, miditype)
; DrawText(20, 350, "cando " + candostring1)
StopDrawing()
hcontainer = ContainerGadget(#PB_Any, 10, 10, 400, 400)
hbutton = ButtonGadget(#PB_Any, 20, 150, 150, 150, "my button")
htrackbar = TrackBarGadget(#PB_Any, 300, 100, 150, 150, 0, 100, #PB_TrackBar_Vertical)
GadgetToolTip(hbutton, "tooltip for button")
CloseGadgetList()
BindGadgetEvent(hbutton, @gadgetshandler())
ProcedureReturn #True
EndProcedure

Procedure GUIClose()
CloseWindow(hWndMain)
EndProcedure

Procedure GetRect(*rect)
  *rect = @winrect
ProcedureReturn #True
EndProcedure

Code: Select all

;  general file VST_plugin.pb
; 18.10.2020 basic example
EnableExplicit
XIncludeFile "aeffectx.pbi"
XIncludeFile "vstgui.pbi"

Global channels.l = 2
Global numparams.l = 3
Global.f leftparam = 1.0, rightparam = 1.0, ModeValue
Global SampleRate.f
Global BlockSize.l
Global NumPrograms.l = 5
Global CurProgram.l = 0
Global NameProgram.s
Define.l currentNote, currentVelocity, currentDelta, noteIsOn

Enumeration ParameterIndex
#LeftVolume
#RightVolume
#ModeVolume
#kVSTparameterLen = 12
EndEnumeration

Procedure.f LeftSample(inputsample.f)
ProcedureReturn inputsample * leftparam
EndProcedure

Procedure.f RightSample(inputsample.f)
ProcedureReturn inputsample * rightparam
EndProcedure

; other procedures
Procedure suspend()
EndProcedure

Procedure resume()
EndProcedure

Procedure.l getProgram()
 ProcedureReturn curprogram
EndProcedure

Procedure setProgram(program.l)
CurProgram = program
EndProcedure

Procedure.l getProgramNameIndexed (category.l, index.l, *text)
If index < NumPrograms
PokeS(*text, NameProgram, #kVstMaxProgNameLen, #PB_Ascii)
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
 
 Procedure getProgramName(*name)
PokeS(*name, "Basic preset", #kVstMaxProgNameLen, #PB_Ascii)
EndProcedure

Procedure setProgramName(*name)
NameProgram = PeekS(*name, #kVstMaxProgNameLen, #PB_Ascii)
EndProcedure

Procedure getParameterName(index.l, *text)
Select index
Case #LeftVolume
PokeS(*text, "Left volume", #kVSTparameterLen, #PB_Ascii)
Case #RightVolume
PokeS(*text, "Right volume", #kVSTparameterLen, #PB_Ascii)
Case #ModeVolume
PokeS(*text, "Mode", #kVSTparameterLen, #PB_Ascii)
EndSelect
EndProcedure

Procedure getParameterLabel(index.l, *text)
Select index
Case #LeftVolume
PokeS(*text, StrF(leftparam, 4), SizeOf(Float), #PB_Ascii)
Case #RightVolume
PokeS(*text, StrF(rightparam, 4), SizeOf(Float), #PB_Ascii)
Case #ModeVolume

Select Int(ModeValue * 1000.0)
Case 0
PokeS(*text, "left", #kVstMaxShortLabelLen, #PB_Ascii)
Case 1
PokeS(*text, "center", #kVstMaxShortLabelLen, #PB_Ascii)
Case 2
PokeS(*text, "right", #kVstMaxShortLabelLen, #PB_Ascii)
Default
PokeS(*text, "empty", #kVstMaxShortLabelLen, #PB_Ascii)
EndSelect

EndSelect
EndProcedure

Procedure.l canDo(*text)
 If CompareMemoryString(*text, @canDoReceiveVstEvents, #PB_String_NoCase, -1, #PB_Ascii) = 0
ProcedureReturn 1
EndIf
If CompareMemoryString(*text, @canDoReceiveVstMidiEvent, #PB_String_NoCase, -1, #PB_Ascii) = 0
ProcedureReturn 1
EndIf
ProcedureReturn -1
EndProcedure

Procedure.l getNumMidiOutputChannels()
 ProcedureReturn 1
EndProcedure

Procedure.l getNumMidiInputChannels()
ProcedureReturn 1
EndProcedure

ProcedureC.l ProcessEvents(*EVs.VstEvents)
Protected ve.VstEvent, me.VstMidiEvent
Protected i.l
For i = 0 To *EVs\numEvents
If *EVs\events[i]\type = #kVstMidiType
CopyStructure(@ve, @me.VstMidiEvent, VstMidiEvent)
miditype = Chr(me\type)
miditext0 = Chr(me\mididata[0])
miditext1 = Chr(me\mididata[1])
miditext2 = Chr(me\mididata[2])

EndIf
Next i
ProcedureReturn #True
EndProcedure


; procedures for VST sdk
ProcedureC.i DispatcherProc(*d.AEffect, opcode.l, index.l, Value.i, *ptr, opt.f)
Protected result.i
If opcode = #effClose
FreeStructure(*d)
ElseIf opcode = #effSetSampleRate
SampleRate = opt
ElseIf opcode = #effSetBlockSize
BlockSize = value
ElseIf opcode = #effCanDo
result = CanDo(*ptr)
ElseIf opcode = #effgetNumMidiOutputChannels
result = getNumMidiOutputChannels()
ElseIf opcode = #effgetNumMidiInputChannels
result = getNumMidiInputChannels()
ElseIf opcode = #effProcessEvents
result = ProcessEvents(*ptr)
ElseIf opcode = #effSetProgram
 setProgram(Value)
ElseIf opcode = #effGetProgram
result = getProgram()
ElseIf opcode = #effSetProgramName
setProgramName(*ptr)
ElseIf opcode = #effGetProgramName
getProgramName(*ptr)
ElseIf opcode = #effGetProgramNameIndexed
result = getProgramNameIndexed(value, index, *ptr)
ElseIf opcode = #effGetParamLabel
getParameterLabel(index, *ptr)
ElseIf opcode = #effGetParamName
getParameterName(index, *ptr)
ElseIf opcode = #effMainsChanged
 If Not Value
  suspend()
 Else
  resume()
  EndIf
ElseIf opcode = #effGetPlugCategory
result = #kPlugCategEffect | #kPlugCategAnalysis
ElseIf opcode = #effGetEffectName
PokeS(*ptr, "test plugin", #kVstMaxEffectNameLen, #PB_Ascii)
ElseIf opcode = #effGetVendorString
PokeS(*ptr, "Alex Longard", #kVstMaxVendorStrLen, #PB_Ascii)
ElseIf opcode = #effEditGetRect
result = GetRect(*ptr)
ElseIf opcode = #effEditOpen
GUIOpen(*ptr)
ElseIf opcode = #effEditClose
GUIClose()
EndIf
ProcedureReturn result
EndProcedure

ProcedureC ProcessReplacingProc(*ap.AEffect, *inputs, *outputs, sampleframes.l)
Protected *In1, *In2, *Out1, *Out2, i.i
*In1 = PeekI(*inputs)
*Out1 = PeekI(*outputs)
*In2 = PeekI(*inputs + SizeOf(integer))
*Out2 = PeekI(*outputs + SizeOf(integer))

For i = 0 To sampleframes - 1
PokeF(*Out1 + i * SizeOf(float), LeftSample(PeekF(*In1 + i * SizeOf(float))))
PokeF(*Out2 + i * SizeOf(float), RightSample(PeekF(*In2 + i * SizeOf(float))))
Next i
EndProcedure

ProcedureC ProcessDoubleReplacingProc(*ap.AEffect, *inputs, *outputs, sampleframes.l)
Protected *In1, *In2, *Out1, *Out2, i.i
*In1 = PeekI(*inputs)
*Out1 = PeekI(*outputs)
*In2 = PeekI(*inputs + SizeOf(integer))
*Out2 = PeekI(*outputs + SizeOf(integer))

For i = 0 To sampleframes - 1
PokeD(*Out1 + i * SizeOf(Double), LeftSample(PeekD(*In1 + i * SizeOf(Double))))
PokeD(*Out2 + i * SizeOf(Double), RightSample(PeekD(*In2 + i * SizeOf(Double))))
Next i
EndProcedure

ProcedureC SetParameterProc(*asp.AEffect, index.l, value.f)
Select index
Case #LeftVolume
leftparam = value
Case #RightVolume
rightparam = value
Case #ModeVolume
ModeValue = value
EndSelect
EndProcedure

ProcedureC.f GetParameterProc(*agp.AEffect, index.l)
Protected result.f = 0
Select index
Case #LeftVolume
result = leftparam
Case #RightVolume
result = rightparam
Case #ModeVolume
result = ModeValue
EndSelect
ProcedureReturn result
EndProcedure

ProcedureCDLL VSTPluginMain(*audioMaster.AudioMasterCallback)
Protected *Aef.AEffect = AllocateStructure(AEffect)
*aef\magic = #kEffectMagic
*aef\dispatcher = @DispatcherProc()
*aef\setParameter = @SetParameterProc()
*aef\getParameter = @GetParameterProc()
*aef\numPrograms = NumPrograms
*aef\numParams = numparams
*aef\numInputs = channels
*aef\numOutputs = channels
*aef\flags = #effFlagsHasEditor | #effFlagsCanDoubleReplacing ;| #effFlagsIsSynth
*aef\processReplacing = @ProcessReplacingProc()
*aef\processDoubleReplacing = @ProcessDoubleReplacingProc()
*aef\uniqueID = 02081987
*aef\version = 1
*aef\Object = 0
ProcedureReturn *aef
EndProcedure

Last edited by Aleks_Longard on Tue Apr 04, 2023 4:21 pm, edited 5 times in total.
Sory my bad english
Fred
Administrator
Administrator
Posts: 16618
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: VST SDK plugin example

Post by Fred »

Nice stuff !
sq4
User
User
Posts: 98
Joined: Wed Feb 26, 2014 3:16 pm
Contact:

Re: VST SDK plugin example

Post by sq4 »

@Aleks_Longard.

Hi, I've been doing this stuff for over 10 years now in PureBasic.
If you have any questions, don't hesitate to ask!
I'm glad I am not the only one anymore.

You can see my plugins here :
http://www.raxntrax.com

Beware though, there's a bug in the threadsave library of PureBasic.
So if you want to make stable plugins don't use threadsafety, you'll need to protect all your lists/maps/strings all by your own code.
It's an old bug that appears on closing the plugin only in some hosts (cantabile/tracktion/mulab/flstudio).
You'll get an access violation. Probably a threadsave ressource not cleaned up properly.

It has been mentioned a couple of times here on the forum, but still there seems to be no solution...

Success!
Eric
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: VST SDK plugin example

Post by Aleks_Longard »

Hello Fred, thank you!!!

Hello Sq4, thanks, i am C++ developer and write some plugins with VST SDK and Reaper SDK on C++.
I very love Purebasic, and only recently I had time to rewrite some my old codes on Purebasic, since in C++ I don’t like some things related to classes and silly wrappers for simple functions.
Cheers!
Sory my bad english
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: VST SDK plugin example

Post by Joris »

Aleks_Longard wrote:...
If anyone is interested in this, I can translate the full VST SDK.
I'm realy interested in this !
This might give me a new start on some of my own smaller midi-projects.
I always found these VST-C sources to difficult to my knowledge,
so I realy hope you will continu your work.

Yet, some more info on 'how to use this' would help.
(DAW's and VST-host's I use here, are Logic on OSX and still one on XP too, Cantabile, LMMS).

Thanks and keep up the good work.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: VST SDK plugin example

Post by Aleks_Longard »

Hello Joris,
I can't try this in Logic, since I don't have a Mac os, and vst plug's for Mac is different from Windows plugins.
I will try to find information for vst on a Mac, as long as I can translate all includes "aeffect.h, aeffectx.h" which are essential for plugins for Windows DAWs.
Cheers!
Sory my bad english
User avatar
oreopa
Enthusiast
Enthusiast
Posts: 281
Joined: Sat Jun 24, 2006 3:29 am
Location: Edinburgh, Scotland.

Re: VST SDK plugin example

Post by oreopa »

Really great stuff Aleks. PLEASE continue :D

Compiled and loaded in daw (REAPER also) as vst dll without problems. It's a really nice basic starting framework.

How about simple ASIO vst host next? :DDD (Just kidding about that one ;) Or...? :D )

Thank you very much for this.

sq4: Your music software stuff has always highly impressed me. Very good work mate.
Proud supporter of PB! * Musician * C64/6502 Freak
sq4
User
User
Posts: 98
Joined: Wed Feb 26, 2014 3:16 pm
Contact:

Re: VST SDK plugin example

Post by sq4 »

oreopa wrote: How about simple ASIO vst host next? :DDD (Just kidding about that one ;) Or...? :D )
If you search for Asio you'll find an older topic of mine under my previous member name "eriansa".
I remember I had to write assembler for the x86 version due to calling conventions. Pure coding hell...

Btw thanks for your nice comment on my plugins. :D
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: VST SDK plugin example

Post by Aleks_Longard »

Oreopa
I not see problem trying to write Asio / VST host :)
AudioMasterCallback it's same as AEffectDispatcherProc function.
I will translate sdk and try to write something.
I already wrote a simple host on pure C to test my ideas for VST and Reaper))))
Cheers!
Sory my bad english
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: VST SDK plugin example

Post by Joris »

@Aleks_Longard
I also have a pc with XP still, but how do I have to use your code on that, isn't clear ?
If I run it nothing happens or appears ?
Somewhere the source looks like a DLL, so then it would be VST itself not a VST-host...
Sorry, for my stupidity about this.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: VST SDK plugin example

Post by Aleks_Longard »

Hello Joris!
See this:
https://www.dropbox.com/sh/j0vun0sg751f ... drVEa?dl=0

I compile dll for x64 and x86 Windows.
And example.pb in folder.

I while not have time for write vsthost and some examples.
Sory my bad english
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: VST SDK plugin example

Post by Joris »

@Aleks_Longard,
I can open it here in Cantabile Lite (a VST host) and LMMS (a DAW).
In Cantabile I get some volume-controller shown, LMMS loads the VST but nothing is shown.
Logic (on XP) didn't work, yet I must retry as I might have done something wrong there.

Thanks
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Aleks_Longard
User
User
Posts: 59
Joined: Mon Dec 24, 2012 9:07 am
Location: Germany, Munich

Re: VST SDK plugin example

Post by Aleks_Longard »

Joris,
this example not have GUI, volume slider accessible as automatable control.
In Reaper DAW this shows in alternative GUI, which make Reaper for nongui plugins.
I can not have others DAWs for testing.
Sory my bad english
Joris
Addict
Addict
Posts: 885
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: VST SDK plugin example

Post by Joris »

Aleks_Longard wrote:I can not have others DAWs for testing.
Ok.
If you need some testings ... I have 4 DAW's available.
(LMMS is a free one and opensource.)
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
Kurzer
Enthusiast
Enthusiast
Posts: 664
Joined: Sun Jun 11, 2006 12:07 am
Location: Near Hamburg

Re: VST SDK plugin example

Post by Kurzer »

in adobe audition the x64 plugin example works great.
maybe in future i will dive into this vst stuff. it sounds amazing to write a vst plugin in purebasic.

Sent via mobile phone
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520, User age in 2023: 56y
"Happiness is a pet." | "Never run a changing system!"
Post Reply