Looking for overview of how VST scheduling of events, repainting etc. works

gui

#1

I’m new to JUCE and VST coding, but I’m trying to write my first VST plugin which is a kind of automata that generates MIDI and control signals that can be sent to other plugins.

The idea is that the plugin has some kind of regular scheduler or timer, updating the state of its internal model, which in turn updates the visual display in the Editor. When certain events occur in the model it also emits MIDI.

However, I’m unsure how to implement the regular updates and repaints.

The simple tutorials only talk about using standard UI components and adding listeners to them to update the model. Meanwhile, other results of googling, such as Best strategy for painting , are a bit cryptic for me. They rely to too much context I don’t know.

So I’m looking for a fairly n00b-oriented overview of how scheduling events / repainting etc. works in JUCE/VST.

For comparison, I’ve been doing this stuff previously in Processing and in the browser. In Processing it’s very simple. You just write a “draw” handler in which you update your model and repaint your window. And which gets automatically called 30 times a second. In the browser you can achieve the equivalent in with the Javascript timer.

So far, I’ve tried putting the call to update the automata model in processBlock, but I understand I shouldn’t be trying to do any graphics or calling paint from there. So how / where should I be trying to do that? As far as I can tell, paint is just being called when the plugin is launched.


#2

For the repainting, the simplest solution is to use a timer in your GUI that just calls repaint() on the component.


#3

What timer is that, though? In JUCE / VST?

Any links to examples or documentation?


#4

If you use the ValueTreeState for your parameters, there is no need for a timer.


#5

Right, but the simplest solution is to just use a timer. ValueTrees are more involved. (Especially if the data model isn’t already working based on a ValueTree…)


#6

JUCE Timer. Inherit your GUI component from Timer, implement the timerCallback virtual method and call startTimer in the constructor of the GUI editor.


#7

The most important thing to understand is, there are realtime threads and non-realtime threads.

Modern GUI programs have a message queue, that is non-realtime. Either the OS or the host will post messages in there, e.g. “repaint region x,y,w,h on the screen” or “your timer you registered is due”, or “the user moved the mouse or clicked something”, you get the idea.
These messages are just executed, one after anther, so you cannot know, when it happens.

There is the audio thread, that is called from the audio hardware (maybe through the host), that the audio device needs a certain amount of audio data. That needs to go quick, since when this call is not finished in time, there is no data and you get horrible sounds.
Therefore it is obvious, that you must not do something in the audio thread, that potentially has to wait for the message thread.

The audio is always running, from the moment the audio device is started (or when the host starts to play). No matter if there is a GUI or not.

Back to your question, you have two options:

a) continuous repaint:
Create a Timer, that will continuously call your paint at e.g. 30 times per second, and the resulting paint will paint everything according to the current state.

b) changed messages
In literature called semaphore, you set a flag “something changed, you’d better repaint”.
Like @peter-samplicity pointed out, the AudioProcessorValueTreeState and the attachment classes take care of the repaint.

If you want to implement a semaphore yourself, use an AsyncUpdater.

Hope that helps


#8

Many thanks daniel. That’s a very useful overview.

So where can I see some code that does this?

I started with the default JUCE / VST template. So has that already created such a message queue behind the scenes? If so, what’s it called? And how do I post a message to it?

And how do I register my component (I created as a subclass of Component) to listen for messages on it?

Presumably I post the messages from the callback of a Timer. I see in the docs how to create a Timer. But where is the right place to create it? And start it? Is it an instance variable of my Component subclass, that I start running in the constructor of my component? Or should I put it in the PluginProcessor or PluginEditor etc?

I’m still not sure I understand what an AudioProcessorValueTreeState or AsyncUpdater are, and how they fit into this message queue story.

cheers

Phil


#9

The message queue is created by the startup boilerplate, you can access it using the MessageManager. It is a singleton, so you can access the instance everywhere.
Most of the time you only need the MessageManager::callAsync(), that does all you need.

The timer is an interface, so you simply inherit from the Timer class and override the timerCallback(). When starting the timer this callback will automatically be called every n milliseconds from the message thread.

The AudioProcessorValueTreeState is a helper class, that takes care of all your parameter handling, that are shared with the host. You can do everything without it, but I find it a very useful way to manage a plugin’s state. Have a look at the tutorial. There are plenty of them now.

The difference between callAsync and AsyncUpdater is, that all callAsnc calls are executed, vs. if many AsyncUpdater::triggerAsyncUpdate() happend, it is still only once handled (coalesced).

HTH


#10

Right. I think I get that. I’ll go have a play.

Many thanks again.


#11

OK … first follow-up question :slight_smile:

I inherit my component from both Component and Timer.

I implement a timerCallback method which is presumably being called every n milliseconds.

Now, I assume that inside this callback from the Timer, I then put a repaint message on the queue using MessageManager::callAsync.

I see that callAsync takes a lambda. So I assume, inside the lambda, I call the paint() method of my Component.

But where, inside timerCallback can I get the handle to Graphics& that’s needed in that call to paint?

cheers

Phil


#12

Ok, first: the timerCallback() is already from the MessageManager, so no need for callAsync().
And second, you never call paint() yourself. You call repaint(), which invalidates a rectangle (default the whole component). This will result into a paint call from the system as soon as possible.


#13

OK.

Brilliant! So I just literally have to call repaint() inside the timerCallback method to ensure that the component is repainted every time the timer ticks?


#14

exactly :slight_smile:


#15

Cool. It’s now doing what I wanted.