diff layer/SpectrumLayer.cpp @ 277:8acd30ed735c

* Fix up and simplify the LayerTreeModel, removing a horrible memory leak * Move phase-unwrapped frequency estimation from SpectrogramLayer to FFTDataServer * Make the spectrum show peak phase-unwrapped frequencies as well (still needs work) * Start adding piano keyboard horizontal scale to spectrum * Debug output for id3 tags
author Chris Cannam
date Tue, 03 Jul 2007 12:46:18 +0000
parents bbe57afe9d7d
children a078aa2932cc
line wrap: on
line diff
--- a/layer/SpectrumLayer.cpp	Mon Jul 02 14:58:34 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Tue Jul 03 12:46:18 2007 +0000
@@ -21,6 +21,7 @@
 #include "base/AudioLevel.h"
 #include "base/Preferences.h"
 #include "base/RangeMapper.h"
+#include "base/Pitch.h"
 #include "ColourMapper.h"
 
 #include <QPainter>
@@ -53,6 +54,14 @@
 {
     if (m_originModel == model) return;
     m_originModel = model;
+
+    if (m_sliceableModel) {
+        const Model *oldModel = m_sliceableModel;
+        setSliceableModel(0);
+        // surprised I'm allowed to delete a const pointer -- may be a
+        // source of future compiler rejection?
+        delete oldModel;
+    }
 //!!!    setupFFT();
 }
 
@@ -549,8 +558,112 @@
         const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh
         m_newFFTNeeded = false;
     }
+
+    FFTModel *fft = dynamic_cast<FFTModel *>
+        (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
+
+    float thresh = powf(10, -8) / m_gain; // -80dB
+
+    int xorigin = getVerticalScaleWidth(v, paint) + 1;
+    int w = v->width() - xorigin - 1;
+
+    if (fft) {
+
+        // draw peak lines
+        //!!! should be optional
+
+        size_t col = v->getCentreFrame() / fft->getResolution();
+
+        paint.save();
+        paint.setRenderHint(QPainter::Antialiasing, false);
+        paint.setPen(QColor(160, 160, 160)); //!!!
+
+        ColourMapper mapper(m_colourMap, 0, 1);
+
+        BiasCurve curve;
+        getBiasCurve(curve);
+        size_t cs = curve.size();
+        
+        for (size_t bin = 0; bin < fft->getHeight(); ++bin) {
+            
+            if (!fft->isLocalPeak(col, bin)) continue;
+            if (!fft->isOverThreshold(col, bin, thresh)) continue;
+            
+            float freq = 0;
+            bool haveFreq = fft->estimateStableFrequency(col, bin, freq);
+            if (!haveFreq) continue;
+            
+            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
+
+            paint.setPen(mapper.map(norm));
+            paint.drawLine(xorigin + x, 0, xorigin + x, v->height());
+        }
+
+        paint.restore();
+    }
     
     SliceLayer::paint(v, paint, rect);
+
+    if (m_binScale == LogBins) {
+
+        int pkh = 10;
+        int h = v->height();
+
+        // piano keyboard
+        //!!! should be in a new paintHorizontalScale()?
+
+	paint.drawLine(xorigin, h - pkh - 1, w, h - pkh - 1);
+
+	int px = xorigin, ppx = xorigin;
+//	paint.setBrush(paint.pen().color());
+
+	for (int i = 0; i < 128; ++i) {
+
+	    float f = Pitch::getFrequencyForPitch(i);
+	    int x = lrintf(getXForFrequency(f, w));
+
+            if (x < 0) break;
+            if (x + xorigin > w) {
+                continue;
+            }
+                           
+            x += xorigin;
+
+	    int n = (i % 12);
+
+            if (n == 1) {
+                // C# -- fill the C from here
+                if (x - ppx > 2) {
+                    paint.fillRect(x,
+                                   h - pkh,
+                                   x - (px + ppx) / 2,
+                                   pkh,
+                                   Qt::gray);
+                }
+            }
+
+	    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;
+		if (rw < 2) rw = 2;
+		paint.drawRect(x - (px-x)/4, h - pkh, rw, pkh/2);
+	    } else if (n == 0 || n == 5) {
+		// C, F
+		if (px < w) {
+		    paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h);
+		}
+	    }
+
+            ppx = px;
+	    px = x;
+	}
+    }
 }
 
 void