comparison layer/SpectrumLayer.cpp @ 1486:ac0a8addabcf

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:25:16 +0100
parents e540aa5d89cd
children
comparison
equal deleted inserted replaced
1468:de41a11cabc2 1486:ac0a8addabcf
31 #include <QPainter> 31 #include <QPainter>
32 #include <QTextStream> 32 #include <QTextStream>
33 33
34 34
35 SpectrumLayer::SpectrumLayer() : 35 SpectrumLayer::SpectrumLayer() :
36 m_originModel(nullptr),
37 m_channel(-1), 36 m_channel(-1),
38 m_channelSet(false), 37 m_channelSet(false),
39 m_windowSize(4096), 38 m_windowSize(4096),
40 m_windowType(HanningWindow), 39 m_windowType(HanningWindow),
41 m_windowHopLevel(3), 40 m_windowHopLevel(3),
54 setBinScale(LogBins); 53 setBinScale(LogBins);
55 } 54 }
56 55
57 SpectrumLayer::~SpectrumLayer() 56 SpectrumLayer::~SpectrumLayer()
58 { 57 {
59 Model *m = const_cast<Model *> 58 ModelById::release(m_sliceableModel);
60 (static_cast<const Model *>(m_sliceableModel)); 59 }
61 if (m) m->aboutToDelete(); 60
62 m_sliceableModel = nullptr; 61 void
63 delete m; 62 SpectrumLayer::setModel(ModelId modelId)
64 } 63 {
65 64 auto newModel = ModelById::getAs<DenseTimeValueModel>(modelId);
66 void 65 if (!modelId.isNone() && !newModel) {
67 SpectrumLayer::setModel(DenseTimeValueModel *model) 66 throw std::logic_error("Not a DenseTimeValueModel");
68 { 67 }
69 SVDEBUG << "SpectrumLayer::setModel(" << model << ") from " << m_originModel << endl; 68
70 69 if (m_originModel == modelId) return;
71 if (m_originModel == model) return; 70 m_originModel = modelId;
72
73 m_originModel = model;
74
75 if (m_sliceableModel) {
76 Model *m = const_cast<Model *>
77 (static_cast<const Model *>(m_sliceableModel));
78 m->aboutToDelete();
79 setSliceableModel(nullptr);
80 delete m;
81 }
82 71
83 m_newFFTNeeded = true; 72 m_newFFTNeeded = true;
84 73
85 emit layerParametersChanged(); 74 emit layerParametersChanged();
86 } 75 }
102 } 91 }
103 92
104 void 93 void
105 SpectrumLayer::setupFFT() 94 SpectrumLayer::setupFFT()
106 { 95 {
107 if (m_sliceableModel) { 96 ModelById::release(m_sliceableModel);
108 Model *m = const_cast<Model *> 97 m_sliceableModel = {};
109 (static_cast<const Model *>(m_sliceableModel)); 98
110 m->aboutToDelete(); 99 if (m_originModel.isNone()) {
111 setSliceableModel(nullptr);
112 delete m;
113 }
114
115 if (!m_originModel) {
116 return; 100 return;
117 } 101 }
118 102
119 int fftSize = getFFTSize(); 103 int fftSize = getFFTSize();
120 104
121 FFTModel *newFFT = new FFTModel(m_originModel, 105 auto newFFT = std::make_shared<FFTModel>(m_originModel,
122 m_channel, 106 m_channel,
123 m_windowType, 107 m_windowType,
124 m_windowSize, 108 m_windowSize,
125 getWindowIncrement(), 109 getWindowIncrement(),
126 fftSize); 110 fftSize);
127 111
128 if (m_minbin == 0 && m_maxbin == 0) { 112 if (m_minbin == 0 && m_maxbin == 0) {
129 m_minbin = 1; 113 m_minbin = 1;
130 m_freqOfMinBin = double(m_minbin * newFFT->getSampleRate()) 114 m_freqOfMinBin = double(m_minbin * newFFT->getSampleRate())
131 / getFFTSize(); 115 / getFFTSize();
132 m_maxbin = newFFT->getHeight(); 116 m_maxbin = newFFT->getHeight();
133 } 117 }
134 118
135 setSliceableModel(newFFT); 119 setSliceableModel(ModelById::add(newFFT));
136 120
137 m_biasCurve.clear(); 121 m_biasCurve.clear();
138 for (int i = 0; i < fftSize; ++i) { 122 for (int i = 0; i < fftSize; ++i) {
139 // Scale by the window size, not the FFT size, because we 123 // Scale by the window size, not the FFT size, because we
140 // don't want to scale down by all the zero bins 124 // don't want to scale down by all the zero bins
401 } 385 }
402 386
403 double 387 double
404 SpectrumLayer::getBinForFrequency(double freq) const 388 SpectrumLayer::getBinForFrequency(double freq) const
405 { 389 {
406 if (!m_sliceableModel) return 0; 390 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
407 double bin = (freq * getFFTSize()) / m_sliceableModel->getSampleRate(); 391 (m_sliceableModel);
392 if (!sliceableModel) return 0;
393 double bin = (freq * getFFTSize()) / sliceableModel->getSampleRate();
408 return bin; 394 return bin;
409 } 395 }
410 396
411 double 397 double
412 SpectrumLayer::getBinForX(const LayerGeometryProvider *v, double x) const 398 SpectrumLayer::getBinForX(const LayerGeometryProvider *v, double x) const
413 { 399 {
414 if (!m_sliceableModel) return 0; 400 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
401 (m_sliceableModel);
402 if (!sliceableModel) return 0;
415 double bin = getBinForFrequency(getFrequencyForX(v, x)); 403 double bin = getBinForFrequency(getFrequencyForX(v, x));
416 return bin; 404 return bin;
417 } 405 }
418 406
419 double 407 double
420 SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const 408 SpectrumLayer::getFrequencyForX(const LayerGeometryProvider *v, double x) const
421 { 409 {
422 if (!m_sliceableModel) return 0; 410 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
411 (m_sliceableModel);
412 if (!sliceableModel) return 0;
423 413
424 double fmin = getFrequencyForBin(m_minbin); 414 double fmin = getFrequencyForBin(m_minbin);
425 double fmax = getFrequencyForBin(m_maxbin); 415 double fmax = getFrequencyForBin(m_maxbin);
426 416
427 double freq = getScalePointForX(v, x, fmin, fmax); 417 double freq = getScalePointForX(v, x, fmin, fmax);
429 } 419 }
430 420
431 double 421 double
432 SpectrumLayer::getFrequencyForBin(double bin) const 422 SpectrumLayer::getFrequencyForBin(double bin) const
433 { 423 {
434 if (!m_sliceableModel) return 0; 424 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
435 double freq = (bin * m_sliceableModel->getSampleRate()) / getFFTSize(); 425 (m_sliceableModel);
426 if (!sliceableModel) return 0;
427 double freq = (bin * sliceableModel->getSampleRate()) / getFFTSize();
436 return freq; 428 return freq;
437 } 429 }
438 430
439 double 431 double
440 SpectrumLayer::getXForBin(const LayerGeometryProvider *v, double bin) const 432 SpectrumLayer::getXForBin(const LayerGeometryProvider *v, double bin) const
441 { 433 {
442 if (!m_sliceableModel) return 0; 434 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
435 (m_sliceableModel);
436 if (!sliceableModel) return 0;
443 double x = getXForFrequency(v, getFrequencyForBin(bin)); 437 double x = getXForFrequency(v, getFrequencyForBin(bin));
444 return x; 438 return x;
445 } 439 }
446 440
447 double 441 double
448 SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const 442 SpectrumLayer::getXForFrequency(const LayerGeometryProvider *v, double freq) const
449 { 443 {
450 if (!m_sliceableModel) return 0; 444 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
445 (m_sliceableModel);
446 if (!sliceableModel) return 0;
451 447
452 double fmin = getFrequencyForBin(m_minbin); 448 double fmin = getFrequencyForBin(m_minbin);
453 double fmax = getFrequencyForBin(m_maxbin); 449 double fmax = getFrequencyForBin(m_maxbin);
454 double x = getXForScalePoint(v, freq, fmin, fmax); 450 double x = getXForScalePoint(v, freq, fmin, fmax);
455 451
473 469
474 if (m_energyScale == dBScale || m_energyScale == MeterScale) { 470 if (m_energyScale == dBScale || m_energyScale == MeterScale) {
475 471
476 if (value > 0.0) { 472 if (value > 0.0) {
477 value = 10.0 * log10(value); 473 value = 10.0 * log10(value);
478 if (value < m_threshold) value = m_threshold; 474 if (value < m_threshold) {
479 } else value = m_threshold; 475 value = m_threshold;
476 }
477 } else {
478 value = m_threshold;
479 }
480 480
481 unit = "dBV"; 481 unit = "dBV";
482 482
483 } else { 483 } else {
484 unit = "V"; 484 unit = "V";
510 510
511 int hoffset = 2; 511 int hoffset = 2;
512 if (m_binScale == LogBins) hoffset = 13; 512 if (m_binScale == LogBins) hoffset = 13;
513 513
514 int sw = getVerticalScaleWidth(v, false, paint); 514 int sw = getVerticalScaleWidth(v, false, paint);
515
516 // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
517 // replacement (horizontalAdvance) was only added in Qt 5.11
518 // which is too new for us
519 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
515 520
516 QRect value(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2, 521 QRect value(sw, cursorPos.y() - paint.fontMetrics().ascent() - 2,
517 paint.fontMetrics().width("0.0000001 V") + 2, 522 paint.fontMetrics().width("0.0000001 V") + 2,
518 paint.fontMetrics().height()); 523 paint.fontMetrics().height());
519 extents.push_back(value); 524 extents.push_back(value);
541 546
542 void 547 void
543 SpectrumLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint, 548 SpectrumLayer::paintCrosshairs(LayerGeometryProvider *v, QPainter &paint,
544 QPoint cursorPos) const 549 QPoint cursorPos) const
545 { 550 {
546 if (!m_sliceableModel) return; 551 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
552 (m_sliceableModel);
553 if (!sliceableModel) return;
547 554
548 paint.save(); 555 paint.save();
549 QFont fn = paint.font(); 556 QFont fn = paint.font();
550 if (fn.pointSize() > 8) { 557 if (fn.pointSize() > 8) {
551 fn.setPointSize(fn.pointSize() - 1); 558 fn.setPointSize(fn.pointSize() - 1);
628 } 635 }
629 636
630 QString 637 QString
631 SpectrumLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &p) const 638 SpectrumLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &p) const
632 { 639 {
633 if (!m_sliceableModel) return ""; 640 auto sliceableModel = ModelById::getAs<DenseThreeDimensionalModel>
641 (m_sliceableModel);
642 if (!sliceableModel) return "";
634 643
635 int minbin = 0, maxbin = 0, range = 0; 644 int minbin = 0, maxbin = 0, range = 0;
636 QString genericDesc = SliceLayer::getFeatureDescriptionAux 645 QString genericDesc = SliceLayer::getFeatureDescriptionAux
637 (v, p, false, minbin, maxbin, range); 646 (v, p, false, minbin, maxbin, range);
638 647
649 658
650 if (minvalue > maxvalue) std::swap(minvalue, maxvalue); 659 if (minvalue > maxvalue) std::swap(minvalue, maxvalue);
651 660
652 QString binstr; 661 QString binstr;
653 QString hzstr; 662 QString hzstr;
654 int minfreq = int(lrint((minbin * m_sliceableModel->getSampleRate()) / 663 int minfreq = int(lrint((minbin * sliceableModel->getSampleRate()) /
655 getFFTSize())); 664 getFFTSize()));
656 int maxfreq = int(lrint((std::max(maxbin, minbin) 665 int maxfreq = int(lrint((std::max(maxbin, minbin)
657 * m_sliceableModel->getSampleRate()) / 666 * sliceableModel->getSampleRate()) /
658 getFFTSize())); 667 getFFTSize()));
659 668
660 if (maxbin != minbin) { 669 if (maxbin != minbin) {
661 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1); 670 binstr = tr("%1 - %2").arg(minbin+1).arg(maxbin+1);
662 } else { 671 } else {
696 dbstr = tr("%1").arg(mindbstr); 705 dbstr = tr("%1").arg(mindbstr);
697 } 706 }
698 707
699 QString description; 708 QString description;
700 709
701 if (range > int(m_sliceableModel->getResolution())) { 710 if (range > int(sliceableModel->getResolution())) {
702 description = tr("%1\nBin:\t%2 (%3)\n%4 value:\t%5\ndB:\t%6") 711 description = tr("%1\nBin:\t%2 (%3)\n%4 value:\t%5\ndB:\t%6")
703 .arg(genericDesc) 712 .arg(genericDesc)
704 .arg(binstr) 713 .arg(binstr)
705 .arg(hzstr) 714 .arg(hzstr)
706 .arg(m_samplingMode == NearestSample ? tr("First") : 715 .arg(m_samplingMode == NearestSample ? tr("First") :
720 } 729 }
721 730
722 void 731 void
723 SpectrumLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 732 SpectrumLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
724 { 733 {
725 if (!m_originModel || !m_originModel->isOK() || 734 auto originModel = ModelById::get(m_originModel);
726 !m_originModel->isReady()) { 735 if (!originModel || !originModel->isOK() || !originModel->isReady()) {
727 SVDEBUG << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl; 736 SVDEBUG << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << endl;
728 return; 737 return;
729 } 738 }
730 739
731 if (m_newFFTNeeded) { 740 if (m_newFFTNeeded) {
732 SVDEBUG << "SpectrumLayer::paint: new FFT needed, calling setupFFT" << endl; 741 SVDEBUG << "SpectrumLayer::paint: new FFT needed, calling setupFFT" << endl;
733 const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh 742 const_cast<SpectrumLayer *>(this)->setupFFT(); //ugh
734 } 743 }
735 744
736 FFTModel *fft = dynamic_cast<FFTModel *> 745 auto fft = ModelById::getAs<FFTModel>(m_sliceableModel);
737 (const_cast<DenseThreeDimensionalModel *>(m_sliceableModel)); 746 if (!fft) return;
738 747
739 double thresh = (pow(10, -6) / m_gain) * (getFFTSize() / 2.0); // -60dB adj 748 double thresh = (pow(10, -6) / m_gain) * (getFFTSize() / 2.0); // -60dB adj
740 749
741 int xorigin = getVerticalScaleWidth(v, false, paint) + 1; 750 int xorigin = getVerticalScaleWidth(v, false, paint) + 1;
742 int scaleHeight = getHorizontalScaleHeight(v, paint); 751 int scaleHeight = getHorizontalScaleHeight(v, paint);