Add Oscilloscope Effect
This PR adds an effect to visually show the incoming waveform. This is similar to the oscilloscope at the top tool bar, but it has many more features, including pausing the display, scaling the amplitude, zooming in certain sections, and viewing the stereo waveform.
The audio processing portion simply saves the incoming buffer into a ring buffer. Most of the code is for the gui, which includes a zoomable+scrollable waveform graph to display the contents of the ring buffer.
This PR does NOT include a pitch tracking option to lock on to one period of the waveform. Perhaps that can be implemented in the future.
Demo
https://github.com/user-attachments/assets/34f36e90-713d-455b-91de-8f728df0c045
@regulus79 is the orientation okay now?
You can test with either:
- a BitInvader drawn to make a
y=1or - by going to Xpressive and setting the formula for O1 and O2 to
1, literally
In any case, you can notice the horizontal flip.
Have we agreed on the maximum frame buffer size? 3 seconds sounds okay to me, upon further consideration. I think it's enough for everything.
The orientation should be fixed now!
I also tried to implement Lost Robot's suggestion to find the min/max sample values for all the samples per pixel and draw a line connecting them. It works much better, so now having a 10 second window length is actually feasible.
However, it still requires looping over the whole visible buffer each frame, so when you have it at these super long window sizes, your cpu goes up quite a bit. Not the lmms cpu meter, that's fine, but the real cpu usage by lmms causes my fans to start lol. I suppose ideally at these super large buffer sizes, we would switch to using a pixmap approach, or at least caching the min/max pixel values.
But if you think 3 seconds is fine, then maybe it would be simpler to keep the current setup and just limit the window to 3 seconds?
My sources are setting a three-second timer and going "Yeah, that's long enough!" :rofl:
I should cover most crashes, snares, etc, but we'll see from more testing. For now, three seconds is okay. Once that buffer size is set, I'll get to testing.
Should be ready to test!
@rubiefawn @regulus79 Have the mentioned changes been made? Can I test again?
Yes, I've changed the max buffer size to 3 seconds and I committed @rubiefawn's code simplification (thanks!).
However, I didn't want to take the time to recompile everything, so I haven't tested it to see if it actually still works. But given that the builds are still working, I think it's probably fine.
This is great! I'd love to learn more about "Scale" and will approve after that.
Haven't looked, but if you copied the code from the Oscilloscope we already have, maybe we can reuse some of it.
if you copied the code from the Oscilloscope we already have, maybe we can reuse some of it.
I didn't copy anything from the current Oscilloscope in this PR.
Hey, uh, I have a Recommendation: Maybe we can add a Theme Editor next to the "Stereo" toggle button, to change the white line to other colors, what Y'all think about it?
Probably would be easy to turn the RGBA values into variables, so that each color wouldn't be locked to a specific preset.
I barely know about Qt CSS, but I'm always here to help wih anything! :D
I made an effort to make sure all the colors are themeable, so normal themes which customize the style.css should be able to change the colors just fine. They are not hardcoded to a specific preset.
Changing the color of the waveform right there in the plugin is interesting--It's probably not too hard to implement, but that would also bring up the question of whether all the other plugins such as the equalizer and spectrum analyzer should be customizable right in the app. It would be cool to have an in-app theme editor someday, but that may be a difficult task.
Also now that we are bringing up the stereo color, I do apologize--the way I'm drawing the waveforms means I do the left channel first, then the right (or the other way I forgot), which means when the two channels overlap, the channel drawn last looks brighter. I'm still thinking if there's an easy way to fix it without like changing the pen color multiple times per line. I'm not sure, but it's probably not too big a deal.
Changing the color of the waveform right there in the plugin is interesting
One way to put it! :laughing:
the way I'm drawing the waveforms means I do the left channel first, then the right (or the other way I forgot), which means when the two channels overlap, the channel drawn last looks brighter.
I'm sure Qt has an additive blend mode (QPainter::CompositionMode_Plus?)
I'm sure Qt has an additive blend mode (QPainter::CompositionMode_Plus?)
Oh thanks, I tried that and now it seems to look much better!
... which includes a zoomable+scrollable waveform graph...
I just noticed that in the code! That's so cool! So you can pause, zoom with the mouse wheel and move around with the mouse click and drag. Amazing stuff!
I just noticed that in the code! That's so cool! So you can pause, zoom with the mouse wheel and move around with the mouse click and drag. Amazing stuff!
Oh no, if you only found out about it by looking at the code, then will most users not realize it exists? /hj
Oh no, if you only found out about it by looking at the code, then will most users not realize it exists? /hj
The plugin is immeasurably useful even if you don't know about that, and people who need to pause and look at the waveform would figure it out, I think!
~~Asking about this line again, LOL! @regulus79, could you talk me through https://github.com/LMMS/lmms/pull/7937/commits/57f07b7f21c9b3cb88ddcf8cad1f1771f27b91d1?~~ Found it!
Does the removal of the GATE knob done by @messmerd affect that in any way?
Does the removal of the GATE knob done by @messmerd affect that in any way?
The gate knob should only affect effects which use ContinueIfNoteQuiet(I think), so now that I've changed it to Continue, it shouldn't depend on the gate knob.
Did a quick test of the PR, discovered by holding down the left mouse and dragging over the window causing changes in the Offset knob? Other than that great job, it works well for the most part. Another thing I wanted to mention: Should the gray sidebar be gray? I think for most of our plugins that have displays the background is a bit darker.
Did a quick test of the PR, discovered by holding down the left mouse and dragging over the window causing changes in the Offset knob?
Edit: Ohh it seems intentional.
Another thing I wanted to mention: Should the gray sidebar be gray? I think for most of our plugins that have displays the background is a bit darker.
Edit 2: Wait.. just checked with Vectorscope, I guess it doesn't follow that convention. It should be fine then if you don't have a problem with it.
Edit 3: I also think the stereo is really harder to see compared to mono.
Shouldn't the waveform appear from the right edge of the oscilloscope? (and disappear at the left edge)
Shouldn't the waveform appear from the right edge of the oscilloscope? (and disappear at the left edge)
Ideally yes. Since the possible view offset changes with the zoom value, it's difficult to make that work with different zoom levels. Depending on how zoomed in you are, the possible movement of the view gets more/less limited. When all the way zoomed out, technically no horizontal movement of the view should be possible. Ideally the offset knob would change its min/max values accordingly to prevent you from scrolling all the way around (like going over the international date line on a map haha).
Unfortunately, LMMS does not currently allow you to change the min/max values of a FloatModel. Either that would have to be added, or I would have to change the maths to work around the fixed min/max values of the knob.
Shouldn't the waveform appear from the right edge of the oscilloscope? (and disappear at the left edge)
In this case, no. You've moved the offset, so the start position is offset. Usually, you won't be touching that knob manually.
Apart from a few extra whitespaces (I think they're extra, at least, but they might be part of the convention), this looks okay to me. @messmerd can we merge?
I believe the reason we haven't merged this yet is because I haven't yet made it thread-safe via using a LocklessRingBuffer to communicate between the audio thread and the gui. I attempted to do so maybe a week ago by following how SpectrumAnalyzer and Vectorscope do it, but I ran into issues where reading from the buffer did not free up space in it, which meant the buffer would fill up and stop working.