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 {