Mercurial > hg > svgui
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); |