comparison 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
comparison
equal deleted inserted replaced
276:21c7152ddba8 277:8acd30ed735c
19 #include "data/model/FFTModel.h" 19 #include "data/model/FFTModel.h"
20 #include "view/View.h" 20 #include "view/View.h"
21 #include "base/AudioLevel.h" 21 #include "base/AudioLevel.h"
22 #include "base/Preferences.h" 22 #include "base/Preferences.h"
23 #include "base/RangeMapper.h" 23 #include "base/RangeMapper.h"
24 #include "base/Pitch.h"
24 #include "ColourMapper.h" 25 #include "ColourMapper.h"
25 26
26 #include <QPainter> 27 #include <QPainter>
27 28
28 SpectrumLayer::SpectrumLayer() : 29 SpectrumLayer::SpectrumLayer() :
51 void 52 void
52 SpectrumLayer::setModel(DenseTimeValueModel *model) 53 SpectrumLayer::setModel(DenseTimeValueModel *model)
53 { 54 {
54 if (m_originModel == model) return; 55 if (m_originModel == model) return;
55 m_originModel = model; 56 m_originModel = model;
57
58 if (m_sliceableModel) {
59 const Model *oldModel = m_sliceableModel;
60 setSliceableModel(0);
61 // surprised I'm allowed to delete a const pointer -- may be a
62 // source of future compiler rejection?
63 delete oldModel;
64 }
56 //!!! setupFFT(); 65 //!!! setupFFT();
57 } 66 }
58 67
59 void 68 void
60 SpectrumLayer::setupFFT() 69 SpectrumLayer::setupFFT()
547 556
548 if (m_newFFTNeeded) { 557 if (m_newFFTNeeded) {
549 const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh 558 const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh
550 m_newFFTNeeded = false; 559 m_newFFTNeeded = false;
551 } 560 }
561
562 FFTModel *fft = dynamic_cast<FFTModel *>
563 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel));
564
565 float thresh = powf(10, -8) / m_gain; // -80dB
566
567 int xorigin = getVerticalScaleWidth(v, paint) + 1;
568 int w = v->width() - xorigin - 1;
569
570 if (fft) {
571
572 // draw peak lines
573 //!!! should be optional
574
575 size_t col = v->getCentreFrame() / fft->getResolution();
576
577 paint.save();
578 paint.setRenderHint(QPainter::Antialiasing, false);
579 paint.setPen(QColor(160, 160, 160)); //!!!
580
581 ColourMapper mapper(m_colourMap, 0, 1);
582
583 BiasCurve curve;
584 getBiasCurve(curve);
585 size_t cs = curve.size();
586
587 for (size_t bin = 0; bin < fft->getHeight(); ++bin) {
588
589 if (!fft->isLocalPeak(col, bin)) continue;
590 if (!fft->isOverThreshold(col, bin, thresh)) continue;
591
592 float freq = 0;
593 bool haveFreq = fft->estimateStableFrequency(col, bin, freq);
594 if (!haveFreq) continue;
595
596 int x = lrintf(getXForFrequency(freq, w));
597
598 float value = m_sliceableModel->getValueAt(col, bin);
599 if (bin < cs) value *= curve[bin];
600 float norm = 0.f;
601 float y = getYForValue(value, v, norm); // don't need y, need norm
602
603 paint.setPen(mapper.map(norm));
604 paint.drawLine(xorigin + x, 0, xorigin + x, v->height());
605 }
606
607 paint.restore();
608 }
552 609
553 SliceLayer::paint(v, paint, rect); 610 SliceLayer::paint(v, paint, rect);
611
612 if (m_binScale == LogBins) {
613
614 int pkh = 10;
615 int h = v->height();
616
617 // piano keyboard
618 //!!! should be in a new paintHorizontalScale()?
619
620 paint.drawLine(xorigin, h - pkh - 1, w, h - pkh - 1);
621
622 int px = xorigin, ppx = xorigin;
623 // paint.setBrush(paint.pen().color());
624
625 for (int i = 0; i < 128; ++i) {
626
627 float f = Pitch::getFrequencyForPitch(i);
628 int x = lrintf(getXForFrequency(f, w));
629
630 if (x < 0) break;
631 if (x + xorigin > w) {
632 continue;
633 }
634
635 x += xorigin;
636
637 int n = (i % 12);
638
639 if (n == 1) {
640 // C# -- fill the C from here
641 if (x - ppx > 2) {
642 paint.fillRect(x,
643 h - pkh,
644 x - (px + ppx) / 2,
645 pkh,
646 Qt::gray);
647 }
648 }
649
650 if (n == 1 || n == 3 || n == 6 || n == 8 || n == 10) {
651 // black notes
652 paint.drawLine(x, h - pkh, x, h);
653 int rw = ((px - x) / 4) * 2;
654 if (rw < 2) rw = 2;
655 paint.drawRect(x - (px-x)/4, h - pkh, rw, pkh/2);
656 } else if (n == 0 || n == 5) {
657 // C, F
658 if (px < w) {
659 paint.drawLine((x + px) / 2, h - pkh, (x + px) / 2, h);
660 }
661 }
662
663 ppx = px;
664 px = x;
665 }
666 }
554 } 667 }
555 668
556 void 669 void
557 SpectrumLayer::getBiasCurve(BiasCurve &curve) const 670 SpectrumLayer::getBiasCurve(BiasCurve &curve) const
558 { 671 {