Mercurial > hg > svgui
comparison 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 |
comparison
equal
deleted
inserted
replaced
1280:34394e8c2942 | 1281:fc9d9f1103fa |
---|---|
24 #include "base/Strings.h" | 24 #include "base/Strings.h" |
25 | 25 |
26 #include "ColourMapper.h" | 26 #include "ColourMapper.h" |
27 #include "PaintAssistant.h" | 27 #include "PaintAssistant.h" |
28 #include "PianoScale.h" | 28 #include "PianoScale.h" |
29 #include "LogNumericalScale.h" | 29 #include "HorizontalFrequencyScale.h" |
30 | 30 |
31 #include <QPainter> | 31 #include <QPainter> |
32 #include <QTextStream> | 32 #include <QTextStream> |
33 | 33 |
34 | 34 |
302 double | 302 double |
303 SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const | 303 SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const |
304 { | 304 { |
305 if (!m_sliceableModel) return 0; | 305 if (!m_sliceableModel) return 0; |
306 double bin = getBinForX(v, x); | 306 double bin = getBinForX(v, x); |
307 // we assume the frequency of a bin corresponds to the centre of | |
308 // its visual range | |
309 bin -= 0.5; | |
307 return (m_sliceableModel->getSampleRate() * bin) / | 310 return (m_sliceableModel->getSampleRate() * bin) / |
308 (m_sliceableModel->getHeight() * 2); | 311 (m_sliceableModel->getHeight() * 2); |
309 } | 312 } |
310 | 313 |
311 double | 314 double |
312 SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const | 315 SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const |
313 { | 316 { |
314 if (!m_sliceableModel) return 0; | 317 if (!m_sliceableModel) return 0; |
315 double bin = (freq * m_sliceableModel->getHeight() * 2) / | 318 double bin = (freq * m_sliceableModel->getHeight() * 2) / |
316 m_sliceableModel->getSampleRate(); | 319 m_sliceableModel->getSampleRate(); |
320 // we want the centre of the bin range | |
321 bin += 0.5; | |
317 return getXForBin(v, bin); | 322 return getXForBin(v, bin); |
318 } | 323 } |
319 | 324 |
320 bool | 325 bool |
321 SpectrumLayer::getXScaleValue(const LayerGeometryProvider *v, int x, | 326 SpectrumLayer::getXScaleValue(const LayerGeometryProvider *v, int x, |
598 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); | 603 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); |
599 | 604 |
600 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj | 605 double thresh = (pow(10, -6) / m_gain) * (m_windowSize / 2.0); // -60dB adj |
601 | 606 |
602 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; | 607 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; |
603 int w = v->getPaintWidth() - xorigin - 1; | 608 int scaleHeight = getHorizontalScaleHeight(v, paint); |
604 | |
605 int pkh = int(paint.fontMetrics().height() * 0.7 + 0.5); | |
606 if (pkh < 10) pkh = 10; | |
607 | |
608 int scaleh = LogNumericalScale().getWidth(v, paint, true); | |
609 | |
610 paint.save(); | |
611 | 609 |
612 if (fft && m_showPeaks) { | 610 if (fft && m_showPeaks) { |
613 | 611 |
614 // draw peak lines | 612 // draw peak lines |
615 | |
616 // SVDEBUG << "Showing peaks..." << endl; | |
617 | 613 |
618 int col = int(v->getCentreFrame() / fft->getResolution()); | 614 int col = int(v->getCentreFrame() / fft->getResolution()); |
619 | 615 |
620 paint.save(); | 616 paint.save(); |
621 paint.setRenderHint(QPainter::Antialiasing, false); | 617 paint.setRenderHint(QPainter::Antialiasing, false); |
622 paint.setPen(QColor(160, 160, 160)); //!!! | 618 |
623 | 619 ColourMapper mapper = |
620 hasLightBackground() ? | |
621 ColourMapper(ColourMapper::BlackOnWhite, 0, 1) : | |
622 ColourMapper(ColourMapper::WhiteOnBlack, 0, 1); | |
623 | |
624 int peakminbin = 0; | 624 int peakminbin = 0; |
625 int peakmaxbin = fft->getHeight() - 1; | 625 int peakmaxbin = fft->getHeight() - 1; |
626 double peakmaxfreq = Pitch::getFrequencyForPitch(128); | 626 double peakmaxfreq = Pitch::getFrequencyForPitch(128); |
627 peakmaxbin = int(((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate())); | 627 peakmaxbin = int(((peakmaxfreq * fft->getHeight() * 2) / fft->getSampleRate())); |
628 | 628 |
629 FFTModel::PeakSet peaks = fft->getPeakFrequencies | 629 FFTModel::PeakSet peaks = fft->getPeakFrequencies |
630 (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin); | 630 (FFTModel::MajorPitchAdaptivePeaks, col, peakminbin, peakmaxbin); |
631 | 631 |
632 ColourMapper mapper(ColourMapper::BlackOnWhite, 0, 1); | |
633 | |
634 BiasCurve curve; | 632 BiasCurve curve; |
635 getBiasCurve(curve); | 633 getBiasCurve(curve); |
636 int cs = int(curve.size()); | 634 int cs = int(curve.size()); |
637 | 635 |
638 std::vector<double> values; | 636 std::vector<double> values; |
658 | 656 |
659 double norm = 0.f; | 657 double norm = 0.f; |
660 (void)getYForValue(v, values[bin], norm); // don't need return value, need norm | 658 (void)getYForValue(v, values[bin], norm); // don't need return value, need norm |
661 | 659 |
662 paint.setPen(mapper.map(norm)); | 660 paint.setPen(mapper.map(norm)); |
663 paint.drawLine(x, 0, x, v->getPaintHeight() - scaleh - pkh - 1); | 661 paint.drawLine(x, 0, x, v->getPaintHeight() - scaleHeight - 1); |
664 } | 662 } |
665 | 663 |
666 paint.restore(); | 664 paint.restore(); |
667 } | 665 } |
668 | 666 |
667 paint.save(); | |
668 | |
669 SliceLayer::paint(v, paint, rect); | 669 SliceLayer::paint(v, paint, rect); |
670 | 670 |
671 paintHorizontalScale(v, paint, xorigin); | |
672 | |
673 paint.restore(); | |
674 } | |
675 | |
676 int | |
677 SpectrumLayer::getHorizontalScaleHeight(LayerGeometryProvider *v, | |
678 QPainter &paint) const | |
679 { | |
680 int pkh = int(paint.fontMetrics().height() * 0.7 + 0.5); | |
681 if (pkh < 10) pkh = 10; | |
682 | |
683 int scaleh = HorizontalFrequencyScale().getHeight(v, paint); | |
684 | |
685 return pkh + scaleh; | |
686 } | |
687 | |
688 void | |
689 SpectrumLayer::paintHorizontalScale(LayerGeometryProvider *v, | |
690 QPainter &paint, | |
691 int xorigin) const | |
692 { | |
671 //!!! All of this stuff relating to depicting frequencies | 693 //!!! All of this stuff relating to depicting frequencies |
672 // (keyboard, crosshairs etc) should be applicable to any slice | 694 // (keyboard, crosshairs etc) should be applicable to any slice |
673 // layer whose model has a vertical scale unit of Hz. However, | 695 // layer whose model has a vertical scale unit of Hz. However, |
674 // the dense 3d model at the moment doesn't record its vertical | 696 // the dense 3d model at the moment doesn't record its vertical |
675 // scale unit -- we need to fix that and hoist this code as | 697 // scale unit -- we need to fix that and hoist this code as |
676 // appropriate. Same really goes for any code in SpectrogramLayer | 698 // appropriate. Same really goes for any code in SpectrogramLayer |
677 // that could be relevant to Colour3DPlotLayer with unit Hz, but | 699 // that could be relevant to Colour3DPlotLayer with unit Hz, but |
678 // that's a bigger proposition. | 700 // that's a bigger proposition. |
679 | 701 |
680 int h = v->getPaintHeight(); | 702 if (!v->getViewManager()->shouldShowHorizontalValueScale()) { |
703 return; | |
704 } | |
705 | |
706 int totalScaleHeight = getHorizontalScaleHeight(v, paint); // inc piano | |
707 int freqScaleHeight = HorizontalFrequencyScale().getHeight(v, paint); | |
708 int paintHeight = v->getPaintHeight(); | |
709 int paintWidth = v->getPaintWidth(); | |
681 | 710 |
682 PianoScale().paintPianoHorizontal | 711 PianoScale().paintPianoHorizontal |
683 (v, this, paint, | 712 (v, this, paint, |
684 QRect(xorigin, h - scaleh - pkh - 1, w + xorigin, pkh)); | 713 QRect(xorigin, paintHeight - totalScaleHeight - 1, |
685 | 714 paintWidth - 1, totalScaleHeight - freqScaleHeight)); |
686 LogNumericalScale().paintHorizontal | 715 |
716 int scaleLeft = int(getXForBin(v, 1)); | |
717 | |
718 paint.drawLine(int(getXForBin(v, 0)), paintHeight - freqScaleHeight, | |
719 scaleLeft, paintHeight - freqScaleHeight); | |
720 | |
721 QString hz = tr("Hz"); | |
722 int hzw = paint.fontMetrics().width(hz); | |
723 if (scaleLeft > hzw + 5) { | |
724 paint.drawText | |
725 (scaleLeft - hzw - 5, | |
726 paintHeight - freqScaleHeight + paint.fontMetrics().ascent() + 5, | |
727 hz); | |
728 } | |
729 | |
730 HorizontalFrequencyScale().paintScale | |
687 (v, this, paint, | 731 (v, this, paint, |
688 QRect(int(getXForBin(v, 1)), h - scaleh, w + xorigin, scaleh)); | 732 QRect(scaleLeft, paintHeight - freqScaleHeight, |
689 | 733 paintWidth, totalScaleHeight), |
690 paint.restore(); | 734 m_binScale == LogBins); |
691 } | 735 } |
692 | 736 |
693 void | 737 void |
694 SpectrumLayer::getBiasCurve(BiasCurve &curve) const | 738 SpectrumLayer::getBiasCurve(BiasCurve &curve) const |
695 { | 739 { |