Efficient multiple wavetables painting

I’m drawing multiple waveforms on a component and over that (in a children component) I paint the selected waveform that the user is playing.
Since I want to change the wavetable playing in real time, I want the painting to be fast and efficient (only repainting the active waveform on top instead of all of them would be the way to go). But afaik if a component isn’t set to opaque the component under it will be repainted (taking a good chunk of CPU when the LFO triggers constant repaintings), which is kinda confirmed by the similar CPU usage when using this aproach.

So for now I’ve tried 4 methods (all of them with setBufferedImage and attatching an openGL context to render on GPU):

  • Path rendering: looks great, melts CPU
  • drawVerticalLine: looks great except for waves with accentuated slopes like Saws. Plus it isn’t efficient enough.
  • OpenGL (PolyLine2D): takes a good amount of CPU (Mojave/Xcode 10 mentioned problems?). Haven’t tried raw OpenGL by myself since I don’t wanna dive in yet and is giving me compiling problems in cross platforms, I discard this aproach for now.
  • Pixel painting on an image: the best performance so far, but again for accentuaded slopes I need to use drawLine which makes the CPU usage high again.

Am I overcomplicating this and can be aproached by a much simpler way, or is it an usual problem where you must make some concessions?

The AudioThumbnail is pretty optimised, so I would start there. It uses RectangleList internally, and is quite clever not to do extra work, like clipping in a Viewport.

If the waveforms in the background don’t change, I would use setBufferedImage, but only there. The things that are changing (like the live waveform) you can paint then transparent on top. You can use the AudioThumbnail for live data as well (calling addBlock), or check out AudioVisualiserComponent.

Thanks for the fast answer daniel. My bad I didn’t specify: the waveforms are actually wavetable cycles instead of traditional waveforms, so I rolled my own painting method instead of AudioThumbnail because I stack them “3D-like” with depth. Also IIRC Jules said it’s painted usin drawVerticalLine like I did. A bit the same with AudioVisualiserComponent: more than a scrolling waveform I’m “painting the selected wave cycle” on the top of the full stack of waves, but using a separate child component and playing with setOpaque didn’t make much difference even when setBufferedImage on the background component (stack of waves) was true.

Can you elavorate about clipping in a Viewport? That’s new to me.

P.S: I can post the profiling and aprox. CPU usage of the four methods tested for the sake of it if it helps any other user here.

The AudioThumbnail has a RectangleList, that is created from a subsampled version. Instead of always iterating the whole file, it will check the clip rect, that the Graphics context has set, and will only iterate through that section:

Not sure, if that helps you though…

Thanks for the insight.

About the painting method I tried to use Drawables. The idea was good so far since they don’t use/trigger repaints on the other components, but the DrawablePath filling made it slow (if it was just a simple colored path that would have fixed it), DrawableRectangle wasn’t efficient (needed 256-512 rectangles) and DrawableImage was efficient but was just painting once.

So my solution if anyone is interested was to paint all the waveforms in an image on the parent, and take a flag inside paint() to decide wether it had to repaint and trace again the paths for the whole stack of waveforms (because a new one was introduced) or just repaint the already stored image, every time that the child component would call a repaint on parent. So now I can use paths to paint all the hundreds of cycles with a similar CPU usage of repainting them everytime with pixels.

Can you post a screenshot of what you’re trying to paint? In Waveform we draw dozens of audio thumbnails constantly as the user scroll around or the view follows the playhead…

Yes I expressed myself in a wrong way in the first post, by waveforms I always meant the painting of the wavetable cycles. Here it’s what I was trying to achieve. I already achieved it but have still to clean up a lot of code and make it neat, I can put a picture of the results once I’ve finished it.

edit: changing the title to avoid creating more confusions