changeset 278:a078aa2932cc

* Fix piano keyboard in spectrum, add pitch labels to frequency displays in measurement rect (clunkily done) and harmonic cursor in spectrum
author Chris Cannam
date Tue, 03 Jul 2007 18:47:39 +0000
parents 8acd30ed735c
children 47fe0352861e
files layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp view/View.cpp
diffstat 3 files changed, 98 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Tue Jul 03 12:46:18 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Tue Jul 03 18:47:39 2007 +0000
@@ -2487,7 +2487,13 @@
     float fundamental = getFrequencyForY(v, cursorPos.y());
 
     int sw = getVerticalScaleWidth(v, paint);
-    paint.drawText(sw + 2, cursorPos.y() - 2, QString("%1 Hz").arg(fundamental));
+    v->drawVisibleText(paint,
+                       sw + 2,
+                       cursorPos.y() - 2,
+                       QString("%1 Hz").arg(fundamental),
+                       View::OutlinedText);
+
+    //!!! and pitch label
 
     int harmonic = 2;
 
--- a/layer/SpectrumLayer.cpp	Tue Jul 03 12:46:18 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Tue Jul 03 18:47:39 2007 +0000
@@ -401,11 +401,22 @@
     QRect horizontal(0, cursorPos.y(), v->width(), 12);
     extents.push_back(horizontal);
 
-    QRect label(cursorPos.x(), v->height() - paint.fontMetrics().height(),
+    int hoffset = 1;
+    if (m_binScale == LogBins) hoffset = 12;
+
+    QRect label(cursorPos.x(),
+                v->height() - paint.fontMetrics().height() - hoffset,
                 paint.fontMetrics().width("123456 Hz") + 2,
                 paint.fontMetrics().height());
     extents.push_back(label);
 
+    int w(paint.fontMetrics().width("C#10+50c") + 2);
+    QRect pitch(cursorPos.x() - w,
+                v->height() - paint.fontMetrics().height() - hoffset,
+                w,
+                paint.fontMetrics().height());
+    extents.push_back(pitch);
+
     return true;
 }
 
@@ -426,8 +437,23 @@
     
     float fundamental = getFrequencyForX(cursorPos.x() - xorigin, w);
 
-    paint.drawText(cursorPos.x() + 2, v->height() - 2,
-                   QString("%1 Hz").arg(fundamental));
+    int hoffset = 1;
+    if (m_binScale == LogBins) hoffset = 12;
+
+    v->drawVisibleText(paint,
+                       cursorPos.x() + 2,
+                       v->height() - 2 - hoffset,
+                       QString("%1 Hz").arg(fundamental),
+                       View::OutlinedText);
+
+    if (Pitch::isFrequencyInMidiRange(fundamental)) {
+        QString pitchLabel = Pitch::getPitchLabelForFrequency(fundamental);
+        v->drawVisibleText(paint,
+                           cursorPos.x() - paint.fontMetrics().width(pitchLabel) - 2,
+                           v->height() - 2 - hoffset,
+                           pitchLabel,
+                           View::OutlinedText);
+    }
 
     int harmonic = 2;
 
@@ -567,6 +593,9 @@
     int xorigin = getVerticalScaleWidth(v, paint) + 1;
     int w = v->width() - xorigin - 1;
 
+    int pkh = 0;
+    if (m_binScale == LogBins) pkh = 10;
+
     if (fft) {
 
         // draw peak lines
@@ -601,7 +630,7 @@
             float y = getYForValue(value, v, norm); // don't need y, need norm
 
             paint.setPen(mapper.map(norm));
-            paint.drawLine(xorigin + x, 0, xorigin + x, v->height());
+            paint.drawLine(xorigin + x, 0, xorigin + x, v->height() - pkh - 1);
         }
 
         paint.restore();
@@ -609,6 +638,15 @@
     
     SliceLayer::paint(v, paint, rect);
 
+    //!!! 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, the
+    //dense 3d model at the moment doesn't record its vertical scale
+    //unit -- we need to fix that and hoist this code as appropriate.
+    //Same really goes for any code in SpectrogramLayer that could be
+    //relevant to Colour3DPlotLayer with unit Hz, but that's a bigger
+    //proposition.
+
     if (m_binScale == LogBins) {
 
         int pkh = 10;
@@ -616,32 +654,45 @@
 
         // piano keyboard
         //!!! should be in a new paintHorizontalScale()?
+        // nice to have a piano keyboard class, of course
 
-	paint.drawLine(xorigin, h - pkh - 1, w, h - pkh - 1);
+	paint.drawLine(xorigin, h - pkh - 1, w + xorigin, h - pkh - 1);
 
 	int px = xorigin, ppx = xorigin;
-//	paint.setBrush(paint.pen().color());
+	paint.setBrush(paint.pen().color());
 
 	for (int i = 0; i < 128; ++i) {
 
 	    float f = Pitch::getFrequencyForPitch(i);
 	    int x = lrintf(getXForFrequency(f, w));
+                           
+            x += xorigin;
 
-            if (x < 0) break;
-            if (x + xorigin > w) {
+            if (i == 0) {
+                px = ppx = x;
+            }
+            if (i == 1) {
+                ppx = px - (x - px);
+            }
+
+            if (x < xorigin) {
+                ppx = px;
+                px = x;
                 continue;
             }
-                           
-            x += xorigin;
+                
+            if (x > w) {
+                break;
+            }
 
 	    int n = (i % 12);
 
             if (n == 1) {
                 // C# -- fill the C from here
                 if (x - ppx > 2) {
-                    paint.fillRect(x,
+                    paint.fillRect((px + ppx) / 2 + 1,
                                    h - pkh,
-                                   x - (px + ppx) / 2,
+                                   x - (px + ppx) / 2 - 1,
                                    pkh,
                                    Qt::gray);
                 }
@@ -650,9 +701,9 @@
 	    if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
 		// black notes
 		paint.drawLine(x, h - pkh, x, h);
-		int rw = ((px - x) / 4) * 2;
+		int rw = lrintf(float(x - px) / 4) * 2;
 		if (rw < 2) rw = 2;
-		paint.drawRect(x - (px-x)/4, h - pkh, rw, pkh/2);
+		paint.drawRect(x - rw/2, h - pkh, rw, pkh/2);
 	    } else if (n == 0 || n == 5) {
 		// C, F
 		if (px < w) {
--- a/view/View.cpp	Tue Jul 03 12:46:18 2007 +0000
+++ b/view/View.cpp	Tue Jul 03 18:47:39 2007 +0000
@@ -18,6 +18,7 @@
 #include "data/model/Model.h"
 #include "base/ZoomConstraint.h"
 #include "base/Profiler.h"
+#include "base/Pitch.h"
 
 #include "layer/TimeRulerLayer.h" //!!! damn, shouldn't be including that here
 #include "data/model/PowerOfSqrtTwoZoomConstraint.h" //!!! likewise
@@ -1679,6 +1680,13 @@
 
     if (!focus) return;
 
+    paint.save();
+    QFont fn = paint.font();
+    if (fn.pointSize() > 8) {
+        fn.setPointSize(fn.pointSize() - 1);
+        paint.setFont(fn);
+    }
+
     int fontHeight = paint.fontMetrics().height();
     int fontAscent = paint.fontMetrics().ascent();
 
@@ -1695,6 +1703,10 @@
 
     if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) {
         axs = QString("%1 %2").arg(v0).arg(u0);
+        if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
+            axs = QString("%1 (%2)").arg(axs)
+                .arg(Pitch::getPitchLabelForFrequency(v0));
+        }
         aw = paint.fontMetrics().width(axs);
         ++labelCount;
     }
@@ -1702,6 +1714,10 @@
     if (r.width() > 0) {
         if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) {
             bxs = QString("%1 %2").arg(v1).arg(u1);
+            if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
+                bxs = QString("%1 (%2)").arg(bxs)
+                    .arg(Pitch::getPitchLabelForFrequency(v1));
+            }
             bw = paint.fontMetrics().width(bxs);
         }
     }
@@ -1716,6 +1732,10 @@
 
     if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) {
         ays = QString("%1 %2").arg(v0).arg(u0);
+        if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) {
+            ays = QString("%1 (%2)").arg(ays)
+                .arg(Pitch::getPitchLabelForFrequency(v0));
+        }
         aw = std::max(aw, paint.fontMetrics().width(ays));
         ++labelCount;
     }
@@ -1723,6 +1743,10 @@
     if (r.height() > 0) {
         if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) {
             bys = QString("%1 %2").arg(v1).arg(u1);
+            if (u1 == "Hz" && Pitch::isFrequencyInMidiRange(v1)) {
+                bys = QString("%1 (%2)").arg(bys)
+                    .arg(Pitch::getPitchLabelForFrequency(v1));
+            }
             bw = std::max(bw, paint.fontMetrics().width(bys));
         }
     }
@@ -1827,6 +1851,8 @@
         drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
         dxy += fontHeight;
     }
+
+    paint.restore();
 }
 
 bool