Newbie needing some VST3 examples set up like Projucer sets them up


#1

I find it extremely confusing that the VST Plugin demos provided in the tutorial section are not set up the same way Projucer sets them up. All the demos seem to be built with the processing code and declarations in ONE file, i.e., “somename.h”.

However, when you create a new VST plugin using “Projucer” it creates 4 files - two sets for the Editor and two sets for the Processor. Since the Editor and Processor are separated in this case it requires more code to connect them all together - which is NOT shown in the examples.

Can someone point me to examples that ARE set up the same way Projucer sets them up?


#2

Perhaps a better exercise for you would be to split that single demo file up into separate Editor and Processor header/implementation files. That should help you understand how both design approaches (a single header file vs lots of short .h/.cpp files) are good to have at your disposal when building a project.


#3

If I knew how to do that I wouldn’t be asking for examples.

None of the required “listener” code is shown AT ALL in the JUCE examples. There’s a lot of other cross-communication code required that is not shown because the examples don’t follow how Juce sets it up. Where can I see an actual 4-file example of how this is done?


#4

I think they removed the old example, but you can find it in older versions of JUCE. I don’t know if this is really the right way to start, but the 4-file approach can be seen here…


#5

Did you look at these tutorials here, e.g.: https://docs.juce.com/master/tutorial_plugin_examples.html#tutorial_plugin_examples_noise_gate

These tutorials are starting from the boilerplate as it is generated from Projucer. The first tutorial set-up tutorial is actually about how to start a project and hook it up for debugging.

The reason to move the examples to the PIP style one file implementation was to focus on the actual code, since a lot of the boilerplate never changes anyway. But for bigger projects nobody would choose the PIP obviously, so it is understandable, that you might find the transition a bit hard.


#6

Yes, I have been studying that example and that is what’s confusing me. Other examples I have seen that use a Slider on the Editor side, for example, don’t mention anything about the “addParameter” functions on the Processor side - they just add a “listener” to the Processor side.

What ties the Processor and Editor together - in both directions - is where I’m lost. Seems there is a bunch of code required that is not shown in the examples.


#7

I see. Other than the editor having a reference to the processor, there is nothing built in to connect them. And the classes used have been changing.
IMHO it is the best way to use the AudioProcessorValueTreeState. There is another tutorial, which shows how to do that: https://docs.juce.com/master/tutorial_audio_processor_value_tree_state.html

There are some links on the forum to examples on github… some open source effects from myself included (me toying around, new to juce: ffTapeDelay - be warned, not all is best practice there. And a bigger one, more maintained: Frequalizer)


#8

Right! And also probably a lot of stuff missing from the examples because it’s “assumed”. Not helpful for someone like me trying to learn everything all at once.

For example, I don’t see “AudioProcessorValueTreeState” or “add Listener” shown in any of the JUCE VST example projects - but yet they compile and “magically” WORK. Very confusing for a newbie!

I think another problem here is that I’m trying to learn all this using JUCE - which has different functions and names for things than the Steinberg examples. Rather than helping to simplify the process it’s adding a second layer of confusion. :confounded:

Thank you for the links and help!


#9

Yes it is a second layer.

JUCE is abstracting from the plugin SDKs, so in 95% you don’t have to look at the Steinberg API at all.

The benefit is, that your JUCE plugin will work in different host types, like VST3 (and VST, if you have the license from Steinberg with a little manual steps), AU on Mac OSX, AAX, if you are in the Avid developer program and LADSPA (I don’t know the current status of that, it is not in the primary focus, forgive me - Linux people).

So when learning, maybe you can see it as alternative to the Steinberg SDK with a lot of additional benefit. If you are however familiar with the SDK already, you may recognise similar named functions…


#10

Yes, that I why I came to JUCE in the first place - multiple output format options easily produced.

Now, if I could just learn it…:stuck_out_tongue_closed_eyes:


#11

Yes, it is a challenge :slight_smile:
Good luck and feel free to ask, when you get stuck, there are a lot of helpful people here…


#12

Thank you. I am looking at your “Tape Delay” example and that is EXTREMELY helpful. Thank you for the link!


#13

OK, I used your Tape Delay example - and everything was going good until I got a linker error:

Error LNK2001 unresolved external symbol “public: class juce::AudioProcessorValueTreeState & __cdecl DynawideAudioProcessor::getValueTreeState(void)” (?getValueTreeState@DynawideAudioProcessor@@QEAAAEAVAudioProcessorValueTreeState@juce@@XZ)

I have gone through everything line-by-line and I don’t see any difference between what I have and your example. Any idea what is causing that linker error? It’s something in the Editor section and something with the ValueTree.


#14

This error means, that in the header the compiler knows about a function called AudioProcessorValueTreeState& getValueTreeState(), but when linking in the next step, no implementation was found.

Check your cpp file for the method, that gives access to the treeState member variable.
What sometimes happens:

  • forgot to add it
  • spelling errors
  • forgot to add the class namespace to the implementation (DynawideAudioProcessor::)

Good luck!


#15

FOUND IT - THANK YOU!

Was missing this in Processor.cpp:

AudioProcessorValueTreeState& DynawideAudioProcessor::getValueTreeState()
{
return *mState;
}


#16

OK, it’s working (almost) but there is a problem - the slider in the Editor is changing the value in the Processor as it should but when I close the plugin window (GUI) and re-open the slider is back to it’s initial value as identified the Editor constructor.

Why isn’t the Editor staying persistent when the plugin GUI is closed/re-opened?


#17

If you set a value to the slider in the constructor after it was connected to the valueTree, this is sent as a change from the user. If you use the SliderAttachment, you don’t need to set anything on the slider. It will automatically use:

  • range
  • value
  • textToValue lambda
  • valueToText lambda

Hope that helps


#18

Because the JUCE plugin client code fully destroys and recreates the GUI editor object when the host hides/reshows it. As to why it is done that way, I suppose to save on memory and CPU when the GUI isn’t visible. (But is a pain if the GUI takes a long time to create and/or destroy…)


#19

Yes, I had that “epiphany” in the middle of the night (I’m driven to get my project going).

Thank you very much for all your help!