changeset 477:92f4d88241b8

* some preparatory reorganisation
author Chris Cannam
date Tue, 03 Feb 2009 11:19:39 +0000
parents 2613bc1b2823
children 0990b95140e3
files layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/layer.pro
diffstat 3 files changed, 283 insertions(+), 225 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Mon Feb 02 17:07:47 2009 +0000
+++ b/layer/SpectrogramLayer.cpp	Tue Feb 03 11:19:39 2009 +0000
@@ -42,7 +42,7 @@
 #include <cassert>
 #include <cmath>
 
-//#define DEBUG_SPECTROGRAM_REPAINT 1
+#define DEBUG_SPECTROGRAM_REPAINT 1
 
 SpectrogramLayer::SpectrogramLayer(Configuration config) :
     m_model(0),
@@ -1781,7 +1781,9 @@
     PixmapCache &cache = m_pixmapCaches[v];
 
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-    std::cerr << "SpectrogramLayer::paint(): pixmap cache valid area " << cache.validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl;
+    std::cerr << "SpectrogramLayer::paint(): pixmap cache valid area " << cache.
+
+validArea.x() << ", " << cache.validArea.y() << ", " << cache.validArea.width() << "x" << cache.validArea.height() << std::endl;
 #endif
 
 #ifdef DEBUG_SPECTROGRAM_REPAINT
@@ -2114,11 +2116,8 @@
 
 //    std::cerr << "(giving actual minFreq " << minFreq << " and display minFreq " << displayMinFreq << ")" << std::endl;
 
-    float ymag[h];
-    float ydiv[h];
-
-    float yval[maxbin - minbin + 1];
-    float values[maxbin - minbin + 1];
+    float yforbin[maxbin - minbin + 1];
+    float yval[h];
 
     size_t increment = getWindowIncrement();
     
@@ -2126,7 +2125,7 @@
 
     for (size_t q = minbin; q <= maxbin; ++q) {
         float f0 = (float(q) * sr) / fftSize;
-        yval[q - minbin] =
+        yforbin[q - minbin] =
             v->getYForFrequency(f0, displayMinFreq, displayMaxFreq,
                                 logarithmic);
     }
@@ -2136,17 +2135,6 @@
 
     bool fftSuspended = false;
 
-    bool interpolate = false;
-    Preferences::SpectrogramSmoothing smoothing = 
-        Preferences::getInstance()->getSpectrogramSmoothing();
-    if (smoothing == Preferences::SpectrogramInterpolated ||
-        smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) {
-        if (m_binDisplay != PeakBins &&
-            m_binDisplay != PeakFrequencies) {
-            interpolate = true;
-        }
-    }
-
 #ifdef DEBUG_SPECTROGRAM_REPAINT
     std::cerr << ((float(v->getFrameForX(1) - v->getFrameForX(0))) / increment) << " bin(s) per pixel" << std::endl;
 #endif
@@ -2162,12 +2150,16 @@
 #endif
 
     Profiler outerprof("SpectrogramLayer::paint: all cols");
-    FFTModel::PeakSet peaks;
 
     for (int x = 0; x < w; ++x) {
 
         Profiler innerprof("SpectrogramLayer::paint: 1 pixel column");
 
+        runOutOfData = !getColumnValues(v, fft, x0, x,
+                                        minbin, maxbin,
+                                        displayMinFreq, displayMaxFreq,
+                                        h, yforbin, yval);
+
         if (runOutOfData) {
 #ifdef DEBUG_SPECTROGRAM_REPAINT
             std::cerr << "Run out of data -- dropping out of loop" << std::endl;
@@ -2175,214 +2167,21 @@
             break;
         }
 
+        Profiler drawbufferprof("SpectrogramLayer::paint: set buffer pixels");
+
 	for (int y = 0; y < h; ++y) {
-	    ymag[y] = 0.f;
-	    ydiv[y] = 0.f;
-	}
-
-	float s0 = 0, s1 = 0;
-
-	if (!getXBinRange(v, x0 + x, s0, s1)) {
+
+            unsigned char pixel = 0;
+
+            pixel = getDisplayValue(v, yval[y]);
+
+            assert(x <= m_drawBuffer.width());
+            QColor c = m_palette.getColour(pixel);
+            m_drawBuffer.setPixel(x, y,
+                                  qRgb(c.red(), c.green(), c.blue()));
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-            std::cerr << "Out of range at " << x0 + x << std::endl;
+            ++pixels;
 #endif
-	    assert(x <= m_drawBuffer.width());
-	    continue;
-	}
-
-	int s0i = int(s0 + 0.001);
-	int s1i = int(s1);
-
-	if (s1i >= int(fft->getWidth())) {
-	    if (s0i >= int(fft->getWidth())) {
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-                std::cerr << "Column " << s0i << " out of range" << std::endl;
-#endif
-		continue;
-	    } else {
-		s1i = s0i;
-	    }
-	}
-
-        for (int s = s0i; s <= s1i; ++s) {
-
-            if (!m_synchronous) {
-                if (!fft->isColumnAvailable(s)) {
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-                    std::cerr << "Met unavailable column at col " << s << std::endl;
-#endif
-                    runOutOfData = true;
-                    break;
-                }
-            }
-/*!!!            
-            if (!fftSuspended) {
-                fft->suspendWrites();
-                fftSuspended = true;
-            }
-*/
-            Profiler innerprof2("SpectrogramLayer::paint: 1 data column");
-
-            MagnitudeRange mag;
-
-            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) {
-
-                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;
-		}
-                if (m_binDisplay == PeakFrequencies) {
-                    if (peaks.find(q) == peaks.end()) continue;
-                }
-
-                if (m_threshold != 0.f &&
-                    !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
-                    continue;
-                }
-
-		float sprop = 1.f;
-		if (s == s0i) sprop *= (s + 1) - s0;
-		if (s == s1i) sprop *= s1 - s;
- 
-		if (m_binDisplay == PeakFrequencies) {
-		    y0 = y1 = v->getYForFrequency
-			(peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
-		}
-		
-		int y0i = int(y0 + 0.001f);
-		int y1i = int(y1);
-
-                float value = values[q - minbin];
-
-                if (m_colourScale != PhaseColourScale) {
-                    if (!m_normalizeColumns) {
-                        value /= (m_fftSize/2.f);
-                    }
-                    mag.sample(value);
-                    value *= m_gain;
-                }
-
-                if (interpolate) {
-                    
-                    int ypi = y0i;
-                    if (q < maxbin - 1) ypi = int(yval[q + 2 - minbin]);
-
-                    for (int y = ypi; y <= y1i; ++y) {
-                    
-                        if (y < 0 || y >= h) continue;
-                    
-                        float yprop = sprop;
-                        float iprop = yprop;
-
-                        if (ypi < y0i && y <= y0i) {
-
-                            float half = float(y0i - ypi) / 2.f;
-                            float dist = y - (ypi + half);
-
-                            if (dist >= 0) {
-                                iprop = (iprop * dist) / half;
-                                ymag[y] += iprop * value;
-                            }
-                        } else {
-                            if (y1i > y0i) {
-
-                                float half = float(y1i - y0i) / 2.f;
-                                float dist = y - (y0i + half);
-                                
-                                if (dist >= 0) {
-                                    iprop = (iprop * (half - dist)) / half;
-                                }
-                            }
-
-                            ymag[y] += iprop * value;
-                            ydiv[y] += yprop;
-                        }
-                    }
-
-                } else {
-
-                    for (int y = y0i; y <= y1i; ++y) {
-                    
-                        if (y < 0 || y >= h) continue;
-                    
-                        float yprop = sprop;
-                        if (y == y0i) yprop *= (y + 1) - y0;
-                        if (y == y1i) yprop *= y1 - y;
-
-                        for (int y = y0i; y <= y1i; ++y) {
-		    
-                            if (y < 0 || y >= h) continue;
-
-                            float yprop = sprop;
-                            if (y == y0i) yprop *= (y + 1.f) - y0;
-                            if (y == y1i) yprop *= y1 - y;
-                            ymag[y] += yprop * value;
-                            ydiv[y] += yprop;
-                        }
-                    }
-                }
-	    }
-
-            if (mag.isSet()) {
-
-                if (s >= int(m_columnMags.size())) {
-                    std::cerr << "INTERNAL ERROR: " << s << " >= "
-                              << m_columnMags.size() << " at SpectrogramLayer.cpp:2087" << std::endl;
-                }
-
-                m_columnMags[s].sample(mag);
-
-                if (overallMag.sample(mag)) {
-                    //!!! scaling would change here
-                    overallMagChanged = true;
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-                    std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl;
-#endif
-                }
-            }
-	}
-
-        Profiler drawbufferprof("SpectrogramLayer::paint: set buffer pixels");
-
-	for (int y = 0; y < h; ++y) {
-
-	    if (ydiv[y] > 0.0) {
-
-		unsigned char pixel = 0;
-
-		float avg = ymag[y] / ydiv[y];
-		pixel = getDisplayValue(v, avg);
-
-		assert(x <= m_drawBuffer.width());
-		QColor c = m_palette.getColour(pixel);
-		m_drawBuffer.setPixel(x, y,
-                                      qRgb(c.red(), c.green(), c.blue()));
-#ifdef DEBUG_SPECTROGRAM_REPAINT
-                ++pixels;
-#endif
-	    }
 	}
     }
 
@@ -2490,6 +2289,241 @@
 //!!!    if (fftSuspended) fft->resume();
 }
 
+
+bool
+SpectrogramLayer::getColumnValues(View *v, 
+                                  FFTModel *fft,
+                                  int x0,
+                                  int x,
+                                  int minbin,
+                                  int maxbin,
+                                  float displayMinFreq,
+                                  float displayMaxFreq,
+                                  const int h,
+                                  const float *yforbin,
+                                  float *yval) const
+{
+    float ymag[h];
+    float ydiv[h];
+    float values[maxbin - minbin + 1];
+
+    bool logarithmic = (m_frequencyScale == LogFrequencyScale);
+
+    bool interpolate = false;
+    Preferences::SpectrogramSmoothing smoothing = 
+        Preferences::getInstance()->getSpectrogramSmoothing();
+    if (smoothing == Preferences::SpectrogramInterpolated ||
+        smoothing == Preferences::SpectrogramZeroPaddedAndInterpolated) {
+        if (m_binDisplay != PeakBins &&
+            m_binDisplay != PeakFrequencies) {
+            interpolate = true;
+        }
+    }
+
+    for (int y = 0; y < h; ++y) {
+        ymag[y] = 0.f;
+        ydiv[y] = 0.f;
+    }
+
+    float s0 = 0, s1 = 0;
+
+    if (!getXBinRange(v, x0 + x, s0, s1)) {
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+        std::cerr << "Out of range at " << x0 + x << std::endl;
+#endif
+        assert(x <= m_drawBuffer.width());
+        return false;
+    }
+
+    int s0i = int(s0 + 0.001);
+    int s1i = int(s1);
+
+    if (s1i >= int(fft->getWidth())) {
+        if (s0i >= int(fft->getWidth())) {
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+            std::cerr << "Column " << s0i << " out of range" << std::endl;
+#endif
+            return false;
+        } else {
+            s1i = s0i;
+        }
+    }
+
+    FFTModel::PeakSet peaks;
+
+    for (int s = s0i; s <= s1i; ++s) {
+
+        if (!m_synchronous) {
+            if (!fft->isColumnAvailable(s)) {
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+                std::cerr << "Met unavailable column at col " << s << std::endl;
+#endif
+                return false;
+            }
+        }
+/*!!!            
+            if (!fftSuspended) {
+                fft->suspendWrites();
+                fftSuspended = true;
+            }
+*/
+        Profiler innerprof2("SpectrogramLayer::paint: 1 data column");
+
+        MagnitudeRange mag;
+
+        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) {
+
+            Profiler innerprof3("SpectrogramLayer::paint: 1 bin");
+
+            float y0 = yforbin[q + 1 - minbin];
+            float y1 = yforbin[q - minbin];
+
+            if (m_binDisplay == PeakBins) {
+                if (!fft->isLocalPeak(s, q)) continue;
+            }
+            if (m_binDisplay == PeakFrequencies) {
+                if (peaks.find(q) == peaks.end()) continue;
+            }
+
+            if (m_threshold != 0.f &&
+                !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
+                continue;
+            }
+
+            float sprop = 1.f;
+            if (s == s0i) sprop *= (s + 1) - s0;
+            if (s == s1i) sprop *= s1 - s;
+ 
+            if (m_binDisplay == PeakFrequencies) {
+                y0 = y1 = v->getYForFrequency
+                    (peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
+            }
+		
+            int y0i = int(y0 + 0.001f);
+            int y1i = int(y1);
+
+            float value = values[q - minbin];
+
+            if (m_colourScale != PhaseColourScale) {
+                if (!m_normalizeColumns) {
+                    value /= (m_fftSize/2.f);
+                }
+                mag.sample(value);
+                value *= m_gain;
+            }
+
+            if (interpolate) {
+                    
+                int ypi = y0i;
+                if (q < maxbin - 1) ypi = int(yforbin[q + 2 - minbin]);
+
+                for (int y = ypi; y <= y1i; ++y) {
+                    
+                    if (y < 0 || y >= h) continue;
+                    
+                    float yprop = sprop;
+                    float iprop = yprop;
+
+                    if (ypi < y0i && y <= y0i) {
+
+                        float half = float(y0i - ypi) / 2.f;
+                        float dist = y - (ypi + half);
+
+                        if (dist >= 0) {
+                            iprop = (iprop * dist) / half;
+                            ymag[y] += iprop * value;
+                        }
+                    } else {
+                        if (y1i > y0i) {
+
+                            float half = float(y1i - y0i) / 2.f;
+                            float dist = y - (y0i + half);
+                                
+                            if (dist >= 0) {
+                                iprop = (iprop * (half - dist)) / half;
+                            }
+                        }
+
+                        ymag[y] += iprop * value;
+                        ydiv[y] += yprop;
+                    }
+                }
+
+            } else {
+
+                for (int y = y0i; y <= y1i; ++y) {
+                    
+                    if (y < 0 || y >= h) continue;
+                    
+                    float yprop = sprop;
+                    if (y == y0i) yprop *= (y + 1) - y0;
+                    if (y == y1i) yprop *= y1 - y;
+
+                    for (int y = y0i; y <= y1i; ++y) {
+		    
+                        if (y < 0 || y >= h) continue;
+
+                        float yprop = sprop;
+                        if (y == y0i) yprop *= (y + 1.f) - y0;
+                        if (y == y1i) yprop *= y1 - y;
+                        ymag[y] += yprop * value;
+                        ydiv[y] += yprop;
+                    }
+                }
+            }
+        }
+
+        if (mag.isSet()) {
+
+            if (s >= int(m_columnMags.size())) {
+                std::cerr << "INTERNAL ERROR: " << s << " >= "
+                          << m_columnMags.size() << " at SpectrogramLayer.cpp:2087" << std::endl;
+            }
+
+            m_columnMags[s].sample(mag);
+/*!!!
+            if (overallMag.sample(mag)) {
+                //!!! scaling would change here
+                overallMagChanged = true;
+#ifdef DEBUG_SPECTROGRAM_REPAINT
+                std::cerr << "Overall mag changed (again?) at column " << s << ", to [" << overallMag.getMin() << "->" << overallMag.getMax() << "]" << std::endl;
+#endif
+            }
+*/
+        }
+    }
+
+    for (int y = 0; y < h; ++y) {
+
+        if (ydiv[y] > 0.0) {
+            yval[y] = ymag[y] / ydiv[y];
+        } else {
+            yval[y] = 0;
+        }
+    }
+
+    return true;
+}
+
+
 void
 SpectrogramLayer::illuminateLocalFeatures(View *v, QPainter &paint) const
 {
--- a/layer/SpectrogramLayer.h	Mon Feb 02 17:07:47 2009 +0000
+++ b/layer/SpectrogramLayer.h	Tue Feb 03 11:19:39 2009 +0000
@@ -283,6 +283,11 @@
 
     Palette m_palette;
 
+    /**
+     * PixmapCache covers the area of the view, at view resolution.
+     * Not all of it is necessarily valid at once (it is refreshed
+     * in parts when scrolling, for example).
+     */
     struct PixmapCache
     {
         QPixmap pixmap;
@@ -294,6 +299,13 @@
     void invalidatePixmapCaches();
     void invalidatePixmapCaches(size_t startFrame, size_t endFrame);
     mutable ViewPixmapCache m_pixmapCaches;
+
+    /**
+     * When painting, we draw directly onto the draw buffer and then
+     * copy this to the part of the pixmap cache that needed refreshing
+     * before copying the pixmap cache onto the window.  (Remind me why
+     * we don't draw directly onto the cache?)
+     */
     mutable QImage m_drawBuffer;
 
     mutable QTimer *m_updateTimer;
@@ -401,6 +413,11 @@
     mutable std::vector<MagnitudeRange> m_columnMags;
     void invalidateMagnitudes();
     bool updateViewMagnitudes(View *v) const;
+    bool getColumnValues(View *v, FFTModel *fft, int x0, int x,
+                         int minbin, int maxbin,
+                         float displayMinFreq, float displayMaxFreq,
+                         const int h,
+                         const float *yforbin, float *yval) const;
 
     virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
     virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
--- a/layer/layer.pro	Mon Feb 02 17:07:47 2009 +0000
+++ b/layer/layer.pro	Tue Feb 03 11:19:39 2009 +0000
@@ -6,6 +6,13 @@
 CONFIG += sv staticlib qt thread warn_on stl rtti exceptions
 QT += xml
 
+
+#!!!
+	debug {
+		CONFIG += precompile_header
+		PRECOMPILED_HEADER = ../stable.h
+	}
+
 TARGET = svlayer
 
 DEPENDPATH += . ..