diff layer/SpectrumLayer.cpp @ 1281:fc9d9f1103fa horizontal-scale

Provide linear horizontal scale in spectrum as well as log; fix bin positioning and colour scale property box updating; ensure proper background colour and visibility of peak lines
author Chris Cannam
date Thu, 03 May 2018 15:15:15 +0100
parents 34394e8c2942
children d79e21855aef
line wrap: on
line diff
--- a/layer/SpectrumLayer.cpp	Wed May 02 14:27:17 2018 +0100
+++ b/layer/SpectrumLayer.cpp	Thu May 03 15:15:15 2018 +0100
@@ -26,7 +26,7 @@
 #include "ColourMapper.h"
 #include "PaintAssistant.h"
 #include "PianoScale.h"
-#include "LogNumericalScale.h"
+#include "HorizontalFrequencyScale.h"
 
 #include <QPainter>
 #include <QTextStream>
@@ -304,6 +304,9 @@
 {
     if (!m_sliceableModel) return 0;
     double bin = getBinForX(v, x);
+    // we assume the frequency of a bin corresponds to the centre of
+    // its visual range
+    bin -= 0.5;
     return (m_sliceableModel->getSampleRate() * bin) /
         (m_sliceableModel->getHeight() * 2);
 }
@@ -314,6 +317,8 @@
     if (!m_sliceableModel) return 0;
     double bin = (freq * m_sliceableModel->getHeight() * 2) /
         m_sliceableModel->getSampleRate();
+    // we want the centre of the bin range
+    bin += 0.5;
     return getXForBin(v, bin);
 }
 
@@ -600,27 +605,22 @@
     double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj
 
     int xorigin = getVerticalScaleWidth(v, false, paint) + 1;
-    int w = v->getPaintWidth() - xorigin - 1;
-
-    int pkh = int(paint.fontMetrics().height() * 0.7 + 0.5);
-    if (pkh < 10) pkh = 10;
-
-    int scaleh = LogNumericalScale().getWidth(v, paint, true);
-
-    paint.save();
+    int scaleHeight = getHorizontalScaleHeight(v, paint);
 
     if (fft && m_showPeaks) {
 
         // draw peak lines
 
-//        SVDEBUG << "Showing peaks..." << endl;
-
         int col = int(v->getCentreFrame() / fft->getResolution());
 
         paint.save();
         paint.setRenderHint(QPainter::Antialiasing, false);
-        paint.setPen(QColor(160, 160, 160)); //!!!
 
+        ColourMapper mapper =
+            hasLightBackground() ?
+            ColourMapper(ColourMapper::BlackOnWhite, 0, 1) :
+            ColourMapper(ColourMapper::WhiteOnBlack, 0, 1);
+        
         int peakminbin = 0;
         int peakmaxbin = fft->getHeight() - 1;
         double peakmaxfreq = Pitch::getFrequencyForPitch(128);
@@ -629,8 +629,6 @@
         FFTModel::PeakSet peaks = fft->getPeakFrequencies
             (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin);
 
-        ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1);
-
         BiasCurve curve;
         getBiasCurve(curve);
         int cs = int(curve.size());
@@ -660,14 +658,38 @@
             (void)getYForValue(v, values[bin], norm); // don't need return value, need norm
 
             paint.setPen(mapper.map(norm));
-            paint.drawLine(x, 0, x, v->getPaintHeight() - scaleh - pkh - 1);
+            paint.drawLine(x, 0, x, v->getPaintHeight() - scaleHeight - 1);
         }
 
         paint.restore();
     }
     
+    paint.save();
+    
     SliceLayer::paint(v, paint, rect);
+    
+    paintHorizontalScale(v, paint, xorigin);
 
+    paint.restore();
+}
+
+int
+SpectrumLayer::getHorizontalScaleHeight(LayerGeometryProvider *v,
+                                        QPainter &paint) const
+{
+    int pkh = int(paint.fontMetrics().height() * 0.7 + 0.5);
+    if (pkh < 10) pkh = 10;
+
+    int scaleh = HorizontalFrequencyScale().getHeight(v, paint);
+
+    return pkh + scaleh;
+}
+
+void
+SpectrumLayer::paintHorizontalScale(LayerGeometryProvider *v,
+                                    QPainter &paint,
+                                    int xorigin) const
+{
     //!!! All of this stuff relating to depicting frequencies
     // (keyboard, crosshairs etc) should be applicable to any slice
     // layer whose model has a vertical scale unit of Hz.  However,
@@ -677,17 +699,39 @@
     // that could be relevant to Colour3DPlotLayer with unit Hz, but
     // that's a bigger proposition.
 
-    int h = v->getPaintHeight();
+    if (!v->getViewManager()->shouldShowHorizontalValueScale()) {
+        return;
+    }
+    
+    int totalScaleHeight = getHorizontalScaleHeight(v, paint); // inc piano
+    int freqScaleHeight = HorizontalFrequencyScale().getHeight(v, paint);
+    int paintHeight = v->getPaintHeight();
+    int paintWidth = v->getPaintWidth();
 
     PianoScale().paintPianoHorizontal
         (v, this, paint,
-         QRect(xorigin, h - scaleh - pkh - 1, w + xorigin, pkh));
+         QRect(xorigin, paintHeight - totalScaleHeight - 1,
+               paintWidth - 1, totalScaleHeight - freqScaleHeight));
 
-    LogNumericalScale().paintHorizontal
+    int scaleLeft = int(getXForBin(v, 1));
+    
+    paint.drawLine(int(getXForBin(v, 0)), paintHeight - freqScaleHeight,
+                   scaleLeft, paintHeight - freqScaleHeight);
+
+    QString hz = tr("Hz");
+    int hzw = paint.fontMetrics().width(hz);
+    if (scaleLeft > hzw + 5) {
+        paint.drawText
+            (scaleLeft - hzw - 5,
+             paintHeight - freqScaleHeight + paint.fontMetrics().ascent() + 5,
+             hz);
+    }
+
+    HorizontalFrequencyScale().paintScale
         (v, this, paint,
-         QRect(int(getXForBin(v, 1)), h - scaleh, w + xorigin, scaleh)); 
-    
-    paint.restore();
+         QRect(scaleLeft, paintHeight - freqScaleHeight,
+               paintWidth, totalScaleHeight),
+         m_binScale == LogBins);
 }
 
 void