Mercurial > hg > svgui
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 { |