I wanted to avoid using JUCE. This isn’t to meant to offend anyone, but I thought as beginner using smaller libraries, or simply including vst directly would be the best choice. It’s been about a year since I started exploring my options for audio programming, and now I am much better informed. Plugins are the way to go. The host handles the final audio output, while I just take care of the signal processing.
Now I want to build custom GUIs built with inkscape or GIMP, but most gui code is prebuilt. How do I take something I made in a graphics editor and put it in my gui?
Also is there a way to everything I want to do with my vst without JUCE or Qt? Can I use openGL for 2D GUI implimentation?
If you’re using SVGs for your UI you’ll want to check out the Drawable class. You can load an SVG with it and place the result directly on screen as a type of Component!
If you’re using raster graphics like sprite sheets and such you will be relying on loading and drawing Image objects (or similarly, using the DrawableImage type).
As for getting the SVG or raster graphics “into” JUCE there’s some helpful info in this blog post about it. Basically you can add files to your project that the Projucer app will convert to an array of bytes (const char*) that you can then give JUCE to load.
You could write it yourself, but depending on your needs it may be fairly complicated/involved. If you’re looking to do Object-Oriented-style interfaces like what JUCE offers, you may be best suited using the library.
If you really just want to easily put controls on screen without hassle or an Object-Oriented API I would look at something like Dear IMGUI. That kind of approach lets you define your UI all as a series of functions which can handle events and draw to screen, so putting the interface and actions together would be pretty straightforward.
Why? Implementing all the boilerplate code for a VST2(*) (let alone VST3, AU etc plugins) is a massive hassle. Juce makes all that much more simpler with the AudioProcessor base class and the helper classes for that.
(*) It should be mentioned that as a newcomer to plugin development, you can’t release VST2 plugins publicly anymore, though. Steinberg had a deadline in October 2018 for obtaining the VST2 license. If you are able to obtain the VST2 SDK from somewhere, you can of course privately build and use VST2 plugins yourself.
That’s very not beginner attitude. And if you don’t really need some complex graphs this would actually back fire you in the long run.
JUCE actually provides a toolkit that’s much beginner friendly than others.
You can try iPlug2 if you want some bleeding edge and more permissive license out of the box. but for getting started JUCE is the way to go.
The curved thing I think is an SVG. The logos I think are SVGs as well, though we’ve used PNGs before. The icons are either SVGs, juce::Path for the curve shapes or from Font Awesome (the power button).
Everything else, including the knobs are just calls to basic juce::Graphics methods.
Exactly! Plus I use SVG just for icons/logos too. I rewrote to JUCE a huge Windows application which I created 15 years ago, did GUI’s for embedded Linux devices as well as iOS/Android devices so this approach seems to fit everywhere now. No need to use some external tools etc.
I have mixed feelings about LookAndFeel and Buttons too. For example I don’t fully understand why Label has its own font which can be overridden by L&F eventually, but TextButton doesn’t and you have to override a method in a L&F class. I created DrawableTextButton which can have a SVG icon and text placed freely and extended Look&Feel class with methods to paint this button according to the L&F paradigm but it caused circular references between both classes and a need of dynamic cast etc. It works but I feel too that a better (or maybe more convenient) approach is just to override paintButton in the end.
I would disagree with this. That would mean you need lots of Button classes around each for a particular type of drawing. This makes it very difficult to change colour themes or even LAFs entirely.
What I’ve started doing more and more these days is using Component::getProperties() to store additional information about buttons. This means you can do things like add icons/paths, specify corner size etc. and just draw it accordingly from the LAF without having to create new classes.
One step further from that would be to create multiple free drawMyButton (...) functions which get delegated to depending on properties set.
In general, the more UI code I can move to a LAF type class (even with my own methods), the happier I am. It makes it much, much easier to change graphics this way and keeps all the drawing logic out of the behavioural classes and behind essentially a single API.
Colour themes we do with some global statics and a message sent to all components to repaint(). Works perfectly.
Corner sizes are global constexpr.
Having a single class with loads of if/switch statements to handle all the button possibilities has always just got me into a complete mess after a while. Whereas a simple button you know where to look for the problems, and if the style needs changing you know exactly what you are breaking:)
This is ok, unless you have drastically different colour schemes which require differences to the way you actually draw things. For example, our light scheme has gradients used for shadows with are not only lighter than the dark themes but actually go different ways. Similarly, highlights for buttons are just completely different in dark/light themes.
Ok, but what if you have buttons where you want different corner sizes? Some could be lozenge shape, some could be a soft round, some hard etc.
I think having dedicated classes works up to a certain size but in something like Waveform where we have thousands of buttons/controls/elements etc. it doesn’t really scale.
Simply adding a new ID and then specialising drawing based on that, even if all it does is delegate to a named method is much simpler IMO.
In your example, using a ShapeButton or similar would be much more preferable (although I do have a subclass which simply takes a path in its constructor).
Well exactly. So where you want things different we just use a different class. Related things tend to use the same button rendering code, but to have a global lookandfeel that has all the button rendering code is just perverse complication
And anyway I can’t figure out why, even if you wanted all the rendering code in one place why you’d not implement WaveformButton as a parent class containing a master complex paintButton(…) function with all your cases in. Having generic Button classes that go back to a separate master look and feel class only really makes sense if you want to swap the complete look and feel of the buttons around on the fly, and I’m not sure I can think of a good looking app that does that …?
Well what I’m saying is that we didn’t use to have several LAFs that drew everything, then I had to add support for multiple, user defined colour schemes, then half the drawing looked terrible and the only sensible way to fix it was to create multiple LAF instances. For example, we have at least a dark and light LAF and also a “simple” LAF for low-cpu usage (although these days I’ve simplified that by having a “low-detail” member in the LAF that is checked in all of the drawing methods to avoid overly complicated shapes and shadows etc.).
I guess it comes down to personal preference but in general I’ve simply found it much easier to reason about our drawing since moving towards everything having LAF methods rather than being hidden in Component subclasses.
I think maybe we’re talking at slightly cross purposes as for button there is generally less difference. For sliders though, we have multiple styles that can absolutely change dynamically depending on if they have active modifications (like LFOs etc.) or are currently being assigned to from MIDI etc. When you have components that change the way they look on a very dynamic basis like this, I’ve found it easier to use dynamic variables like properties to determine this behaviour. For static components, maybe a button subclass is more explicit.
In all honesty we have a mixture of both of these methods depending on the purpose. We do have a “StandardButton” class that draws most of our buttons but I’ve never particularly liked that. We also have several different button subclasses that have special behaviour but again, these are probably there because they predate std::function and the much more customisable way of using buttons these days.
I guess the overriding thing for me is that in my Component building I think of “this is a button, users will click on it to trigger some event”, in my lookAndFeelChanged method I think “some UI related property has changed, update the button properties to reflect this”, then in the LAF methods I think “this is how I draw a button with these properties”.
Again, maybe not necessary for small apps but I’ve found this scales much better for our use cases.