diff layer/SpectrogramLayer.cpp @ 133:9e6b3e239b9d

* Add zoom thumbwheels to Pane. Implement horizontal thumbwheel, and vertical depending on layer type (supported for waveform and spectrogram, though wrong for log-scale spectrogram at the moment). * Add bare bones of a spectrum layer. * Add window icon * Add shortcut for "insert time instant" on laptops without keypad enter (";") * Delete FFT processing thread when it exits (at least, next time we're asked for something interesting) * Get audio file extensions from the file readers, and thus from libsndfile for the wave file reader -- leads to rather a wide combo box in file dialog though * Better refresh order for spectrogram (redraw centre section first)
author Chris Cannam
date Fri, 04 Aug 2006 17:01:37 +0000
parents 5d3a483856ff
children 13949a6970ab
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Thu Aug 03 15:40:11 2006 +0000
+++ b/layer/SpectrogramLayer.cpp	Fri Aug 04 17:01:37 2006 +0000
@@ -35,7 +35,7 @@
 #include <cassert>
 #include <cmath>
 
-//#define DEBUG_SPECTROGRAM_REPAINT 1
+#define DEBUG_SPECTROGRAM_REPAINT 1
 
 SpectrogramLayer::SpectrogramLayer(Configuration config) :
     Layer(),
@@ -57,6 +57,7 @@
     m_binDisplay(AllBins),
     m_normalizeColumns(false),
     m_normalizeVisibleArea(false),
+    m_lastEmittedZoomStep(-1),
     m_updateTimer(0),
     m_candidateFillStartFrame(0),
     m_exiting(false)
@@ -487,6 +488,11 @@
 	case 8: setMinFrequency(4000); break;
 	case 9: setMinFrequency(10000); break;
 	}
+        int vs = getCurrentVerticalZoomStep();
+        if (vs != m_lastEmittedZoomStep) {
+            emit verticalZoomChanged();
+            m_lastEmittedZoomStep = vs;
+        }
     } else if (name == "Max Frequency") {
 	switch (value) {
 	case 0: setMaxFrequency(500); break;
@@ -501,6 +507,11 @@
 	default:
 	case 9: setMaxFrequency(0); break;
 	}
+        int vs = getCurrentVerticalZoomStep();
+        if (vs != m_lastEmittedZoomStep) {
+            emit verticalZoomChanged();
+            m_lastEmittedZoomStep = vs;
+        }
     } else if (name == "Colour Scale") {
 	switch (value) {
 	default:
@@ -1159,7 +1170,12 @@
         //!!! experiment with normalizing the visible area this way.
         //In any case, we need to have some indication of what the dB
         //scale is relative to.
-        input = 10.f * log10f(input / max);
+        input = input / max;
+        if (input > 0.f) {
+            input = 10.f * log10f(input);
+        } else {
+            input = thresh;
+        }
         if (min > 0.f) {
             thresh = 10.f * log10f(min);
             if (thresh < -80.f) thresh = -80.f;
@@ -1173,7 +1189,12 @@
     case OtherColourScale:
         //!!! the "Other" scale is just where our current experiments go
         //!!! power rather than v
-        input = 10.f * log10f((input * input) / (max * max));
+        input = (input * input) / (max * max);
+        if (input > 0.f) {
+            input = 10.f * log10f(input);
+        } else {
+            input = thresh;
+        }
         if (min > 0.f) {
             thresh = 10.f * log10f(min * min);
             if (thresh < -80.f) thresh = -80.f;
@@ -1657,9 +1678,9 @@
     std::cerr << "rect is " << rect.x() << "," << rect.y() << " " << rect.width() << "x" << rect.height() << std::endl;
 #endif
 
-    long sf = v->getStartFrame();
-    if (sf < 0) m_candidateFillStartFrame = 0;
-    else m_candidateFillStartFrame = sf;
+    long startFrame = v->getStartFrame();
+    if (startFrame < 0) m_candidateFillStartFrame = 0;
+    else m_candidateFillStartFrame = startFrame;
 
     if (!m_model || !m_model->isOK() || !m_model->isReady()) {
 	return;
@@ -1695,7 +1716,6 @@
     std::cerr << "SpectrogramLayer::paint(): Still cacheing = " << stillCacheing << std::endl;
 #endif
 
-    long startFrame = v->getStartFrame();
     int zoomLevel = v->getZoomLevel();
 
     int x0 = 0;
@@ -1824,17 +1844,18 @@
     }
 */
 
+    if (updateViewMagnitudes(v)) {
+        std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
+        recreateWholePixmapCache = true;
+    } else {
+        std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
+    }
+
     if (recreateWholePixmapCache) {
         x0 = 0;
         x1 = v->width();
     }
 
-    if (updateViewMagnitudes(v)) {
-        std::cerr << "SpectrogramLayer: magnitude range changed to [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
-    } else {
-        std::cerr << "No change in magnitude range [" << m_viewMags[v].getMin() << "->" << m_viewMags[v].getMax() << "]" << std::endl;
-    }
-
     int paintBlockWidth = (300000 / zoomLevel);
     if (paintBlockWidth < 20) paintBlockWidth = 20;
 
@@ -1875,7 +1896,16 @@
             
     } else {
         if (x1 > x0 + paintBlockWidth) {
-            x1 = x0 + paintBlockWidth;
+            int sfx = x1;
+            if (startFrame < 0) sfx = v->getXForFrame(0);
+            if (sfx >= x0 && sfx + paintBlockWidth <= x1) {
+                x0 = sfx;
+                x1 = x0 + paintBlockWidth;
+            } else {
+                int mid = (x1 + x0) / 2;
+                x0 = mid - paintBlockWidth/2;
+                x1 = x0 + paintBlockWidth;
+            }
         }
         cache.validArea = QRect(x0, 0, x1 - x0, v->height());
     }
@@ -2156,6 +2186,9 @@
                   << x0 << "," << y1 << " -> " << x1 << "," << y0 << std::endl;
         
         paint.setPen(Qt::white);
+
+        //!!! should we be using paintCrosshairs for this?
+
         paint.drawRect(x0, y1, x1 - x0 + 1, y0 - y1 + 1);
     }
 }
@@ -2193,8 +2226,16 @@
 SpectrogramLayer::getValueExtents(float &min, float &max,
                                   bool &logarithmic, QString &unit) const
 {
-    min = getEffectiveMinFrequency();
-    max = getEffectiveMaxFrequency();
+//!!!
+//    min = getEffectiveMinFrequency();
+//    max = getEffectiveMaxFrequency();
+
+    if (!m_model) return false;
+
+    int sr = m_model->getSampleRate();
+    min = float(sr) / m_fftSize;
+    max = float(sr) / 2;
+    
     logarithmic = (m_frequencyScale == LogFrequencyScale);
     unit = "Hz";
     return true;
@@ -2228,6 +2269,12 @@
     
     emit layerParametersChanged();
 
+    int vs = getCurrentVerticalZoomStep();
+    if (vs != m_lastEmittedZoomStep) {
+        emit verticalZoomChanged();
+        m_lastEmittedZoomStep = vs;
+    }
+
     return true;
 }
 
@@ -2712,6 +2759,72 @@
     }
 }
 
+int
+SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const
+{
+    defaultStep = 0;
+    return 20; //!!!
+}
+
+int
+SpectrogramLayer::getCurrentVerticalZoomStep() const
+{
+    if (!m_model) return 0;
+
+    float dmin, dmax;
+    getDisplayExtents(dmin, dmax);
+    
+    float mmin, mmax;
+    int sr = m_model->getSampleRate();
+    mmin = float(sr) / m_fftSize;
+    mmax = float(sr) / 2;
+    
+    float mdist = mmax - mmin;
+    float ddist = dmax - dmin;
+    
+    int n = 0;
+    float s2 = sqrtf(2);
+    while (mdist > ddist) {
+        if (++n > 20) break;
+        mdist /= s2;
+    }
+
+    return n;
+}
+
+void
+SpectrogramLayer::setVerticalZoomStep(int step)
+{
+    //!!! does not do the right thing for log scale
+
+    float dmin, dmax;
+    getDisplayExtents(dmin, dmax);
+    
+    float mmin, mmax;
+    int sr = m_model->getSampleRate();
+    mmin = float(sr) / m_fftSize;
+    mmax = float(sr) / 2;
+    
+    float ddist = mmax - mmin;
+    
+    int n = 0;
+    float s2 = sqrtf(2);
+    while (n < step) {
+        ddist /= s2;
+        ++n;
+    }
+
+    float dmid = (dmax + dmin) / 2;
+    float newmin = dmid - ddist / 2;
+    float newmax = dmid + ddist / 2;
+    
+    if (newmin < mmin) newmin = mmin;
+    if (newmax > mmax) newmax = mmax;
+    
+    setMinFrequency(newmin);
+    setMaxFrequency(newmax);
+}
+
 QString
 SpectrogramLayer::toXmlString(QString indent, QString extraAttributes) const
 {
@@ -2815,8 +2928,3 @@
     setNormalizeColumns(normalizeColumns);
 }
     
-
-#ifdef INCLUDE_MOCFILES
-#include "SpectrogramLayer.moc.cpp"
-#endif
-