changeset 1403:10e768adaee5

Retain consistent min freq (rather than min bin no) when changing fft parameters in spectrum; scale ffts by window size rather than fft size in case of oversampling, to avoid fading out because of scale factor including zero padding
author Chris Cannam
date Thu, 15 Nov 2018 15:08:08 +0000
parents b0eeec95ab5b
children a33d38247631
files layer/SliceLayer.cpp layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp layer/SpectrumLayer.h
diffstat 4 files changed, 53 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SliceLayer.cpp	Thu Nov 15 14:18:26 2018 +0000
+++ b/layer/SliceLayer.cpp	Thu Nov 15 15:08:08 2018 +0000
@@ -1203,7 +1203,23 @@
 
     m_minbin = int(lrint(min));
     m_maxbin = int(lrint(max));
-    
+
+    if (m_minbin < 0) {
+        m_minbin = 0;
+    }
+    if (m_maxbin < 0) {
+        m_maxbin = 0;
+    }
+    if (m_minbin > m_sliceableModel->getHeight()) {
+        m_minbin = m_sliceableModel->getHeight();
+    }
+    if (m_maxbin > m_sliceableModel->getHeight()) {
+        m_maxbin = m_sliceableModel->getHeight();
+    }
+    if (m_maxbin < m_minbin) {
+        m_maxbin = m_minbin;
+    }
+
     emit layerParametersChanged();
     return true;
 }
@@ -1238,14 +1254,9 @@
     int dist = m_sliceableModel->getHeight() - step;
     if (dist < 1) dist = 1;
     double centre = m_minbin + (m_maxbin - m_minbin) / 2.0;
-    m_minbin = int(lrint(centre - dist/2.0));
-    if (m_minbin < 0) m_minbin = 0;
-    m_maxbin = m_minbin + dist;
-    if (m_maxbin > m_sliceableModel->getHeight()) m_maxbin = m_sliceableModel->getHeight();
-
-//    SVDEBUG << "SliceLayer::setVerticalZoomStep(" <<step <<"):  after: minbin = " << m_minbin << ", maxbin = " << m_maxbin << endl;
-    
-    emit layerParametersChanged();
+    int minbin = int(lrint(centre - dist/2.0));
+    int maxbin = minbin + dist;
+    setDisplayExtents(minbin, maxbin);
 }
 
 RangeMapper *
--- a/layer/SpectrogramLayer.cpp	Thu Nov 15 14:18:26 2018 +0000
+++ b/layer/SpectrogramLayer.cpp	Thu Nov 15 15:08:08 2018 +0000
@@ -1534,7 +1534,7 @@
 
         if (m_colourScale != ColourScaleType::Phase &&
             m_normalization != ColumnNormalization::Hybrid) {
-            params.scaleFactor *= 2.f / float(getFFTSize());
+            params.scaleFactor *= 2.f / float(getWindowSize());
         }
 
         Preferences::SpectrogramSmoothing smoothing = 
--- a/layer/SpectrumLayer.cpp	Thu Nov 15 14:18:26 2018 +0000
+++ b/layer/SpectrumLayer.cpp	Thu Nov 15 15:08:08 2018 +0000
@@ -41,7 +41,8 @@
     m_windowHopLevel(3),
     m_oversampling(1),
     m_showPeaks(false),
-    m_newFFTNeeded(true)
+    m_newFFTNeeded(true),
+    m_freqOfMinBin(0.0)
 {
     m_binAlignment = BinsCentredOnScalePoints;
     
@@ -126,6 +127,8 @@
 
     if (m_minbin == 0 && m_maxbin == 0) {
         m_minbin = 1;
+        m_freqOfMinBin = double(m_minbin * newFFT->getSampleRate())
+            / getFFTSize();
         m_maxbin = newFFT->getHeight();
     }
 
@@ -133,7 +136,9 @@
 
     m_biasCurve.clear();
     for (int i = 0; i < fftSize; ++i) {
-        m_biasCurve.push_back(1.f / (float(fftSize)/2.f));
+        // Scale by the window size, not the FFT size, because we
+        // don't want to scale down by all the zero bins
+        m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f));
     }
 
     m_newFFTNeeded = false;
@@ -298,12 +303,12 @@
     SVDEBUG << "setWindowSize: from " << m_windowSize
             << " to " << ws << ": updating min and max bins from "
             << m_minbin << " and " << m_maxbin << " to ";
-    /*
-    m_minbin = int(round((double(m_minbin) / m_windowSize) * ws));
-    */
-    m_maxbin = int(round((double(m_maxbin) / m_windowSize) * ws));
 
+    int previousWs = m_windowSize;
     m_windowSize = ws;
+    
+    m_minbin = int(round(getBinForFrequency(m_freqOfMinBin)));
+    m_maxbin = int(round((double(m_maxbin) / previousWs) * m_windowSize));
 
     int h = getFFTSize() / 2 + 1;
     if (m_minbin > h) m_minbin = h;
@@ -341,12 +346,13 @@
     SVDEBUG << "setOversampling: from " << m_oversampling
             << " to " << oversampling << ": updating min and max bins from "
             << m_minbin << " and " << m_maxbin << " to ";
-/*    
-    m_minbin = int(round((double(m_minbin) / m_oversampling) * oversampling));
-*/
-    m_maxbin = int(round((double(m_maxbin) / m_oversampling) * oversampling));
 
+    int previousOversampling = m_oversampling;
     m_oversampling = oversampling;
+    
+    m_minbin = int(round(getBinForFrequency(m_freqOfMinBin)));
+    m_maxbin = int(round((double(m_maxbin) / previousOversampling) *
+                         m_oversampling));
 
     int h = getFFTSize() / 2 + 1;
     if (m_minbin > h) m_minbin = h;
@@ -355,7 +361,6 @@
     SVDEBUG << m_minbin << " and " << m_maxbin << endl;
     
     m_newFFTNeeded = true;
-    
     emit layerParametersChanged();
 }
 
@@ -385,6 +390,16 @@
     }
 }
 
+bool
+SpectrumLayer::setDisplayExtents(double min, double max)
+{
+    bool result = SliceLayer::setDisplayExtents(min, max);
+    if (result) {
+        m_freqOfMinBin = getFrequencyForBin(m_minbin);
+    }
+    return result;
+}
+
 double
 SpectrumLayer::getBinForFrequency(double freq) const
 {
--- a/layer/SpectrumLayer.h	Thu Nov 15 14:18:26 2018 +0000
+++ b/layer/SpectrumLayer.h	Thu Nov 15 15:08:08 2018 +0000
@@ -68,6 +68,8 @@
     virtual void setProperty(const PropertyName &, int value) override;
     virtual void setProperties(const QXmlAttributes &) override;
 
+    virtual bool setDisplayExtents(double min, double max) override;
+    
     virtual bool getXScaleValue(const LayerGeometryProvider *v, int x,
                                 double &value, QString &unit) const override;
 
@@ -123,6 +125,10 @@
     bool                    m_showPeaks;
     mutable bool            m_newFFTNeeded;
 
+    double                  m_freqOfMinBin; // used to ensure accurate
+                                            // alignment when changing
+                                            // fft size
+
     mutable QMutex m_fftMutex;
 
     void setupFFT();