diff layer/SpectrogramLayer.cpp @ 187:e7cf6044c2a0

* better icon * support range mappers in thumbwheel * supply range mapper for vertical zoom from spectrogram * fix bug in fftmodel for scaled ffts * make the various widgets all respond to double-click for edit, middle-click for reset, ctrl-left-click for reset
author Chris Cannam
date Fri, 12 Jan 2007 14:49:18 +0000
parents 3a6fea0abf56
children dd573e090eed
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Fri Jan 05 15:49:10 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Fri Jan 12 14:49:18 2007 +0000
@@ -725,6 +725,8 @@
 {
     if (m_minFrequency == mf) return;
 
+    std::cerr << "SpectrogramLayer::setMinFrequency: " << mf << std::endl;
+
     invalidatePixmapCaches();
     invalidateMagnitudes();
     
@@ -744,6 +746,8 @@
 {
     if (m_maxFrequency == mf) return;
 
+    std::cerr << "SpectrogramLayer::setMaxFrequency: " << mf << std::endl;
+
     invalidatePixmapCaches();
     invalidateMagnitudes();
     
@@ -1595,7 +1599,7 @@
             m_fftModels.erase(v);
         } else {
 #ifdef DEBUG_SPECTROGRAM_REPAINT
-            std::cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model" << std::endl;
+            std::cerr << "SpectrogramLayer::getFFTModel(" << v << "): Found a good model of height " << m_fftModels[v].first->getHeight() << std::endl;
 #endif
             return m_fftModels[v].first;
         }
@@ -2293,6 +2297,7 @@
 {
     min = getEffectiveMinFrequency();
     max = getEffectiveMaxFrequency();
+    std::cerr << "SpectrogramLayer::getDisplayExtents: " << min << "->" << max << std::endl;
     return true;
 }    
 
@@ -2300,6 +2305,9 @@
 SpectrogramLayer::setDisplayExtents(float min, float max)
 {
     if (!m_model) return false;
+
+    std::cerr << "SpectrogramLayer::setDisplayExtents: " << min << "->" << max << std::endl;
+
     if (min < 0) min = 0;
     if (max > m_model->getSampleRate()/2) max = m_model->getSampleRate()/2;
     
@@ -2806,38 +2814,73 @@
     }
 }
 
+class SpectrogramRangeMapper : public RangeMapper
+{
+public:
+    SpectrogramRangeMapper(int sr, int fftsize) :
+//        m_dist((float(sr) / 2) - (float(sr) / fftsize)),
+        m_dist(float(sr) / 2),
+        m_s2(sqrtf(sqrtf(2))) { }
+    ~SpectrogramRangeMapper() { }
+    
+    virtual int getPositionForValue(float value) const {
+
+        float dist = m_dist;
+    
+        int n = 0;
+        int discard = 0;
+
+        while (dist > (value + 0.00001) && dist > 0.1f) {
+            dist /= m_s2;
+            ++n;
+        }
+
+        return n;
+    }
+
+    virtual float getValueForPosition(int position) const {
+
+        // Vertical zoom step 0 shows the entire range from DC ->
+        // Nyquist frequency.  Step 1 shows 2^(1/4) of the range of
+        // step 0, and so on until the visible range is smaller than
+        // the frequency step between bins at the current fft size.
+
+        float dist = m_dist;
+    
+        int n = 0;
+        while (n < position) {
+            dist /= m_s2;
+            ++n;
+        }
+
+        return dist;
+    }
+    
+    virtual QString getUnit() const { return "Hz"; }
+
+protected:
+    float m_dist;
+    float m_s2;
+};
+
 int
 SpectrogramLayer::getVerticalZoomSteps(int &defaultStep) const
 {
-    // Vertical zoom step 0 shows the entire range from DC -> Nyquist
-    // frequency.  Step 1 shows 2^(1/4) of the range of step 0, and so
-    // on until the visible range is smaller than the frequency step
-    // between bins at the current fft size.
-
     if (!m_model) return 0;
+
+    int sr = m_model->getSampleRate();
+
+    SpectrogramRangeMapper mapper(sr, m_fftSize);
+
+//    int maxStep = mapper.getPositionForValue((float(sr) / m_fftSize) + 0.001);
+    int maxStep = mapper.getPositionForValue(0);
+    int minStep = mapper.getPositionForValue(float(sr) / 2);
     
-    float min, max;
-    int sr = m_model->getSampleRate();
-    min = float(sr) / m_fftSize;
-    max = float(sr) / 2;
-    
-    float dist = max - min;
-
-    int n = 0;
-    defaultStep = 0;
-    bool haveDefault = false;
-    float s2 = sqrtf(sqrtf(2));
-    while (dist > min) {
-        if (!haveDefault && max <= m_initialMaxFrequency) {
-            defaultStep = n;
-            haveDefault = true;
-        }
-        ++n;
-        dist /= s2;
-        max = min + dist;
-    }
-
-    return n;
+    defaultStep = mapper.getPositionForValue(m_initialMaxFrequency) - minStep;
+
+    std::cerr << "SpectrogramLayer::getVerticalZoomSteps: " << maxStep - minStep << " (" << maxStep <<"-" << minStep << "), default is " << defaultStep << " (from initial max freq " << m_initialMaxFrequency << ")" << std::endl;
+
+    return maxStep - minStep;
 }
 
 int
@@ -2848,23 +2891,9 @@
     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;
-    int discard = 0;
-    int m = getVerticalZoomSteps(discard);
-    float s2 = sqrtf(sqrtf(2));
-    while (mdist > ddist) {
-        if (++n > m) break;
-        mdist /= s2;
-    }
-
+    SpectrogramRangeMapper mapper(m_model->getSampleRate(), m_fftSize);
+    int n = mapper.getPositionForValue(dmax - dmin);
+    std::cerr << "SpectrogramLayer::getCurrentVerticalZoomStep: " << n << std::endl;
     return n;
 }
 
@@ -2873,32 +2902,42 @@
 {
     //!!! does not do the right thing for log scale
 
+    if (!m_model) return;
+
     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(sqrtf(2));
-    while (n < step) {
-        ddist /= s2;
-        ++n;
-    }
+    SpectrogramRangeMapper mapper(sr, m_fftSize);
+    float ddist = mapper.getValueForPosition(step);
 
     float dmid = (dmax + dmin) / 2;
     float newmin = dmid - ddist / 2;
     float newmax = dmid + ddist / 2;
+
+    float mmin, mmax;
+    mmin = 0;
+    mmax = float(sr) / 2;
     
-    if (newmin < mmin) newmin = mmin;
-    if (newmax > mmax) newmax = mmax;
+    if (newmin < mmin) {
+        newmax += (mmin - newmin);
+        newmin = mmin;
+    }
+    if (newmax > mmax) {
+        newmax = mmax;
+    }
     
-    setMinFrequency(newmin);
-    setMaxFrequency(newmax);
+    std::cerr << "SpectrogramLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << ddist << ")" << std::endl;
+
+    setMinFrequency(int(newmin));
+    setMaxFrequency(int(newmax));
+}
+
+RangeMapper *
+SpectrogramLayer::getNewVerticalZoomRangeMapper() const
+{
+    if (!m_model) return 0;
+    return new SpectrogramRangeMapper(m_model->getSampleRate(), m_fftSize);
 }
 
 QString
@@ -2971,10 +3010,16 @@
     if (ok) setThreshold(threshold);
 
     size_t minFrequency = attributes.value("minFrequency").toUInt(&ok);
-    if (ok) setMinFrequency(minFrequency);
+    if (ok) {
+        std::cerr << "SpectrogramLayer::setProperties: setting min freq to " << minFrequency << std::endl;
+        setMinFrequency(minFrequency);
+    }
 
     size_t maxFrequency = attributes.value("maxFrequency").toUInt(&ok);
-    if (ok) setMaxFrequency(maxFrequency);
+    if (ok) {
+        std::cerr << "SpectrogramLayer::setProperties: setting max freq to " << maxFrequency << std::endl;
+        setMaxFrequency(maxFrequency);
+    }
 
     ColourScale colourScale = (ColourScale)
 	attributes.value("colourScale").toInt(&ok);