changeset 1025:c02de0e34233 spectrogram-minor-refactor

Make paint method do its own timing and abandon if it's taking too long (still needs some work on queueing correct repaints of the remainder)
author Chris Cannam
date Mon, 25 Jan 2016 16:16:21 +0000
parents 3bce4c45b681
children 53110ace211f
files layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h
diffstat 2 files changed, 67 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Mon Jan 25 15:52:26 2016 +0000
+++ b/layer/SpectrogramLayer.cpp	Mon Jan 25 16:16:21 2016 +0000
@@ -33,7 +33,6 @@
 #include <QImage>
 #include <QPixmap>
 #include <QRect>
-#include <QTimer>
 #include <QApplication>
 #include <QMessageBox>
 #include <QMouseEvent>
@@ -49,9 +48,9 @@
 #include <alloca.h>
 #endif
 
-//#define DEBUG_SPECTROGRAM_REPAINT 1
-
-using std::vector;
+#define DEBUG_SPECTROGRAM_REPAINT 1
+
+using namespace std;
 
 SpectrogramLayer::SpectrogramLayer(Configuration config) :
     m_model(0),
@@ -78,7 +77,6 @@
     m_lastEmittedZoomStep(-1),
     m_synchronous(false),
     m_haveDetailedScale(false),
-    m_lastPaintBlockWidth(0),
     m_exiting(false),
     m_sliceableModel(0)
 {
@@ -1615,7 +1613,7 @@
 SpectrogramLayer::invalidateMagnitudes()
 {
     m_viewMags.clear();
-    for (std::vector<MagnitudeRange>::iterator i = m_columnMags.begin();
+    for (vector<MagnitudeRange>::iterator i = m_columnMags.begin();
          i != m_columnMags.end(); ++i) {
         *i = MagnitudeRange();
     }
@@ -1637,8 +1635,8 @@
         s10 = s11 = double(m_model->getEndFrame()) / getWindowIncrement();
     }
 
-    int s0 = int(std::min(s00, s10) + 0.0001);
-    int s1 = int(std::max(s01, s11) + 0.0001);
+    int s0 = int(min(s00, s10) + 0.0001);
+    int s1 = int(max(s01, s11) + 0.0001);
 
 //    SVDEBUG << "SpectrogramLayer::updateViewMagnitudes: x0 = " << x0 << ", x1 = " << x1 << ", s00 = " << s00 << ", s11 = " << s11 << " s0 = " << s0 << ", s1 = " << s1 << endl;
 
@@ -1730,13 +1728,6 @@
             cache.validArea = QRect();
         }
     }
-
-    if (cache.zoomLevel != zoomLevel) {
-        // no matter what we do with the cache, we'll need to
-        // recalculate our paint width again because each block will
-        // take a different time to render from previously
-        m_lastPaintBlockWidth = 0;
-    }
     
     if (cache.validArea.width() > 0) {
 
@@ -1875,40 +1866,6 @@
         x1 = v->getPaintWidth();
     }
 
-    auto mainPaintStart = std::chrono::steady_clock::now();
-
-    int paintBlockWidth = m_lastPaintBlockWidth;
-
-    if (m_synchronous) {
-        if (paintBlockWidth < x1 - x0) {
-            // always paint full width
-            paintBlockWidth = x1 - x0;
-        }
-    } else {
-        if (paintBlockWidth == 0) {
-            paintBlockWidth = (300000 / zoomLevel);
-        } else {
-            double lastTime = m_lastPaintTime;
-            while (lastTime > 0.2 &&
-                   paintBlockWidth > 30) {
-                paintBlockWidth /= 2;
-                lastTime = lastTime / 2;
-            }
-            while (lastTime < 0.09 &&
-                   paintBlockWidth < std::max(50, 1200000 / zoomLevel) &&
-                   paintBlockWidth < 1500) {
-                paintBlockWidth *= 2;
-                lastTime = lastTime * 2;
-            }
-        }
-        
-        if (paintBlockWidth < 20) paintBlockWidth = 20;
-    }
-
-//#ifdef DEBUG_SPECTROGRAM_REPAINT
-    cerr << "[" << this << "]: last paint width: " << m_lastPaintBlockWidth << ", last paint time: " << m_lastPaintTime << ", new paint width: " << paintBlockWidth << endl;
-//#endif
-
     // We always paint the full height when refreshing the cache.
     // Smaller heights can be used when painting direct from cache
     // (further up in this function), but we want to ensure the cache
@@ -1917,6 +1874,12 @@
 
     int h = v->getPaintHeight();
 
+    /*
+    auto mainPaintStart = chrono::steady_clock::now();
+
+    //!!! nb full-width case goes like
+                paintBlockWidth = x1 - x0;
+
     if (cache.validArea.width() > 0) {
 
         // If part of the cache is known to be valid, select a strip
@@ -1931,7 +1894,7 @@
         vx1 = cache.validArea.x() + cache.validArea.width();
         
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-        cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << ", paintBlockWidth " << paintBlockWidth << endl;
+        cerr << "x0 " << x0 << ", x1 " << x1 << ", vx0 " << vx0 << ", vx1 " << vx1 << endl;
 #endif         
         if (x0 < vx0) {
             if (x0 + paintBlockWidth < vx0) {
@@ -1969,11 +1932,13 @@
             }
         }
     }
-
+    */
+    
     int repaintWidth = x1 - x0;
 
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-    cerr << "x0 " << x0 << ", x1 " << x1 << ", w " << w << ", h " << h << endl;
+    cerr << "x0 " << x0 << ", x1 " << x1
+         << ", repaintWidth " << repaintWidth << ", h " << h << endl;
 #endif
 
     sv_samplerate_t sr = m_model->getSampleRate();
@@ -2163,7 +2128,12 @@
     }
 
     int failedToRepaint = bufwid - attainedBufwid;
-    if (failedToRepaint < 0) {
+    if (failedToRepaint > 0) {
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+        cerr << "Failed to repaint " << failedToRepaint << " of " << bufwid
+             << " columns in time" << endl;
+#endif
+    } else if (failedToRepaint < 0) {
         cerr << "WARNING: failedToRepaint < 0 (= " << failedToRepaint << ")"
              << endl;
         failedToRepaint = 0;
@@ -2241,34 +2211,32 @@
     // update cache valid area based on painted area
     if (cache.validArea.width() > 0) {
         
-        int left = std::min(cache.validArea.x(), x0);
-
-        int wid  = std::max(cache.validArea.x() + cache.validArea.width() - left,
-                            x1 - left);
-
+        int left = min(cache.validArea.x(), x0);
+
+        int wid = max(cache.validArea.x() + cache.validArea.width() - left,
+                      x1 - left);
         wid = wid - failedToRepaint;
         if (wid < 0) wid = 0;
         
         cache.validArea = QRect
             (left, cache.validArea.y(), wid, cache.validArea.height());
 
+    } else {
+
+        int wid = x1 - x0;
+        wid = wid - failedToRepaint;
+        if (wid < 0) wid = 0;
+        
+        cache.validArea = QRect(x0, 0, wid, h);
+    }
+
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-        cerr << "Valid area becomes " << cache.validArea.x()
-                  << ", " << cache.validArea.y() << ", "
-                  << cache.validArea.width() << "x"
-                  << cache.validArea.height() << endl;
+    cerr << "Cache valid area becomes " << cache.validArea.x()
+         << ", " << cache.validArea.y() << ", "
+         << cache.validArea.width() << "x"
+         << cache.validArea.height() << endl;
 #endif
 
-    } else {
-
-        cache.validArea = QRect(x0, 0, x1 - x0, h);
-
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-        cerr << "Valid area becomes " << x0 << ", 0, " << (x1-x0)
-                  << "x" << h << endl;
-#endif
-    }
-
     QRect pr = rect & cache.validArea;
 
 #ifdef DEBUG_SPECTROGRAM_REPAINT
@@ -2325,13 +2293,13 @@
 #ifdef DEBUG_SPECTROGRAM_REPAINT
     cerr << "SpectrogramLayer::paint() returning" << endl;
 #endif
-
+/*!!!
     if (!m_synchronous) {
-        auto mainPaintEnd = std::chrono::steady_clock::now();
+        auto mainPaintEnd = chrono::steady_clock::now();
         auto diff = mainPaintEnd - mainPaintStart;
-        m_lastPaintTime = std::chrono::duration<double>(diff).count();
-        m_lastPaintBlockWidth = paintBlockWidth;
+        m_lastPaintTime = chrono::duration<double>(diff).count();
     }
+*/
 }
 
 int
@@ -2465,6 +2433,13 @@
 {
     Profiler profiler("SpectrogramLayer::paintDrawBuffer");
 
+    //!!! todo: propagate to paintDrawBufferPeakFrequencies
+
+    int minColumns = 4;
+    double maxTime = 0.1; // seconds; only for non-synchronous drawing
+
+    auto startTime = chrono::steady_clock::now();
+    
     int minbin = int(binfory[0] + 0.0001);
     int maxbin = int(binfory[h-1]);
 
@@ -2684,6 +2659,20 @@
 
             m_drawBuffer.setPixel(x, h-y-1, peakpix);
         }
+
+        if (!m_synchronous) {
+            if (x >= minColumns) {
+                auto t = chrono::steady_clock::now();
+                double diff = chrono::duration<double>(t - startTime).count();
+                if (diff > maxTime) {
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+                    cerr << "Max time " << maxTime << " sec exceeded after "
+                         << x << " columns with time " << diff << endl;
+#endif
+                    return x;
+                }
+            }
+        }
     }
 
     return w;
@@ -2881,7 +2870,7 @@
 bool
 SpectrogramLayer::getCrosshairExtents(LayerGeometryProvider *v, QPainter &paint,
                                       QPoint cursorPos,
-                                      std::vector<QRect> &extents) const
+                                      vector<QRect> &extents) const
 {
     QRect vertical(cursorPos.x() - 12, 0, 12, v->getPaintHeight());
     extents.push_back(vertical);
@@ -3281,7 +3270,7 @@
 	paint.drawLine(cw + 7, h - vy, w - pkw - 1, h - vy);
 
 	if (h - vy - textHeight >= -2) {
-	    int tx = w - 3 - paint.fontMetrics().width(text) - std::max(tickw, pkw);
+	    int tx = w - 3 - paint.fontMetrics().width(text) - max(tickw, pkw);
 	    paint.drawText(tx, h - vy + toff, text);
 	}
 
--- a/layer/SpectrogramLayer.h	Mon Jan 25 15:52:26 2016 +0000
+++ b/layer/SpectrogramLayer.h	Mon Jan 25 16:16:21 2016 +0000
@@ -274,8 +274,6 @@
     bool                m_synchronous;
 
     mutable bool        m_haveDetailedScale;
-    mutable int         m_lastPaintBlockWidth;
-    mutable double      m_lastPaintTime; // seconds
 
     enum { NO_VALUE = 0 }; // colour index for unused pixels