drowe67 / freedv-gui

GUI Application for FreeDV – open source digital voice for HF radio
https://freedv.org/
GNU Lesser General Public License v2.1
210 stars 52 forks source link

Waterfall update speed slows significantly with multiple panes visible #148

Closed tmiw closed 1 year ago

tmiw commented 3 years ago

Per digitalvoice list:

Thanks for all your work bur unfortunately the scatter plot is not visible on my windows10 box.

Another interesting thing I noticed is that if the waterfall display is the only active pane then it takes approx 30 seconds for waterfall to scroll down ie the time scale is accurate. However with multiple panes ((spectrum at top and waterfall at bottom) it now takes 60 second for waterfall to go from top to bottom. There is a waterfall speed issue as the size of the window is resized. This is not a serious issue.

Thoughts on what could be happening?

drowe67 commented 3 years ago

Hi @tmiw - hmm that's an interesting one. The multiple pane stuff has always been kind of opaque, something internal to wxWIdgets. For example we have never worked out how to save/restore the multiple pane state.

Perhaps some insight could be gained by dumping a few variables (like the X and Y window size) as it's resized, and see how that affects the algorithm that drives the update rate.

tmiw commented 3 years ago

MainFrame::OnTimer() is what triggers the adding of data points (if needed) and the repainting of each of the panes (regardless of whether they're displayed). I think wxWidgets suppresses the Refresh() calls for the panes that aren't visible, though, or at least doesn't trigger the actual painting to the screen until they do become visible. OnTimer() seems to be set to be called every 100ms (governed by _REFRESH_TIMER_PERIOD, defined as DT*1000 where DT == 0.1), which means that one of the panes visible in OP is potentially taking significantly longer than that to redraw.

Alternatively, it's possible that this block is simply not executing:

    if (m_panelWaterfall->checkDT()) {
        m_panelWaterfall->setRxFreq(FDMDV_FCENTRE - g_RxFreqOffsetHz);
        m_panelWaterfall->m_newdata = true;
        m_panelWaterfall->setColor(wxGetApp().m_waterfallColor);
        m_panelWaterfall->Refresh();
    }

checkDT() is defined as follows:

bool PlotWaterfall::checkDT(void)
{
    // Check dY is > 1 pixel before proceeding. For small screens
    // and large WATERFALL_SECS_Y we might have less than one
    // block per pixel.  In this case increase m_dT and perform draw
    // less often

    float px_per_sec = (float)m_rGrid.GetHeight() / WATERFALL_SECS_Y;
    float dy = m_dT * px_per_sec;

    if (dy < 1.0) {
        m_dT += DT;
        return false;
    }
    else
        return true;
}

although at first glance this should still be causing it to take ~30 seconds to fully refresh the waterfall.

tmiw commented 1 year ago

I made some improvements in #487 that should help with this. Turns out that we should have a fixed number of pixels/second (instead of a fixed number of seconds and calculating the pixels/second from the height); doing it the latter causes some weirdness with fractional pixel positions.

(For example, on my machine, the waterfall's height was something like 850 pixels, resulting in a dy of ~2.85 pixels--despite only having the waterfall displayed. With the behavior in master, that means that the waterfall reaches around the 20 second mark after 30 seconds of audio playback. If I use ceil(2.85) = 3 pixels for dy, we end up having the opposite problem--we scroll off the screen way before 30 seconds are up.)

Anyway, with the current state of that PR, 30 seconds of audio scrolls the waterfall by 30 seconds as expected. Additionally, you can get even more waterfall history if you have a large enough monitor by making it taller :) As I haven't heard any other issues with having multiple visible panes recently, I'll go ahead and close this issue.