changeset 254:a2ae3d93c645

* bit of work on harmonic cursor in spectrum
author Chris Cannam
date Mon, 11 Jun 2007 12:14:52 +0000
parents 1b1e6947c124
children e175ade2d6b0
files layer/SliceLayer.cpp layer/SliceLayer.h layer/SpectrumLayer.cpp layer/SpectrumLayer.h
diffstat 4 files changed, 152 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SliceLayer.cpp	Fri Jun 08 15:19:50 2007 +0000
+++ b/layer/SliceLayer.cpp	Mon Jun 11 12:14:52 2007 +0000
@@ -36,7 +36,6 @@
     m_plotStyle(PlotSteps),
     m_binScale(LinearBins),
     m_normalize(false),
-    m_bias(false),
     m_gain(1.0),
     m_currentf0(0),
     m_currentf1(0)
@@ -229,7 +228,8 @@
 void
 SliceLayer::paint(View *v, QPainter &paint, QRect rect) const
 {
-    if (!m_sliceableModel) return;
+    if (!m_sliceableModel || !m_sliceableModel->isOK() ||
+        !m_sliceableModel->isReady()) return;
 
     paint.save();
     paint.setRenderHint(QPainter::Antialiasing, false);
@@ -287,10 +287,14 @@
     m_currentf0 = f0;
     m_currentf1 = f1;
 
+    BiasCurve curve;
+    getBiasCurve(curve);
+    size_t cs = curve.size();
+
     for (size_t col = col0; col <= col1; ++col) {
         for (size_t bin = 0; bin < mh; ++bin) {
             float value = m_sliceableModel->getValueAt(col, bin);
-            if (m_bias) value *= bin + 1;
+            if (bin < cs) value *= curve[bin];
             if (m_samplingMode == SamplePeak) {
                 if (value > m_values[bin]) m_values[bin] = value;
             } else {
--- a/layer/SliceLayer.h	Fri Jun 08 15:19:50 2007 +0000
+++ b/layer/SliceLayer.h	Mon Jun 11 12:14:52 2007 +0000
@@ -113,6 +113,12 @@
                                           int &minbin, int &maxbin,
                                           int &range) const;
 
+    // This curve may, of course, be flat -- the spectrum uses it for
+    // normalizing the fft results by the fft size (with 1/(fftsize/2)
+    // in each bin).
+    typedef std::vector<float> BiasCurve;
+    virtual void getBiasCurve(BiasCurve &) const { return; }
+
     const DenseThreeDimensionalModel *m_sliceableModel;
     QColor                            m_colour;
     int                               m_colourMap;
@@ -121,7 +127,6 @@
     PlotStyle                         m_plotStyle;
     BinScale                          m_binScale;
     bool                              m_normalize;
-    bool                              m_bias;
     float                             m_gain;
     mutable std::vector<int>          m_scalePoints;
     mutable std::map<View *, int>     m_xorigins;
--- a/layer/SpectrumLayer.cpp	Fri Jun 08 15:19:50 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Mon Jun 11 12:14:52 2007 +0000
@@ -21,6 +21,9 @@
 #include "base/AudioLevel.h"
 #include "base/Preferences.h"
 #include "base/RangeMapper.h"
+#include "ColourMapper.h"
+
+#include <QPainter>
 
 SpectrumLayer::SpectrumLayer() :
     m_originModel(0),
@@ -73,6 +76,11 @@
 
     setSliceableModel(newFFT);
 
+    m_biasCurve.clear();
+    for (size_t i = 0; i < m_windowSize; ++i) {
+        m_biasCurve.push_back(1.f / (float(m_windowSize)/2.f));
+    }
+
     newFFT->resume();
 }
 
@@ -143,7 +151,7 @@
     if (name == "Window Size") {
 
 	*min = 0;
-	*max = 10;
+	*max = 15;
         *deflt = 5;
 	
 	val = 0;
@@ -247,6 +255,121 @@
     return false;
 }
 
+bool
+SpectrumLayer::getCrosshairExtents(View *v, QPainter &,
+                                   QPoint cursorPos,
+                                   std::vector<QRect> &extents) const
+{
+    QRect vertical(cursorPos.x(), cursorPos.y(), 1, v->height() - cursorPos.y());
+    extents.push_back(vertical);
+
+    QRect horizontal(0, cursorPos.y(), v->width(), 12);
+    extents.push_back(horizontal);
+
+    return true;
+}
+
+float
+SpectrumLayer::getFrequencyForX(float x, float w) const
+{
+    float freq = 0;
+
+    int sampleRate = m_sliceableModel->getSampleRate();
+
+    float maxfreq = float(sampleRate) / 2;
+
+    switch (m_binScale) {
+
+    case LinearBins:
+        freq = ((x * maxfreq) / w);
+        break;
+        
+    case LogBins:
+        freq = powf(10.f, (x * log10f(maxfreq)) / w);
+        break;
+
+    case InvertedLogBins:
+        freq = maxfreq - powf(10.f, ((w - x) * log10f(maxfreq)) / w);
+        break;
+    }
+
+    return freq;
+}
+
+float
+SpectrumLayer::getXForFrequency(float freq, float w) const
+{
+    float x = 0;
+
+    int sampleRate = m_sliceableModel->getSampleRate();
+
+    float maxfreq = float(sampleRate) / 2;
+
+    switch (m_binScale) {
+
+    case LinearBins:
+        x = (freq * w) / maxfreq;
+        break;
+        
+    case LogBins:
+        x = (log10f(freq) * w) / log10f(maxfreq);
+        break;
+
+    case InvertedLogBins:
+        x = (w - log10f(maxfreq - freq) * w) / log10f(maxfreq);
+        break;
+    }
+
+    return x;
+}
+
+void
+SpectrumLayer::paintCrosshairs(View *v, QPainter &paint,
+                               QPoint cursorPos) const
+{
+    paint.save();
+
+    ColourMapper mapper(m_colourMap, 0, 1);
+    paint.setPen(mapper.getContrastingColour());
+
+    int xorigin = m_xorigins[v];
+    int w = v->width() - xorigin - 1;
+    
+    paint.drawLine(xorigin, cursorPos.y(), v->width(), cursorPos.y());
+    paint.drawLine(cursorPos.x(), cursorPos.y(), cursorPos.x(), v->height());
+    
+    float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
+
+    int harmonic = 2;
+
+    while (harmonic < 100) {
+
+        float hx = lrintf(getXForFrequency(fundamental * harmonic, w));
+        hx += xorigin;
+
+        if (hx < xorigin || hx > v->width()) break;
+        
+        int len = 7;
+
+        if (harmonic % 2 == 0) {
+            if (harmonic % 4 == 0) {
+                len = 12;
+            } else {
+                len = 10;
+            }
+        }
+
+        paint.drawLine(int(hx),
+                       cursorPos.y(),
+                       int(hx),
+                       cursorPos.y() + len);
+
+        ++harmonic;
+    }
+
+    paint.restore();
+}
+
 QString
 SpectrumLayer::getFeatureDescription(View *v, QPoint &p) const
 {
@@ -336,6 +459,11 @@
     return description;
 }
 
+void
+SpectrumLayer::getBiasCurve(BiasCurve &curve) const
+{
+    curve = m_biasCurve;
+}
 
 QString
 SpectrumLayer::toXmlString(QString indent, QString extraAttributes) const
--- a/layer/SpectrumLayer.h	Fri Jun 08 15:19:50 2007 +0000
+++ b/layer/SpectrumLayer.h	Mon Jun 11 12:14:52 2007 +0000
@@ -38,6 +38,10 @@
     void setModel(DenseTimeValueModel *model);
     virtual const Model *getModel() const { return m_originModel; }
 
+    virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos,
+                                     std::vector<QRect> &extents) const;
+    virtual void paintCrosshairs(View *, QPainter &, QPoint) const;
+
     virtual QString getFeatureDescription(View *v, QPoint &) const;
 
     virtual PropertyList getProperties() const;
@@ -90,6 +94,12 @@
 
     void setupFFT();
 
+    virtual void getBiasCurve(BiasCurve &) const;
+    BiasCurve m_biasCurve;
+
+    float getFrequencyForX(float x, float w) const;
+    float getXForFrequency(float freq, float w) const;
+
     size_t getWindowIncrement() const {
         if (m_windowHopLevel == 0) return m_windowSize;
         else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;