Is repaint not needed for underlying object?

Having a look at the " AudioThumbnail" tutorial. At the end there are suggestions on how to make the code more efficient. Example AudioThumbnailTutorial_03.h separates drawing of audio wave form and playback cursor into two classes and thereby two separate repaints. The text states “we can avoid redrawing the waveform every (playback) frame”

However, I don’t get how the underlying waveform gets restored when the playback cursor has moved without calling repaint. Wouldn’t there be a gap with the wrong color if the waveform is not restored when the cursor has moved to a new position?

I palced DBG-notifications in the paint functions for the two classes in the example.

The class for playback cursor and waveform thumbnail seems to call paint() the same amount of times and always alterernating; one-two-one-two… The waveform is redrawn for every playback frame. I can clearly see it follows the framrate of the playback cursor if I change it.

So while this makes sense to me (that the waveform also needs to be redrawn everytime the cursor moves) the statement in the tutorial about separating the tasks into two classes to make the code more effective is obviously incorrect.

The tutorial text is perhaps misleading. Juce is actually pretty eager to repaint components and separating things into separate components might not really give any significant performance boost, if it isn’t handled carefully. (There’s an optimization possibility which is to repaint only a part of the component, which might be happening with the AudioThumbnail. edit : Looks like that’s not happening in the tutorial code, though, the thumbnail component seems to be repainted completely at each update.)

So a partial repaint of thumbnail, would that be complicated? Perhaps not a very important question for a beginner in Juce but I’m just curious.

Yeah, that stuff is pretty miserable to figure out. If you don’t absolutely need it, don’t bother with it.

1 Like

I’ll save it for a rainy day then :slightly_smiling_face:

The AudioThumbnail uses a different optimisation: It takes the clip area into account. The worst case it cares about is if you zoomed in very much, most of the thumbnail is outside. The code is clever enough not to loop through all the thumbnail but only the visible part.

Reading the quote in question again:

Maybe have a look at the clip bounds, when the playhead moves. In that case only the little area that was covered before needs repainting. Maybe it is as clever as it claims?

It isn’t, both the playhead and the thumbnail components make a full redraw of the components each time. (I checked the clip bounds myself already.)

Ah, that’s a shame. Thanks for checking.

As I remember, something similar was discussed here

Are you using DrawableRectangle as Component? In that case the same happens as described here.

Or if you use paintOverChildren, that is following a paint() before, again, exposing the same problem as described here.

Just tested the code from a link with JUCE_ENABLE_REPAINT_DEBUGGING=1 and it shows that only DrawableRectangle repaints.

Interesting, so that observation is in direct contradiction to @xenakios one.
Maybe a platform dependent thing?

Yes, perhaps but is that dependant of splitting the paint job between two classes? Isn’t more function calls also an efficeny drawback? No big deal for me, just curious.

Generally speaking a function call in GUI scope is really neglible unless in that call a lot of memory is accessed, so that a context switch might hurt. But in most cases the optimiser will sort that out.

In this use case the most expensive operation is the loop drawing all the rectangles of the thumbnail. So limiting this to the area where the occluding playhead moved is the best you can do.
According to xenakios experiment juce is not clever enough to draw only the dirty area in that case though, but who knows maybe there is more to it (is playhead opaque? and such questions).

Avoiding repaint() as general optimisation is pretty painful in JUCE, since a lot happens magically behind the scenes (like in most modern GUI frameworks) or is triggered by the OS outside your control. A better approach is to make your draw calls as quick as possible with tricks like the mentioned one in the AudioThumbnail.

It’s not the same code, I only tested the tutorial code posted by the original poster. losslessgo posted and tested another code that is using a DrawableRectangle for the playhead.

That is all to confusing if we cannot even agree what we are talking about.
Like I asked before, are we talking of a separate Component (be it the bespoke playhead component as in the tutorial or a DrawableRectangle used as Component) or about calling paintOverChildren() in the paint component that draws the AudioThumbnail?

Anyway, stuff works for me. Good luck