changeset 382:06b5f110c5d2

* Speed up spectrogram painting by releasing mutex in FFTDataServer while calculating data prior to writing it, and by adding whole-column value query methods to FFT objects * Add paint cache to Thumbwheel -- repaints of this widget were slowing down the whole spectrogram repaint * More uses of MutexLocker (named and with debug) and more profile points * Make startup much quicker some of the time, with OSC server in place
author Chris Cannam
date Thu, 08 May 2008 14:46:22 +0000
parents a6408c382616
children b35184d0dfe5
files layer/SpectrogramLayer.cpp view/Pane.cpp view/View.cpp widgets/AudioDial.cpp widgets/Thumbwheel.cpp widgets/Thumbwheel.h
diffstat 6 files changed, 102 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Tue Apr 29 11:07:14 2008 +0000
+++ b/layer/SpectrogramLayer.cpp	Thu May 08 14:46:22 2008 +0000
@@ -1239,6 +1239,8 @@
 bool
 SpectrogramLayer::getYBinRange(View *v, int y, float &q0, float &q1) const
 {
+    Profiler profiler("SpectrogramLayer::getYBinRange");
+    
     int h = v->height();
     if (y < 0 || y >= h) return false;
 
@@ -1555,7 +1557,7 @@
                                        m_windowSize,
                                        getWindowIncrement(),
                                        fftSize,
-                                       true,
+                                       true, // polar
                                        StorageAdviser::SpeedCritical,
                                        m_candidateFillStartFrame);
 
@@ -2036,7 +2038,9 @@
 
     float ymag[h];
     float ydiv[h];
-    float yval[maxbin + 1]; //!!! cache this?
+
+    float yval[maxbin - minbin + 1];
+    float values[maxbin - minbin + 1];
 
     size_t increment = getWindowIncrement();
     
@@ -2044,9 +2048,9 @@
 
     for (size_t q = minbin; q <= maxbin; ++q) {
         float f0 = (float(q) * sr) / fftSize;
-        yval[q] = v->getYForFrequency(f0, displayMinFreq, displayMaxFreq,
-                                      logarithmic);
-//        std::cerr << "min: " << minFreq << ", max: " << maxFreq << ", yval[" << q << "]: " << yval[q] << std::endl;
+        yval[q - minbin] =
+            v->getYForFrequency(f0, displayMinFreq, displayMaxFreq,
+                                logarithmic);
     }
 
     MagnitudeRange overallMag = m_viewMags[v];
@@ -2079,8 +2083,13 @@
     size_t pixels = 0;
 #endif
 
+    Profiler outerprof("SpectrogramLayer::paint: all cols");
+    FFTModel::PeakSet peaks;
+
     for (int x = 0; x < w; ++x) {
 
+        Profiler innerprof("SpectrogramLayer::paint: 1 pixel column");
+
         if (runOutOfData) {
 #ifdef DEBUG_SPECTROGRAM_REPAINT
             std::cerr << "Run out of data -- dropping out of loop" << std::endl;
@@ -2133,20 +2142,34 @@
                 fftSuspended = true;
             }
 
+            Profiler innerprof2("SpectrogramLayer::paint: 1 data column");
+
             MagnitudeRange mag;
 
-            FFTModel::PeakSet peaks;
-            if (m_binDisplay == PeakFrequencies &&
-                s < int(fft->getWidth()) - 1) {
-                peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
-                                                s,
-                                                minbin, maxbin - 1);
+            if (m_binDisplay == PeakFrequencies) {
+                if (s < int(fft->getWidth()) - 1) {
+                    peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
+                                                    s,
+                                                    minbin, maxbin - 1);
+                } else {
+                    peaks.clear();
+                }
             }
+                
+            if (m_colourScale == PhaseColourScale) {
+                fft->getPhasesAt(s, values, minbin, maxbin - minbin + 1);
+            } else if (m_normalizeColumns) {
+                fft->getNormalizedMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
+            } else {
+                fft->getMagnitudesAt(s, values, minbin, maxbin - minbin + 1);
+            }
 
             for (size_t q = minbin; q < maxbin; ++q) {
 
-                float y0 = yval[q + 1];
-                float y1 = yval[q];
+                Profiler innerprof3("SpectrogramLayer::paint: 1 bin");
+
+                float y0 = yval[q + 1 - minbin];
+                float y1 = yval[q - minbin];
 
 		if (m_binDisplay == PeakBins) {
 		    if (!fft->isLocalPeak(s, q)) continue;
@@ -2160,7 +2183,7 @@
                     continue;
                 }
 
-		float sprop = 1.0;
+		float sprop = 1.f;
 		if (s == s0i) sprop *= (s + 1) - s0;
 		if (s == s1i) sprop *= s1 - s;
  
@@ -2169,11 +2192,24 @@
 			(peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
 		}
 		
-		int y0i = int(y0 + 0.001);
+		int y0i = int(y0 + 0.001f);
 		int y1i = int(y1);
 
-                float value;
+                float value = values[q - minbin];
+
+                if (m_colourScale != PhaseColourScale) {
+                    if (!m_normalizeColumns) {
+                        value /= (m_fftSize/2.f);
+                    }
+                    mag.sample(value);
+                    value *= m_gain;
+                }
+
+                float v2 = value;
+
+//!!!
                 
+                value = 0.f;
                 if (m_colourScale == PhaseColourScale) {
                     value = fft->getPhaseAt(s, q);
                 } else if (m_normalizeColumns) {
@@ -2186,10 +2222,14 @@
                     value *= m_gain;
                 }
 
+                if (value != v2) {
+                    std::cout << "old = " << value << " new = " << v2 << " at y = " << q << std::endl;
+                }
+
                 if (interpolate) {
                     
                     int ypi = y0i;
-                    if (q < maxbin - 1) ypi = int(yval[q + 2]);
+                    if (q < maxbin - 1) ypi = int(yval[q + 2 - minbin]);
 
                     for (int y = ypi; y <= y1i; ++y) {
                     
@@ -2200,7 +2240,7 @@
 
                         if (ypi < y0i && y <= y0i) {
 
-                            float half = float(y0i - ypi) / 2;
+                            float half = float(y0i - ypi) / 2.f;
                             float dist = y - (ypi + half);
 
                             if (dist >= 0) {
@@ -2210,7 +2250,7 @@
                         } else {
                             if (y1i > y0i) {
 
-                                float half = float(y1i - y0i) / 2;
+                                float half = float(y1i - y0i) / 2.f;
                                 float dist = y - (y0i + half);
                                 
                                 if (dist >= 0) {
@@ -2238,7 +2278,7 @@
                             if (y < 0 || y >= h) continue;
 
                             float yprop = sprop;
-                            if (y == y0i) yprop *= (y + 1) - y0;
+                            if (y == y0i) yprop *= (y + 1.f) - y0;
                             if (y == y1i) yprop *= y1 - y;
                             ymag[y] += yprop * value;
                             ydiv[y] += yprop;
@@ -2266,6 +2306,8 @@
             }
 	}
 
+        Profiler drawbufferprof("SpectrogramLayer::paint: set buffer pixels");
+
 	for (int y = 0; y < h; ++y) {
 
 	    if (ydiv[y] > 0.0) {
@@ -2301,7 +2343,9 @@
 #endif
     }
 
-    Profiler profiler2("SpectrogramLayer::paint: draw image", true);
+    outerprof.end();
+
+    Profiler profiler2("SpectrogramLayer::paint: draw image");
 
     if (recreateWholePixmapCache) {
         std::cerr << "Recreating pixmap cache: width = " << v->width()
@@ -2384,6 +2428,8 @@
 void
 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const
 {
+    Profiler profiler("SpectrogramLayer::illuminateLocalFeatures");
+
     QPoint localPos;
     if (!v->shouldIlluminateLocalFeatures(this, localPos) || !m_model) {
         return;
@@ -2823,7 +2869,7 @@
 	return;
     }
 
-    Profiler profiler("SpectrogramLayer::paintVerticalScale", true);
+    Profiler profiler("SpectrogramLayer::paintVerticalScale");
 
     //!!! cache this?
 
--- a/view/Pane.cpp	Tue Apr 29 11:07:14 2008 +0000
+++ b/view/Pane.cpp	Thu May 08 14:46:22 2008 +0000
@@ -87,7 +87,7 @@
 void
 Pane::updateHeadsUpDisplay()
 {
-    Profiler profiler("Pane::updateHeadsUpDisplay", true);
+    Profiler profiler("Pane::updateHeadsUpDisplay");
 
     if (!isVisible()) return;
 
--- a/view/View.cpp	Tue Apr 29 11:07:14 2008 +0000
+++ b/view/View.cpp	Thu May 08 14:46:22 2008 +0000
@@ -368,6 +368,8 @@
 		       float maxf, 
 		       bool logarithmic) const
 {
+    Profiler profiler("View::getYForFrequency");
+
     int h = height();
 
     if (logarithmic) {
@@ -1401,7 +1403,7 @@
 
 	    } else {
 
-		i->second->setText(text);
+//		i->second->setText(text);
 
 		i->second->setValue(completion);
 		i->second->move(0, ph - i->second->height());
--- a/widgets/AudioDial.cpp	Tue Apr 29 11:07:14 2008 +0000
+++ b/widgets/AudioDial.cpp	Thu May 08 14:46:22 2008 +0000
@@ -50,6 +50,8 @@
 #include <QPaintEvent>
 #include <QInputDialog>
 
+#include "base/Profiler.h"
+
 using std::endl;
 using std::cerr;
 
@@ -115,6 +117,8 @@
 
 void AudioDial::paintEvent(QPaintEvent *)
 {
+    Profiler profiler("AudioDial::paintEvent");
+
     QPainter paint;
 
     float angle = AUDIO_DIAL_MIN // offset
--- a/widgets/Thumbwheel.cpp	Tue Apr 29 11:07:14 2008 +0000
+++ b/widgets/Thumbwheel.cpp	Thu May 08 14:46:22 2008 +0000
@@ -129,6 +129,7 @@
     if (m_atDefault) {
         setValue(m_default);
         m_atDefault = true; // setValue unsets this
+        m_cache = QImage();
         emit valueChanged(getValue());
     }
 }
@@ -145,6 +146,7 @@
         if (newValue != getValue()) {
             setValue(newValue);
             changed = true;
+            m_cache = QImage();
         }
         if (changed) emit valueChanged(newValue);
         m_noMappedUpdate = false;
@@ -152,6 +154,7 @@
         int v = int(mappedValue);
         if (v != getValue()) {
             setValue(v);
+            m_cache = QImage();
             emit valueChanged(v);
         }
     }
@@ -179,6 +182,7 @@
     }
 
     m_rotation = float(m_value - m_min) / float(m_max - m_min);
+    m_cache = QImage();
     if (isVisible()) update();
 }
 
@@ -188,6 +192,7 @@
     if (m_default == m_value) return;
     setValue(m_default);
     m_atDefault = true;
+    m_cache = QImage();
     emit valueChanged(getValue());
 }
 
@@ -436,7 +441,18 @@
 void
 Thumbwheel::paintEvent(QPaintEvent *)
 {
-    Profiler profiler("Thumbwheel::paintEvent", true);
+    Profiler profiler("Thumbwheel::paintEvent");
+
+    if (!m_cache.isNull()) {
+        QPainter paint(this);
+        paint.drawImage(0, 0, m_cache);
+        return;
+    }
+
+    Profiler profiler2("Thumbwheel::paintEvent (no cache)");
+
+    m_cache = QImage(size(), QImage::Format_ARGB32);
+    m_cache.fill(Qt::transparent);
 
     int bw = 3;
 
@@ -447,7 +463,8 @@
         subclip = QRect(bw+1, bw, width() - bw*2 - 2, height() - bw*2);
     }
 
-    QPainter paint(this);
+    QPainter paint(&m_cache);
+    paint.setClipRect(rect());
     paint.fillRect(subclip, palette().background().color());
 
     paint.setRenderHint(QPainter::Antialiasing, true);
@@ -563,6 +580,9 @@
             paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
         }
     }
+
+    QPainter paint2(this);
+    paint2.drawImage(0, 0, m_cache);
 }
 
 QSize
--- a/widgets/Thumbwheel.h	Tue Apr 29 11:07:14 2008 +0000
+++ b/widgets/Thumbwheel.h	Thu May 08 14:46:22 2008 +0000
@@ -17,6 +17,9 @@
 #define _THUMBWHEEL_H_
 
 #include <QWidget>
+#include <QImage>
+
+#include <map>
 
 class RangeMapper;
 
@@ -92,6 +95,7 @@
     float m_clickRotation;
     bool m_showTooltip;
     RangeMapper *m_rangeMapper;
+    QImage m_cache;
 };
 
 #endif