Is Juce really this much slow?

It has been about 5 months that I am trying to create a plugin in Juce. The window of my plug in is resizable. It has two LEDs on it. They are blinking(Each one consists of 15 images. I know this is not recommended ). It does not have many components.Only 4 or 5. But the problem is the GUI is very slow. I have to wait two or three seconds to see that one paint method is being called.

  1. For example I am trying to read the value of a knob(slider) and do some math and then print this into a label. All of these are happening in the paint. Then when I try to see this on. the gui, it gets into paint method. It does what it should do but after changing the content of the label, it takes seconds to repaint the label, I don’t want to add a repaint call in the paint :slight_smile: Actually I already tried it but it didn’t work.

  2. Timers!!! I tried to set a timer with 1 ms interval, it is being called perfectly when I have only one component and doing nothing :slight_smile: but when I add more code and try to put a counter in the timer callback to see how accurate it is, I saw that it is lagging. When I have an LED blinking animation in the gui, timer cannot call the timercallback function on the time.When the gui is empty, I tried to measure the time between two mouse clicks, it works perfectly but when I add more stuff to gui, it starts lagging. Difference is huge. I use a metronome to click correctly. When the gui is empty, metronome 120bpm(500ms) and my click time value is between 480-520 . But when I add more components to gui and try to use the same code. I get something between 320-390. Timer slows down. I had to use millisecondCounter to get over this problem. I don’t use timers for milliseconds anymore.

  3. When I add one blinking LED animation to gui, it effects everything in terms of timing , I fix everything and then when I add another blinking LED to it , it even effects the previous LED :slight_smile: it slows down, it speeds up, rendering stops or images stops being displayed.

So my question is, I don’t use any special method to do these things. You can see my previous posts. I am just trying to understand what’s going on. All methods that I use, are from tutorials and examples. Is there any one else who has problems about timing and these kind of strange behaviors. Whenever I need to add something to plugin, I am freaking out that something else is going to fall apart. I’ve started thinking that Juce gives a limited source to editor to keep everything safe on the processor side.

Thank you if you read all of it.

This is simply too slow for the kind of UI that you have described, there must be something odd in your implementation of that.

This is a hint of something that you shouldn’t do, for example: you shouldn’t update any Component in your paint() calls (I mean, you shouldn’t alter their state like changing the text on a Label, the value of a Slider, etc.).
A paint() callback must only be used to paint the Component it belongs to, in its current state.

Also, the necessity of overriding paint() is also a rare occasion, that occurs when you want to implement some custom Component yourself. If one only uses widgets provided by the JUCE library, one hardly needs to implement paint() callbacks at all.

And then Timers: correct me if I am wrong, but from what you write it looks like you are measuring the time between two clicks of the mouse using a Timer? That doesn’t sound like the most ideal approach: a Timer is something that repeatedly performs a task at a given interval, and expecting that the timer callback is called exactly at the moment when your mouse is clicked, is simply expecting too much from it.

IMHO the correct approach would be to react to mouse clicks with the proper callbacks (e.g. mouseDown in MouseListener, which is a base class of Component already).
In those callbacks you collect the timestamps (for example via Time::getMillisecondCounter() or Time::getMillisecondCounterHiRes() if you really need that precision) of when the clicks happened and do all the logic for updating the BPM.

The only use I see for a Timer could be to have a timeout, something that says: “ok, if the user doesn’t click for a second, then the update to the BPM is finished”. That is done with a Timer which you can re-start with startTimer(1000) every time you handle the mouseDown callback.

And then, in the timerCallback that could be finally triggered, first thing you do is stopTimer() because you don’t need the time to fire again, and finalize your BPM update or whatever.

3 Likes

No, not really. There really are fast and responsive UIs out there that were created using JUCE.

But it’s also possible to make it as slow as you’d like. If you do want it fast then you may have to use it as right. It’s not easy, C++ never was easy…

If you want to get there, a path to the correct usage may consist of creating a small standalone example that recreates your problem, sharing it and getting feedback. @yfede already did a commendable job at trying to trouble-shoot your issues based on guesswork, but it may be more effective with a concrete example.

thank you for your answer. This is what I need to find out. I need to know will Juce be enough to create plugins with 30 LEDs(all blinking with a different interval value and all of them calling images. I need to stick to images because otherwise it won’t looks like a real LED).

I will add a example here soon. But basically I have 14 images . From no light to full glowing LED. Then it should go back to no light situation. So it will fade in and fade out. In total there are 28 images. I set a timer. The start timer value is depend on the slider(its range is from 0 to 1). its value is mapped from 0 to 36. Because the longest bpm will be 60 (1 second). if i draw every single image after every 36 miliseconds. 28 of them will be display in 2836=1008ms=1 sec=60bpm. So if my slider value is 0.5, it will convert it to 18. then I pass this value to timerstart function in my blinkLED class.( in my map function 36-(36slidervalue) =>
36-(360.5)= 18 => 2818=504ms=120bpm)

Here it the tapping with timer.


I stoped using this. when I add more than one LED to gui it start lagging.

I use this method now. but I get the first and current time in paint. There is no anywhere else that I can it. If. I set a timer for it, again it will do the same thing. I won’t count the time correctly,

thank you for your answer.
Yes, there are many plugins made with juce and they are very responsive. I am trying to find my mistake or the limit of Juce. I want to build some different plugins and after that I will create a complete system that will include all of them. There will be more components, cables, 7 segment displays, LEDs, flashing effects,… I am not an expert in Audio Programming but I want to learn. But this gui stuff is driving me crazy. I added my code in GitHub. You can see everything. You can test it in your DAW. Especially if I don’t use repaint in lamp it does not refresh it. i put a comment in the code. you can see it.

void TappingTestAudioProcessorEditor::buttonClicked(Button* _clockRateButton)
{
    MessageManagerLock lock;
	if (_clockRateButton == &clockRateButton && !pressedOnce)
	{
		clickTime = 0;
        pressedOnce = 1;
		startTimer(1);

you’re locking a function that is only called on the message thread, so that is problem 1.
problem 2 is that you’re starting a timer that fires EVERY millisecond.
a 60hz refresh rate is about 16ms
a 30hz refresh rate is about 33ms.
That startTimer(1) is probably the culprit, based on what your timerCallback() is doing.

Also, please help out the reader and clean up your code’s indentation and formatting before you share it publicly in a git repo.

1 Like

I just had a quick 2min look through your code, I didn’t run it. A few things that I immediately spotted are:

After all, all this might not seem too obvious if you are just starting with all this. However, if you don’t know what slows down your plugin, it’s a good idea to run a release build of your plugin under a Profiler and spot where the most time is spent in your code. I successfully spotted some GUI performance bottleneck in various projects through the Profiler myself in the last months

1 Like

that one from highresolutiontimer. I forgot to delete it.


int Lamp::returnImageSize(int i)
{
	int imagename[28];
	imagename[0] = BinaryData::Image_0_pngSize;
	imagename[1] = BinaryData::Image_1_pngSize;
	imagename[2] = BinaryData::Image_2_pngSize;
	imagename[3] = BinaryData::Image_3_pngSize;
	imagename[4] = BinaryData::Image_4_pngSize;
	imagename[5] = BinaryData::Image_5_pngSize;
	imagename[6] = BinaryData::Image_6_pngSize;
	imagename[7] = BinaryData::Image_7_pngSize;
	imagename[8] = BinaryData::Image_8_pngSize;
	imagename[9] = BinaryData::Image_9_pngSize;
	imagename[10] = BinaryData::Image_10_pngSize;
	imagename[11] = BinaryData::Image_11_pngSize;
	imagename[12] = BinaryData::Image_12_pngSize;
	imagename[13] = BinaryData::Image_13_pngSize;
	imagename[14] = BinaryData::Image_13_pngSize;
	imagename[15] = BinaryData::Image_12_pngSize;
	imagename[16] = BinaryData::Image_11_pngSize;
	imagename[17] = BinaryData::Image_10_pngSize;
	imagename[18] = BinaryData::Image_9_pngSize;
	imagename[19] = BinaryData::Image_8_pngSize;
	imagename[20] = BinaryData::Image_7_pngSize;
	imagename[21] = BinaryData::Image_6_pngSize;
	imagename[22] = BinaryData::Image_5_pngSize;
	imagename[23] = BinaryData::Image_4_pngSize;
	imagename[24] = BinaryData::Image_3_pngSize;
	imagename[25] = BinaryData::Image_2_pngSize;
	imagename[26] = BinaryData::Image_1_pngSize;
	imagename[27] = BinaryData::Image_0_pngSize;
	return imagename[i];
}

Here you are creating an array and initializing it every time you call the function, which I see happens in the timerCallback() that updates the frame (so quite frequently). That may also introduce some overhead, but sincerely I interpret it as an indication that you should deepen your knowledge of C++ before you attempt to proceed in even more complex projects.

Thank you very much.

I see… this is what I should do. I believe this will help a lot. I will update the post when I tested it :slight_smile:

Thank you. Yeah you’re right. now I see the problem of this method :slight_smile:

Another suggestion is to use a single Timer to feed your LEDs with ticks to do their fading animation, rather than have each of them run its own Timer. After all the frame rate (hence the Timer periods) is the same for all

That is actually loading from ImageCache, which is a simple lookup with the memory address as hash value, so no performance impact here.

But calling the getClippedImage might not be ideal, it potentially alters the original, if you look at the docs:

This will not make a copy of the original - the new image will keep a reference to it, so that if the original image is changed, the contents of the subsection will also change.

Since you do the same change each time, that might not play a role.
A better approach would be to use the g.reduceClipRegion() when painting instead.

Rectangle<int> lampCropArea(2, 2, 70, 70);
Graphics::ScopedSaveState saver (g);

g.reduceClipRegion (lampCropArea);

g.drawImage (lampImage, getLocalBounds().toFloat());

The ScopedSaveState makes sure when you leave the scope, the clip region is restored (probably not necessary)

Yes good point, I was coming from a Drawable background where there is no cached version, probably you are 100% right here. However, as a general rule, I’d prefer to do all the things that are needed only once in a single setup step instead of repeating them over and over again and would try to minimize overhead during timer callbacks and paint down to the calls that are unique for each callback (e.g. calculations that rely on a size or some state)

I agree, but the ImageCache is an exception that was created exactly for that purpose:
Because copying an Image around would be expensive, the Image is holding its pixel data in a shared object, and the ImageCache is there to keep those shared objects alive and accessible.

On the other hand it is important not to alter an Image from the ImageCache without creating a copy first, because you will alter the image in the ImageCache, and you will be returned the altered version from then on.

TL;DR: don’t hold copies of Image from an ImageCache, that is not necessary. The use of lampImage here is actually correct as kind of pointer, which of the 28 images to paint.

btw where should I do these kind of changes? Should I use a timer? I preferred the paint because creating a timer and calling it again and again and assigning a value to a parameter did not seem good to me.

I am having a similar probelm. I am trying to write an audio plug-in that visualises the current state of a prameter that is time-varying due to an LFO.

I thought the intuitve way was to inherit the timer module in the AudioProcessorEditor object and override the timerCallback method such that it uses repaint(). If you look at the docs, repaint is not reliable in the sense it does not guarantee it will repaint the GUI every time you call it…

" Calling this will not do any repainting immediately, but will mark the component as ‘dirty’. At some point in the near future the operating system will send a paint message, which will redraw all the dirty regions of all components."

I would also like to know a way of getting a reliable updated to the GUI.

That’s a wrong interpretation. It will paint for a fact as soon as possible.
The painting is asynchronous from the message queue. It also does some optimisations behind the scenes, e.g. coalesce multiple repaint() calls and create the union of areas that need repainting…

And there is no other way, interactions with components including painting are not thread safe, that’s why they are only handled by the message queue. That is also the reason, why you should not do anything time consuming from the message queue, because in that period no painting can happen, and all GUI interactions freeze.

2 Likes

Yes sorry - my mistake with my wording!

Thank you for explaining, this has been super helpful! I will try and identify the bottlenecks in my callback methods but I will post what I am doing here because I am sure you will be able to spot trivial mistakes straight away:

Currently in my timerCallback() metthod, I am retrieving the instantaneous value of a parameter and storing it, and then I call repaint(). Then in my paint method, I am drawing a line where the width is a function of the retrieved parameter.

1 Like