ModuleWidget::step() for GUI Updates?

Most of the modules I’ve written so far use a timer within process() to periodically do stuff like reading from controls and updating LEDs. But I wonder if using the step() method in ModuleWidget would be a better place for this?

I’m used to making embedded applications with at least an audio and a GUI thread. So it feels funny to interrupt the audio thread to do stuff that only need to happen at 60fps or something. But most examples I’ve seen just have the single process() callback doing everything.

Does anyone have arguments one way or the other? I’m starting on a new series of modules and would like to improve my plugin coding style if possible.

Thanks!

1 Like

Are you sure the calls to update the LEDs interrupt the audio thread? They probably just store a value that is read by the GUI thread at the next frame draw update.

I’m not sure which is why I’m asking. :slight_smile:

Well, I checked in the code and that’s what setBrightness and setSmoothBrightness are doing : only storing the values, they don’t wait around for the GUI to actually update or something.

void setBrightness(float brightness) {

        value = brightness;

    }

    
    /** Emulates light decay with slow fall but immediate rise. */

    void setSmoothBrightness(float brightness, float deltaTime) {

        if (brightness < value) {

            // Fade out light

            const float lambda = 30.f;

            value += (brightness - value) * lambda * deltaTime;

        }

        else {

            // Immediately illuminate light

            value = brightness;

        }

    }

Doing it in module process is the normal place, and those things don’t take much time. Of course often responding to changes in controls takes a lot of time.

If you really need to move some processing off the audio thread, you have several options. As you know, of course, going multi-treaded brings is a ton of complexity, so you better really want to to that.

Widget::step() is an easy way to run stuff on the UI thread. I do that sometimes myself. It’s not recommended, and in VCV 2.0 it won’t work if you run “headless”. I think it’s so handy I’m still going to do it for now…

The “best” thing to do is create a new thread yourself and run whatever you want on that. A lot of NYSTHI modules do that. I do that in one module “Colors”, mostly as a joke. It generates noise by doing an inverse FFT of a 64k frame of data. Since that is quite time consuming, I do it on a worker thread I create. It took way too long to get that working reliably, and lots of unit tests…

Also, have you read this paper? It’s not the best thing in the world, but I haven’t heard anyone take serious disagreement with it: SquinkyVCV/efficient-plugins.md at main · squinkylabs/SquinkyVCV · GitHub

1 Like

Squinky: thanks for the tips. I’m not getting into anything too heavy in VCV yet that needs extra threads or anything. It makes me feel best to slow things down and avoid a lot of code running over and over within the process() function. I’ll stick with that plus spinning up my own threads for long running processes, I/O, etc.

Thanks!

1 Like