diff layer/SpectrumLayer.cpp @ 280:3c402c6052f6

* Pull peak-picker out of SpectrumLayer and into FFTModel; use combined peak-picker and frequency estimator for SpectrogramLayer (makes the peak frequency spectrogram a bit quicker) * Add more information to spectrum and spectrogram crosshairs
author Chris Cannam
date Wed, 04 Jul 2007 15:29:16 +0000
parents a078aa2932cc
children 4edaff85875d
line wrap: on
line diff
--- a/layer/SpectrumLayer.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -1,4 +1,3 @@
-
 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
 
 /*
@@ -294,6 +293,7 @@
 SpectrumLayer::getFrequencyForX(float x, float w) const
 {
     float freq = 0;
+    if (!m_sliceableModel) return 0;
 
     int sampleRate = m_sliceableModel->getSampleRate();
 
@@ -321,6 +321,7 @@
 SpectrumLayer::getXForFrequency(float freq, float w) const
 {
     float x = 0;
+    if (!m_sliceableModel) return x;
 
     int sampleRate = m_sliceableModel->getSampleRate();
 
@@ -401,14 +402,26 @@
     QRect horizontal(0, cursorPos.y(), v->width(), 12);
     extents.push_back(horizontal);
 
-    int hoffset = 1;
-    if (m_binScale == LogBins) hoffset = 12;
+    int hoffset = 2;
+    if (m_binScale == LogBins) hoffset = 13;
 
-    QRect label(cursorPos.x(),
-                v->height() - paint.fontMetrics().height() - hoffset,
-                paint.fontMetrics().width("123456 Hz") + 2,
+    int sw = getVerticalScaleWidth(v, paint);
+
+    QRect value(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
+                paint.fontMetrics().width("0.0000001 V") + 2,
                 paint.fontMetrics().height());
-    extents.push_back(label);
+    extents.push_back(value);
+
+    QRect log(sw, cursorPos.y() + 2,
+              paint.fontMetrics().width("-80.000 dBV") + 2,
+              paint.fontMetrics().height());
+    extents.push_back(log);
+
+    QRect freq(cursorPos.x(),
+               v->height() - paint.fontMetrics().height() - hoffset,
+               paint.fontMetrics().width("123456 Hz") + 2,
+               paint.fontMetrics().height());
+    extents.push_back(freq);
 
     int w(paint.fontMetrics().width("C#10+50c") + 2);
     QRect pitch(cursorPos.x() - w,
@@ -424,6 +437,8 @@
 SpectrumLayer::paintCrosshairs(View *v, QPainter &paint,
                                QPoint cursorPos) const
 {
+    if (!m_sliceableModel) return;
+
     paint.save();
 
     ColourMapper mapper(m_colourMap, 0, 1);
@@ -437,8 +452,8 @@
     
     float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
 
-    int hoffset = 1;
-    if (m_binScale == LogBins) hoffset = 12;
+    int hoffset = 2;
+    if (m_binScale == LogBins) hoffset = 13;
 
     v->drawVisibleText(paint,
                        cursorPos.x() + 2,
@@ -455,6 +470,24 @@
                            View::OutlinedText);
     }
 
+    float value = getValueForY(cursorPos.y(), v);
+    float thresh = -80.f;
+    float db = thresh;
+    if (value > 0.f) db = 10.f * log10f(value);
+    if (db < thresh) db = thresh;
+
+    v->drawVisibleText(paint,
+                       xorigin + 2,
+                       cursorPos.y() - 2,
+                       QString("%1 V").arg(value),
+                       View::OutlinedText);
+
+    v->drawVisibleText(paint,
+                       xorigin + 2,
+                       cursorPos.y() + 2 + paint.fontMetrics().ascent(),
+                       QString("%1 dBV").arg(db),
+                       View::OutlinedText);
+    
     int harmonic = 2;
 
     while (harmonic < 100) {
@@ -588,7 +621,7 @@
     FFTModel *fft = dynamic_cast<FFTModel *>
         (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
 
-    float thresh = powf(10, -8) / m_gain; // -80dB
+    float thresh = (powf(10, -6) / m_gain) * (m_windowSize / 2.f); // -60dB adj
 
     int xorigin = getVerticalScaleWidth(v, paint) + 1;
     int w = v->width() - xorigin - 1;
@@ -607,27 +640,38 @@
         paint.setRenderHint(QPainter::Antialiasing, false);
         paint.setPen(QColor(160, 160, 160)); //!!!
 
-        ColourMapper mapper(m_colourMap, 0, 1);
+        FFTModel::PeakSet peaks = fft->getPeakFrequencies
+            (FFTModel::MajorPitchAdaptivePeaks, col);
+
+        ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1);
 
         BiasCurve curve;
         getBiasCurve(curve);
         size_t cs = curve.size();
+
+        std::vector<float> values;
         
         for (size_t bin = 0; bin < fft->getHeight(); ++bin) {
+            float value = m_sliceableModel->getValueAt(col, bin);
+            if (bin < cs) value *= curve[bin];
+            values.push_back(value);
+        }
+
+        for (FFTModel::PeakSet::iterator i = peaks.begin();
+             i != peaks.end(); ++i) {
+
+            size_t bin = i->first;
             
-            if (!fft->isLocalPeak(col, bin)) continue;
+//            std::cerr << "bin = " << bin << ", thresh = " << thresh << ", value = " << fft->getMagnitudeAt(col, bin) << std::endl;
+
             if (!fft->isOverThreshold(col, bin, thresh)) continue;
             
-            float freq = 0;
-            bool haveFreq = fft->estimateStableFrequency(col, bin, freq);
-            if (!haveFreq) continue;
-            
+            float freq = i->second;
+          
             int x = lrintf(getXForFrequency(freq, w));
 
-            float value = m_sliceableModel->getValueAt(col, bin);
-            if (bin < cs) value *= curve[bin];
             float norm = 0.f;
-            float y = getYForValue(value, v, norm); // don't need y, need norm
+            float y = getYForValue(values[bin], v, norm); // don't need y, need norm
 
             paint.setPen(mapper.map(norm));
             paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);