Exploring RNBO
Creating a VST3 plugin with a custom UI:
Welcome to my blog! This page is a guide to creating your own VST3 plugin with the help of RNBO [1], the new Toolchain released by Cycling ‘74 [2]. Here I am documenting my personal technical and creative process: some of the steps took a while for me to figure out, so I’d like to share it with you. The blog results from what I currently think is the best course of action to achieve my goal: creating a suite of versatile and efficient VST plugins with RNBO and JUCE [3]. Hopefully, this will be helpful for any Max [4] and RNBO beginner!
I am essentially following the guidance and examples provided by Cycling ‘74 but adding information about bugs, shortcuts, and other tips I found along the way. You can have a look at the documentation here:
Starting in Max
2. A look inside the RNBO Patcher
Let’s now have a look at the RNBO patch I have created. The topic I have chosen to explore for this example is nonlinear distortion, also known as waveshaping.
In this specific case, nonlinear distortion without lookup table seems like a good option to make sure the plugin is light and efficient, by using a real-time transfer function. Here is a nice visual an excellent explanation of this effect:
https://splice.com/blog/what-is-waveshaping/ [5]
Please refer to chapter 11P, paragraph 11.4 of “Electronic Music and Sound Design Vol. 3” [6] for a thorough explanation of this process.
Here is a simple diagram of how the patch works, plus a peek at what it is like within the RNBO environment:
About debugging
First of all, remember that you don’t need to keep the RNBO Auto-compile always on when working on a patch: you can just turn it on when ready to compile and test the results. This workflow will be lighter on your device as continuous Auto-compiling can slow things down.
There have been several issues during the creation of this patch, and more specifically, problems around working with two parallel chains to maintain the stereo image of a stereo audio file.
Initially, I had four cross~ filters, two for each channel, and I tried to use all the outputs to work with the balance parameter.
For instance, by having two cross filters for the left channel, I was crossfading between the low-frequency distorted signal and the clean high-frequency one, and the high-frequency distorted and the low-frequency clean signals.
This created several issues because the filtering impacts the phase of the four different signals per channel. The solution has been to reduce the balance parameter to two signals per channel, a low-frequency distorted wave (saturator) and a high-frequency distorted wave (exciter).
Another issue arose when trying to create a parameter that could specify the split frequency of each pair of filters (distortion and saturation). The approach was creating phase issues as well, causing stereo imbalance.
I then decided to settle with one parameter that allows the control of the split frequency from 500Hz to 4000Hz: 500Hz works well with distorted low-frequency components. At the same time, 4000Hz is a good starting point to saturate high frequency by enhancing the harmonics without distorting the lower frequency content too much.
3. Exporting to C++ source code
The next step is to export the patcher to C++ source code, which can be used to create a custom UI using JUCE.
I know that many will dislike using the Projucer, and in fact, there are some annoying aspects of using that instead of creating your own .h and .cpp files: but for now, here I will follow “the book”!
An official guide on GitHub provides the user with an example template that can be handy: https://github.com/Cycling74/rnbo.example.juce.
I suggest using Visual Studio, installing the CMake extension [7], and exporting the code with the following name: rnbo_source.cpp. The source code must be sent in the export folder of the rnbo.example.juce root directory.
If you name it differently: remember to modify the CMakeLists.txt file! Also, if you are working with an M1 Mac, you must comment out the universal binaries line.
The next step is to export the patcher to C++ source code, which can be used to create a custom UI using JUCE.
A slight interlude about the Projucer: in this case (using the RNBO custom UI example from Cycling ‘74), it is a more feasible option to proceed ‘by the book’. But to properly learn C++ with JUCE, it is better to avoid using it because of the way it automatically generates code. It can be daunting and challenging to understand how the custom UI code connects with the other components of the overall project, so I would not suggest using it to create a JUCE application from scratch.
I will now quote my classmate Jake as I found his observations very valid. My question was, why do you dislike the Projucer?
Answer Below:
‘Cause it takes away from understanding how JUCE works. I.e. you don’t actually need to have a file called MainComponent.cpp and .h. The automatic file generation from the Projucer creates that for you and, as a result (as a newcomer), leads you to adhere to particular ways of writing and organising your code.
A lot of code I was looking at and trying to understand for my project isn’t actually written out like that. Most people seem to separate their gui code from the actual processes, so I’ve been finding it really difficult to break it down.
It also takes away from you looking at the main.cpp - where a lot of important stuff is actually going on - I’d say looking at that is what gives you a better understanding of how JUCE works (and how to write and organise your code in a juicy way).
4. The Projucer: UI starting point design
It is fun to prototype your UI design on paper before starting to ensure enough space for all the parameters to be easily accessed, viewed, and understood by the user.
Here is my first sketch, and I am going to use a painting as a reference for my colour palette: the harbinger of Autumn [8] by Paul Klee.
It is easy and fun to extract a colour palette and find exciting combinations. In this case, I really like the geometric shapes, which are not perfectly aligned, and the accent colours provided by the orange of the tree: I will use it as an action/accent colour in my interface. (wow, so artsy, so Goldsmiths...).
I am reproducing this in the Projucer, thanks to the Graphics section of the GUI editor. This allows me to create a few Path objects, which is much easier than writing it in code in this specific instance!
There are, of course, cases in which it is much more convenient to follow the advanced GUI layout techniques, as shown in the Juce documentation, but not today.
These are the steps to follow
With the Projucer, create a new project (the basic plugin configuration will work just fine).
This project must be saved in your project folder directory named UI.
Remember to select which exporter you are working with, in my case, Visual Studio 2022!
Also, you may have to tick the option in Tools->GUI editor enabled.
It is now time to create our custom UI component: select GUI editor-> Add new GUI component to begin. You can name it RootComponent as in the official guide.
We can also delete the pre-populated files PluginProcessor.cpp/.h and PluginEditor.cpp/.h as we won’t need them.
A few extra tips
When creating your GUI in the Projucer, you can start filling in some information (which you can also change up later in the code). Will will save you a lot of time to:
Remember to name the sliders with the exact name the parameter has in RNBO; otherwise, they won't function.
Set the sliders' range and, if needed, the skew factor.
Name the labels accordingly by filling in the name and text boxes.
Set the font type, size, justification, and colour to save precious time and go to the gym.
Set the initial width and height of the component.
You can also easily set the frame of the number boxes of the sliders to be transparent.
5. Compiling with your IDE and CMake:
Depending on the nature of your patch, you will need to modify some files accordingly. You can refer to the official guide on how to implement your custom UI here:
https://github.com/Cycling74/rnbo.example.juce/blob/main/CUSTOM_UI.md
I will now list a few possible bugs you may encounter along the way. Hopefully they can help make this process easier:
When working with other projects and exports, I noticed that saving two different .vst3 files in the library (to be scanned by the DAW of choice) would result in two separate projects not launching correctly. I was opening this specific distortion effect, but another RNBO plugin would open instead. The issue can be solved by changing the PLUGIN_CODE field (inside the plugin.cmake file) set as a default to “Rnb0”, to another code, for example, “Rnb1” or “Rvb2”. Every different .vst3 needs a unique code! It makes sense, of course, so it is worth checking if the problem appears.
The same applies to the PRODUCT_NAME field (also inside plugin.cmake) field: if you have two different versions of the plugin with the same product name, you will get a mess when your DAW tries to read the available VST3 target directory.
Another issue could be the set configuration provider setup in the c_cpp_properties.json file: ensure the configuration provider specifies using cmake-tools (check the third screenshot below).
If you are using Ableton Live [9] to test your plugins and you are facing these issues, it is also worth checking out this page about resetting Live’s Database:
What you may need to change in the Root Component.cpp file:
Set the unit of measurement of the parameter, remember your math teacher screaming “what is this, apples, pears or millimiters?
juce__slider-> setTextValueSuffix (" suffix");Check again that the ranges are correct:
juce__slider->setRange (min, max, interval);Set the initial value:
juce__slider->setValue (value);To clean up the UI a bit, set the quantity of decimals displayed:
juce__slider->setNumDecimalPlacesToDisplay (value);If you’d like to have a tooltip for each parameter, to display automatically when the mouse hovers on the slider/button, you can easily add them to your project:
juce__slider->setTooltip (TRANS("ParameterDescription"));
You will also need to create an instance of the tooltip window in your header file. you can follow these instructions I found on the JUCE forum (no need to destruct this pointer!):https://forum.juce.com/t/no-button-tooltips-in-juce-widgets-demo/36479/3
Do yourself a favour and remember to lower the volume of your speakers when building, you don’t want a nasty feedback loop to pierce your ears every time you build, especially when working with distortion.
6. Building and customising the rotary sliders
At this point, the plugin should be fully functional and can be tested when the build is complete.
The Cmake bar that lives on the bottom of Visual Studio will probably be set on Build [RNBOApp]: Please note that if the build is started with this configuration, the VST3 plugin file will not be created in the /build directory of the project.
If you want the project to export a VST3 file, select the appropriate target from the menu on the top when you click the [ ] field (see screenshot below). At that point, if the build is successful, you should be able to find your .vst3 file in the following directory:
/rootDirectory/build/RNBOAudioPlugin_artefacts/Debug/VST3
Now that the project is nearly finished, it is a good idea to customise some of the UI components! This can be easily done by following the official guide on the JUCE website or by using other online resources:
https://docs.juce.com/master/tutorial_look_and_feel_customisation.html
Here is a list of what needs to be done grosso modo:
Our MainComponent is, of course, the RootComponent, where our custom UI lives.
A new class should be created in our header file before our MainComponent, aka the class RootComponent. Here we can override the virtual functions we want to customise to create our custom sliders, in my case, the rotary ones (how original…).
A new private variable for the custom look and feel class must be added to the RootComponent.h file, plus a new reference in the RootComponent constructor (Constructor_pre field in the .cpp file).
It is essential to remember to update the destructor in the .cpp file! If you don’t destruct, you will get a Jassert error when building the project (it can be seen in the terminal), which will cause memory leakage, and nobody likes that.
This is it! I hope you enjoyed the blog and found helpful tips and information about this beautiful new tool from Cycling ‘74.
Hasta la vista,
Ottavio
Gallery
Demo
Bibliography & References
[1] Cycling ‘74: ”RNBO”. Available @: https://rnbo.cycling74.com/ (Last Accessed: May 13, 2023).
[2] Cycling ‘74. Available @: https://cycling74.com/. (Last Accessed: May 13, 2023).
[3] Raw Material Software Limited: “JUCE”. Available @: https://juce.com/. (Last Accessed: May 13, 2023).
[4] Cycling ‘74: ”Max”. Available @: https://cycling74.com/products/max. (Last Accessed: May 13, 2023).
[5] Splice Blog. Available @: https://splice.com/blog/what-is-waveshaping/. Last Accessed: May 13, 2023).
[6] Alessandro Cipriani and Maurizio Giri, Musica Elettronica e Sound Design, volume 3, 1st Edition 2021 Rome: Contemponet. https://www.contemponet.com/shop/electronic-music-and-sound-design-2-max-8/. pp 217-221, 284-288.
[7] CMake. Available @: https://cmake.org/. (Last Accessed: May 13, 2023).
[8] Tate: “Biography of Paul Klee”. Available @ https://www.tate.org.uk/art/artists/paul-klee-1417. (Last Accessed: May 13, 2023).
[9] Ableton Live. Available @ https://www.ableton.com/en/. (Last Accessed: May 13, 2023).