changeset 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 47fe0352861e
children ac58acbd7482
files layer/Layer.cpp layer/Layer.h layer/SliceLayer.cpp layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp view/Pane.cpp widgets/LayerTree.cpp widgets/PropertyBox.cpp
diffstat 8 files changed, 131 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Layer.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/layer/Layer.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -272,6 +272,12 @@
 }
 
 void
+Layer::measureDoubleClick(View *v, QMouseEvent *e)
+{
+    // nothing
+}
+
+void
 Layer::paintMeasurementRects(View *v, QPainter &paint,
                              bool showFocus, QPoint focusPoint) const
 {
--- a/layer/Layer.h	Tue Jul 03 18:56:27 2007 +0000
+++ b/layer/Layer.h	Wed Jul 04 15:29:16 2007 +0000
@@ -170,6 +170,7 @@
     virtual void measureStart(View *, QMouseEvent *);
     virtual void measureDrag(View *, QMouseEvent *);
     virtual void measureEnd(View *, QMouseEvent *);
+    virtual void measureDoubleClick(View *, QMouseEvent *);
 
     /**
      * Open an editor on the item under the mouse (e.g. on
--- a/layer/SliceLayer.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/layer/SliceLayer.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -133,6 +133,8 @@
     
     range = f1 - f0 + 1;
 
+    QString rtrangestr = QString("%1 s").arg((rt1 - rt0).toText().c_str());
+
     if (includeBinDescription) {
 
         float minvalue = 0.f;
@@ -157,10 +159,11 @@
             valuestr = QString("%1").arg(minvalue);
         }
 
-        QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples\nBin:\t%4\n%5 value:\t%6")
+        QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)\nBin:\t%5\n%6 value:\t%7")
             .arg(QString::fromStdString(rt0.toText(true)))
             .arg(QString::fromStdString(rt1.toText(true)))
             .arg(range)
+            .arg(rtrangestr)
             .arg(binstr)
             .arg(m_samplingMode == NearestSample ? tr("First") :
                  m_samplingMode == SampleMean ? tr("Mean") : tr("Peak"))
@@ -170,10 +173,11 @@
     
     } else {
 
-        QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples")
+        QString description = tr("Time:\t%1 - %2\nRange:\t%3 samples (%4)")
             .arg(QString::fromStdString(rt0.toText(true)))
             .arg(QString::fromStdString(rt1.toText(true)))
-            .arg(range);
+            .arg(range)
+            .arg(rtrangestr);
         
         return description;
     }
--- a/layer/SpectrogramLayer.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -2071,15 +2071,25 @@
 
             MagnitudeRange mag;
 
+            FFTModel::PeakSet peaks;
+            if (m_binDisplay == PeakFrequencies &&
+                s < int(fft->getWidth()) - 1) {
+                peaks = fft->getPeakFrequencies(FFTModel::AllPeaks,
+                                                s,
+                                                minbin, maxbin - 1);
+            }
+
             for (size_t q = minbin; q < maxbin; ++q) {
 
                 float y0 = yval[q + 1];
                 float y1 = yval[q];
 
-		if (m_binDisplay == PeakBins ||
-		    m_binDisplay == PeakFrequencies) {
+		if (m_binDisplay == PeakBins) {
 		    if (!fft->isLocalPeak(s, q)) continue;
 		}
+                if (m_binDisplay == PeakFrequencies) {
+                    if (peaks.find(q) == peaks.end()) continue;
+                }
 
                 if (m_threshold != 0.f &&
                     !fft->isOverThreshold(s, q, m_threshold * (m_fftSize/2))) {
@@ -2090,14 +2100,9 @@
 		if (s == s0i) sprop *= (s + 1) - s0;
 		if (s == s1i) sprop *= s1 - s;
  
-		if (m_binDisplay == PeakFrequencies &&
-		    s < int(fft->getWidth()) - 1) {
-
-                    float f = 0;
-                    fft->estimateStableFrequency(s, q, f);
-
+		if (m_binDisplay == PeakFrequencies) {
 		    y0 = y1 = v->getYForFrequency
-			(f, displayMinFreq, displayMaxFreq, logarithmic);
+			(peaks[q], displayMinFreq, displayMaxFreq, logarithmic);
 		}
 		
 		int y0i = int(y0 + 0.001);
@@ -2466,16 +2471,29 @@
 
     int sw = getVerticalScaleWidth(v, paint);
 
-    QRect label(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
-                paint.fontMetrics().width("123456 Hz") + 2,
-                paint.fontMetrics().height());
-    extents.push_back(label);
+    QRect freq(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
+               paint.fontMetrics().width("123456 Hz") + 2,
+               paint.fontMetrics().height());
+    extents.push_back(freq);
 
     QRect pitch(sw, cursorPos.y() + 2,
                 paint.fontMetrics().width("C#10+50c") + 2,
                 paint.fontMetrics().height());
     extents.push_back(pitch);
 
+    QRect rt(cursorPos.x(),
+             v->height() - paint.fontMetrics().height() - 2,
+             paint.fontMetrics().width("1234.567 s"),
+             paint.fontMetrics().height());
+    extents.push_back(rt);
+
+    int w(paint.fontMetrics().width("1234567890") + 2);
+    QRect frame(cursorPos.x() - w - 2,
+                v->height() - paint.fontMetrics().height() - 2,
+                w,
+                paint.fontMetrics().height());
+    extents.push_back(frame);
+
     return true;
 }
 
@@ -2507,12 +2525,20 @@
                            View::OutlinedText);
     }
 
-    /*!!!
-    long frame = getFrameForX(cursorPos.x());
+    long frame = v->getFrameForX(cursorPos.x());
     RealTime rt = RealTime::frame2RealTime(frame, m_model->getSampleRate());
-    QString timeLabel = rt.toText(true).c_str();
-    ...
-    */
+    QString rtLabel = QString("%1 s").arg(rt.toText(true).c_str());
+    QString frameLabel = QString("%1").arg(frame);
+    v->drawVisibleText(paint,
+                       cursorPos.x() - paint.fontMetrics().width(frameLabel) - 2,
+                       v->height() - 2,
+                       frameLabel,
+                       View::OutlinedText);
+    v->drawVisibleText(paint,
+                       cursorPos.x() + 2,
+                       v->height() - 2,
+                       rtLabel,
+                       View::OutlinedText);
 
     int harmonic = 2;
 
--- 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);
--- a/view/Pane.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/view/Pane.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -1587,6 +1587,12 @@
 	if (layer && layer->isLayerEditable()) {
 	    if (layer->editOpen(this, e)) relocate = false;
 	}
+
+    } else if (mode == ViewManager::MeasureMode) {
+
+        Layer *layer = getTopLayer();
+        if (layer) layer->measureDoubleClick(this, e);
+        update();
     }
 
     if (relocate) {
--- a/widgets/LayerTree.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/widgets/LayerTree.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -21,6 +21,7 @@
 #include "layer/Layer.h"
 #include "data/model/Model.h"
 
+#include <QIcon>
 #include <iostream>
 
 
--- a/widgets/PropertyBox.cpp	Tue Jul 03 18:56:27 2007 +0000
+++ b/widgets/PropertyBox.cpp	Wed Jul 04 15:29:16 2007 +0000
@@ -429,6 +429,9 @@
                 cb->setEditable(true);
             }
             cb->blockSignals(false);
+            if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) {
+                cb->setMaxVisibleItems(cb->count());
+            }
         }
 
         if (!have) {