VST3 Plugin wrapper

Thanks - should be ok now. (Strange that llvm didn't complain about that)

Hi Jules,


Just some update on this issue. I test again on the demo project generated from introjucer.

With Both 

#ifndef  JucePlugin_Build_VST

 #define JucePlugin_Build_VST              1


#ifndef  JucePlugin_Build_VST3

 #define JucePlugin_Build_VST3             1


vst flags set to 1, the xcode build went fine.

When only the VST3 is enabled, i got the link errors in my previous post.

#ifndef  JucePlugin_Build_VST

 #define JucePlugin_Build_VST              0


#ifndef  JucePlugin_Build_VST3

 #define JucePlugin_Build_VST3             1


Seems a bit weird.

Maybe you have mentioned at somewhere that both of these need to be declared as 1 in order to build vst3 and I did not see that?



Just want to report that my plugin is building and loading in Cubase 7.5 now. Thanks for getting this working! 

xsd121, I have the same where both need to be declared to build VST3. 


Sorry - I hadn't tried building VST3 without VST2. It just needed a little tweak to add those functions.

I just downloaded the VST3 SDK, updated my JUCE version, checked the VST3 box and it works straight away. Awesome!! Big thanks to jrlanglois and Jules!


There are apparently still major problems in WaveLab 8. WaveLab calls process with processContext.sampleRate set to zero, so there's no processing going on. I could easily fix that, but the UI also freezes after a short while.



Ah, good old Wavelab. It's always been a total fucking PITA to support it, so no surprises there.

It probably needs a hack like the checkWhetherMessageThreadIsCorrect() stuff that I did for VST2 to work around its threading model. I'm a bit busy and my Wavelab license has expired, so if anyone wants to volunteer to try that, it'd be appreciated!

I got a similar linker error and did some investigation on it.

For me this happens only when I build a VST3 only plugin without VST code in the same binary.

Therefore added juce_VST3_Wrapper.cpp and juce_VST3_Wrapper.mm to the project.

The linker complains about missing symbols and that is correct. I analysed the object file produced from juce_VST3_Wrapper.mm with the with the command line tool nm. There are no symbols in that object.

This is the same for the Juce Audio Plugin Demo. The Demo Project works, because there is also the juce_VST_Wrapper.mm in the project, where the missing symbols are defined.

So my conclusion is the following: To build a VST3 plugin, add juce_VST3_Wrapper.cpp and juce_VST_Wrapper.mm to the project. It makes no difference, if juce_VST3_Wrapper.mm is also part of the project.

While this work, I wonder what is going wrong with juce_VST3_Wrapper.mm. I think Jules had added that file for a certain reason and there is a difference to juce_VST_Wrapper.mm. So a VST3 plugin built with the configuration above, may be buggy or lacking some functionality, right?

I was wondering, why my VST3 plugin did projuced only noise and did not react to MIDI.

I found out, that setting JucePlugin_MaxNumInputChannels to 0 beaks a VST3 plugin. I did that because the plugin is a Synth and does not care for input data. But in juce_VST3_Wrapper.cpp line 1112 there is this check:

        if (pluginInstance != nullptr
            && data.inputs != nullptr
            && data.outputs != nullptr
            && processContext.sampleRate > 0.0)

Because, the plugin does not allow input channels, data.inputs is a nullpointer. That will make the process function just return false instead of processing files.

Setting JucePlugin_MaxNumInputChannels to a value > 0 is a workaround, but I think that is not the way it should be, right?


Hmm, yes, that code does look a bit ropey - sorry, I hadn't sanity-checked it. I've had a quick look and tightened it up a bit now, if you want to try again..

I think they cleaned up much of the threading mess in v7, so this is probably another issue. After experimenting a bit more, it seems to work fine the first time you instantiate the plug-in. Only when you reopen Wavelab, there are problems. This can easily be reproduced by adding the demo plug-in to the effect chain, closing the app and reopening it (with the restore files option selected). Simply clicking the play button seems to freeze the application. Anyway, you should remove the check for the processContext.sampleRate in the first line of the process method since this is zero in Wavelab 8. Also, Introjucer seems to confuse up the pluginManufacturerWebsite and companyWebsite as well as the pluginManufacturerEmail and companyEmail tags so that you can't change these without manual editing.


Sorry, that post on getParameterNumSteps() probably should have been posted in this thread. Now that I had a look into Steinberg's API and verified what I wrote about the values VST3 hosts are expecting, how about changing line 179 juce_VST3_Wrapper.cpp from

info.stepCount = (Steinberg::int32) p.getParameterNumSteps (index);


info.stepCount = (Steinberg::int32) p.getParameterNumSteps (index) - 1;

or even something like

info.stepCount = (Steinberg::int32) (p.getParameterNumSteps (index) == 0x7fffffff ? 0 : 
p.getParameterNumSteps (index) - 1;


(By the way: thanks a million to everyone working on this library!)

How about

            const int numSteps = p.getParameterNumSteps (index);
            info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0);

Yes, that looks even better.

Hello Everybody, 

I tried out the new VST3 Wrapper and it works well, so DemoPlugin works and so on. 

Now I tried out the new Feature of VST3:  Sampleaccurate Automation

In VST2 I used for automation the functions: beginEdit and endEdit (in JUCE: beginParameterChangeGesture/end...) 

Now in VST3 there is a new Function: performEdit for Automation

Now my Question: 

Is the sampleaccurate Automation working automaticly in VST3 or should I use the "performEdit" function. Because there is no implemented Version of a function like "performParameterChangeGesture" in the new JUCE. 
Im not shure If its working automatic, I tried to automate the gain-param of the DemoPlugin and I made shure that there is a jump while using the slider. But when Im writing out the Automation now (unfortunately through the plugin again) and plot it in Matlab the Jump is not a perfect sample accurate jump. 

So is the sampleaccurate Automation a lie or is my test wrong or do I need the functions. 


Had anyone a similar problem? 


I had a quick look into VST3 automation functions and how they are wrapped in the wrapper yesterday and I guess part of your problem might be that you're "writing out the automation" through your Plugin:

For sample-accurate automation playback, VST3 passes lists of parameter changes along with each sample block (see the "Automation playback" part of VST3 SDK/doc/vstinterfaces/vst3Automation.html within you VST3 SDK folder). They are passed as part of data with each call to IAudioProcessor::process (ProcessData &data).

However, the wrapper apparently only takes the last parameter of each of these lists to call JuceAudioProcessor::setParameter with it (see JuceVST3Component::processParameterChanges in juce_VST3_Wrapper.cpp).

To sum it up: just one parameter change per sample block is passed to JuceAudioProcessor -> no support of sampleaccurate automation (playback). (At least for now and if I'm not mistaken.)

Yeah, all the juce wrapper stuff was written to work on all formats, and pre-dates any sample-accurate parameter abilities that VST3 has added.

It'd require a big redesign of the whole AudioProcessor class to take advantage of it, because obviously it'd need to either break each block down into smaller chunks and process them (which would probably cause many flaky plugins to fail) or add an extra layer to let your process block iterate the parameter changes and find out their positions.. And all of this would need to be ported to all the other plugin formats of course. All worth doing, but not trivial!

When drawing automation in Cubase, there is this tooltip thing that shows you the denormalized String representation of the automation value:

This is calulated by calling Steinberg's IEditController::getParamStringByValue. It passes a normalized value and expects the String representation that the parameter would have if it was set to that value. As it does not actually set the parameter, this cannot be achieved by calling juce::AudioProcessor::getParameterText (int index).

The way the wrapper works right now, this is kind of broken as the tooltip always shows the value the plugin is actually set to (at the moment of editing the automation).

I coded myself a quick fix for that, but I'm still new to the library (and not a c++ expert neither).

Hey Mart, 


So sorry but know I'm a little bit confused. 
Your Quickfix doesn't fix the problem with sampleaccurate automation or have I misunderstood. 

I still do not see the connection between the String-Parameter-representation and the automation. 

Sorry for my confusion :) 

Hey Jules, 

First thank you for the Explanation. 

Is there a way to bypass the current VST-Wrapper only for a short time Interval? So the sample-accurate Automation for me is only interesting at Jump Points (like 0 -> 1). Do you see a way - without porting everything - to write Automation correctly at this points? 

I checked out the problem is not the reading of the Automation, if i draw a Automation-curve in Cubase by Hand an draw a jump from 0 -> 1 the Plugin reads it good enough (I think). But when write the Jump with the Plugin it's not a perfekt jump from 0 -> 1. 

So is there a way to use the "performEdit" function for some samples while writing the automation? Perhaps this helps...